From eee5fc59eeaf182382885f9559df7b2c05ece208 Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Sun, 22 Sep 2024 20:35:44 +0200 Subject: [PATCH 01/29] fix: move the feedback button to the bottom (#723) --- src/app/index.scss | 5 +++++ src/features/feedback/doc/index.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/app/index.scss b/src/app/index.scss index 97e33a53c2..9f389dd50b 100644 --- a/src/app/index.scss +++ b/src/app/index.scss @@ -31,3 +31,8 @@ h6 { border-radius: var(--ifm-button-border-radius) !important; } } + +.theme-back-to-top-button { + // The PushFeedback button is positioned in the same place, so we need to move the "back to top" button higher + bottom: 3.5rem !important; +} diff --git a/src/features/feedback/doc/index.tsx b/src/features/feedback/doc/index.tsx index 5f66ba90be..b6b0a9b200 100644 --- a/src/features/feedback/doc/index.tsx +++ b/src/features/feedback/doc/index.tsx @@ -55,7 +55,7 @@ export function FeedbackWidget({ projectId }: { projectId: string }) { rating-stars-placeholder={translate({ id: "features.feedback-doc.rating-stars-placeholder", })} - button-position="center-right" + button-position="bottom-right" button-style="dark" modal-position="bottom-right" custom-font="true" From b30c0a8b62286e8da06f9a4691dfc39a39e0866a Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Sat, 28 Sep 2024 18:19:49 +0200 Subject: [PATCH 02/29] fix: fix the broken featureslices.dev domain (#726) --- CHANGELOG.md | 2 +- config/docusaurus/navbar.js | 4 ++-- .../current/guides/migration/from-v1.md | 2 +- .../current/guides/migration/from-v1.md | 2 +- src/features/hero/index.tsx | 2 +- src/pages/versions/index.tsx | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fc94ad32f..d5ff4196d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2.0.0] - 2023-10-01 > **Note** -> This release note is retrospective, meaning that prior to this release, the Feature-Sliced Design project did not keep a changelog. Below is a summary of the most prominent recent changes, but there is no FSD v1. Prior to FSD, there has been a project called ["Feature Slices"](https://featureslices.dev/v1.0.html), and it is considered to be the v1 of FSD. +> This release note is retrospective, meaning that prior to this release, the Feature-Sliced Design project did not keep a changelog. Below is a summary of the most prominent recent changes, but there is no FSD v1. Prior to FSD, there has been a project called ["Feature Slices"](https://feature-sliced.github.io/featureslices.dev/v1.0.html), and it is considered to be the v1 of FSD. ### Deprecated diff --git a/config/docusaurus/navbar.js b/config/docusaurus/navbar.js index a0fe088f8e..4230a532ef 100644 --- a/config/docusaurus/navbar.js +++ b/config/docusaurus/navbar.js @@ -37,11 +37,11 @@ const navbar = { dropdownActiveClassDisabled: true, dropdownItemsAfter: [ { - to: "https://featureslices.dev/v1.0.html", + to: "https://feature-sliced.github.io/featureslices.dev/v1.0.html", label: "v1.0", }, { - to: "https://featureslices.dev/v0.1.html", + to: "https://feature-sliced.github.io/featureslices.dev/v0.1.html", label: "v0.1", }, { diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md index 3bd4324d5b..241a964b12 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md @@ -161,7 +161,7 @@ Now it is much easier to [observe the principle of low coupling][refs-low-coupli [refs-low-coupling]: /docs/reference/isolation/coupling-cohesion [refs-adaptability]: /docs/about/understanding/naming -[ext-v1]: https://featureslices.dev/v1.0.html +[ext-v1]: https://feature-sliced.github.io/featureslices.dev/v1.0.html [ext-tg-spb]: https://t.me/feature_slices [ext-fdd]: https://github.com/feature-sliced/documentation/tree/rc/feature-driven [ext-fdd-issues]: https://github.com/kof/feature-driven-architecture/issues diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md index c0f4d33e02..f7b3d77f9d 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md @@ -160,7 +160,7 @@ sidebar_position: 4 [refs-low-coupling]: /docs/reference/isolation/coupling-cohesion [refs-adaptability]: /docs/about/understanding/naming -[ext-v1]: https://featureslices.dev/v1.0.html +[ext-v1]: https://feature-sliced.github.io/featureslices.dev/v1.0.html [ext-tg-spb]: https://t.me/feature_slices [ext-fdd]: https://github.com/feature-sliced/documentation/tree/rc/feature-driven [ext-fdd-issues]: https://github.com/kof/feature-driven-architecture/issues diff --git a/src/features/hero/index.tsx b/src/features/hero/index.tsx index cd32f632af..690fa3f993 100644 --- a/src/features/hero/index.tsx +++ b/src/features/hero/index.tsx @@ -31,7 +31,7 @@ export function Hero() {
{translate({ id: "features.hero.previous" })}{" "} (feature-slices@v1) diff --git a/src/pages/versions/index.tsx b/src/pages/versions/index.tsx index 7eb7a2c545..6c757eb0f5 100644 --- a/src/pages/versions/index.tsx +++ b/src/pages/versions/index.tsx @@ -62,12 +62,12 @@ function Version() {
From faa602aee14bfc92a72207202ec993d16bd84211 Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Sat, 28 Sep 2024 19:40:11 +0200 Subject: [PATCH 03/29] fix: redo the coupling/cohesion graphic (#727) --- .../reference/isolation/coupling-cohesion.md | 8 +++++++- .../reference/isolation/coupling-cohesion.md | 8 +++++++- static/img/coupling-cohesion-dark.svg | 1 + static/img/coupling-cohesion-light.svg | 1 + static/img/coupling.png | Bin 142834 -> 0 bytes 5 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 static/img/coupling-cohesion-dark.svg create mode 100644 static/img/coupling-cohesion-light.svg delete mode 100644 static/img/coupling.png diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md b/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md index 923878b814..9ca0e6cd8c 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md @@ -6,7 +6,13 @@ sidebar_position: 1 Application modules should be designed according to **high cohesion** (should solve one specific task) and **low coupling** (independent of other modules) principles. -![coupling-cohesion-themed](/img/coupling.png) +
+ + +
+ Image inspired by https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/ +
+
Within the methodology, this is achieved through: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md b/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md index b68d2221b3..62cac23dcd 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md @@ -6,7 +6,13 @@ sidebar_position: 1 Модули приложения должны проектироваться как обладающие **сильной связностью** (направленные на решение одной четкой задачи) и **слабой зацепленностью** (как можно менее зависимые от других модулей) -![coupling-cohesion-themed](/img/coupling.png) +
+ + +
+ Иллюстрация вдохновлена статьей https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/ +
+
В рамках методологии это достигается через: diff --git a/static/img/coupling-cohesion-dark.svg b/static/img/coupling-cohesion-dark.svg new file mode 100644 index 0000000000..c5c85a5f42 --- /dev/null +++ b/static/img/coupling-cohesion-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/coupling-cohesion-light.svg b/static/img/coupling-cohesion-light.svg new file mode 100644 index 0000000000..218bf05c0d --- /dev/null +++ b/static/img/coupling-cohesion-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/coupling.png b/static/img/coupling.png deleted file mode 100644 index 5ef1edda774811f76a1585bc6534c98897595471..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142834 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⩔%UpN$fKh|nBW8Ah)3qUz8Vj=Z@&EGI`}&Rb zBE>O&=1ZwzKLOy?`Om}FR7}i-7G6(Q92^3jEjaa-$?wHKPiuU5y@Ez6`w@b;%BCM6l|>}^hT@SyYeE>n!}F{;_LjSqW!(7o^k9-#Xndeu_Thuw~4&>h$* z!ngp$sFQrni^<)#D_HX4L>wH}02 z0{b>r{PQ0J^nUgZa^DwE42ppVmwiDskFD_)jd8=Uhvsa<6sNhAg0qta>m)F*dKGBRZMLEtkou0E_;Q zVv{2;aTF5dj1+}UJe@OF(--*7T^DKuvZ{YV5eJ=v6#jYkC9LS!;MwPg)FjnO*P$J# zC5#Z%(6MD=2>nwPM>L{ymjznKwmDop+4JUr%2CnjGV3jP$=X<1H|~UTan(rJ1M;hR ze!l^>x6E{Im3`@~fNWoxYnpSPwW?TuZ8^H8S7V@KKU3J5%@HuOqCaz{s0QQH|ozKR2T zly?su6hPH)Dw|Zj7a$FQsHZ6-tnkz0$*de1ty;@O-q2WN#8VMDe~+L*YzT5D%EwD< z&u#x(ADJ^E;u6sl!45Ak>vm>SkfBg=WN&p<*nx*=6{rB8T3Gz#>3d8{x)MoEBs;II zhyG|sr~$sv;fe9RC?#C1**UKv@hmHdWHePMyo%^v+QoLaJF`;C6maUUC*JN$NrMuf zU$S}OSVgsIGChXs>*kU+9i-7sQGPK&0f})SmWxYwmZ#Hp^1RQitrU5bEP20lcUQY% zzIF8sdW-I)3O4y*1(^#Yc|!X8YmZ#805h|B?_DYc-UGr{2v3Y3S)cj8JfPEQYns~M zRU<}<_q6~%%wGs<)fl~CMu4=ZX^$2}-TRxL-E@V=IEp_&5L{&4>_OZCeb9KY{G$C% z$+tS&NkzN8uh^rpHcp4)!Td=AO`dyuJBVr6;&PG$bn54tJRoP_0ioxfRiv;^tx!$9Bh5PRBrf;`DcVr}MTG@u3%~*xsK6=XLdeaxzpisN=E4%b zoPFV=WkZzUAJ`Oqtftc{j}ZM5dZ*~4u0*mn8>v{|{FK<#=Ek}&-@C8A{kM?lI*X2e ze|Fizg{DG+m2yT%KfsUpcXLLRF`~{^vPX&EKFP+qtCvjkfAMq`3{i&7cIobJ1OZ9u zE+wVAyBlO_gas+3L%OAjAY8f>jv7VI7N9q@ZNE%p{DWJ;`m6gxf(e#PEwc@TkD97~%g+T3|^4!Gt^lS*Ui^l~&-NxmO-^FHNGn%8#B@umuSi2!6 zX$xOoOMJY?)9kS8c~o1#M7IB(UI(AW+e-KQy%{K>mtT!c?l%0?AFlost~)@X3ccJP%ly52`P#$&fA%p8@67an z4N`Y_>k3vWgNd!Ea|C25GH;HeB7W)pc-Wo~<<@%wtyEsPdZucZ7>vFr7xZIG=XSj7 zoMUFjp1xDn7|&V%^H&03I)tg8-tlo!9q`SVQu8e=o^(FCU%_|k1EpQ3a+}M5`;jRa zh>U%fgId|09WrH^_5O_=;`%;%4Bu2JJs4m|dk8G+v)Cm#@Tt${z+(K&`hs>ph0|SJ z@)?ZJp%)PcmU7+ZJWI7J>D6ww+b{t+wz^zgg}Fb0WVIAZ)bsLqTIkzu?}5v2<)EOT zL(7YItTCqTLvnThYZc)7Jgg@=wYWKx4cH=Tuv^>wbo7>+QFbdbZW8)`_cwyby5Qhs zbB~qY@a*f|wGg&2*}yWT{ycx@)3*I{>m$~Yi4|VG3_$p?n_zKz-a}sMg?f7hu+-LC zQtogpMkB6YKF9u+mrvAd*l_x;zM7al_MxOzj0R>GLI11SXV?LQW+v!sPT;OuFUgxL z7fsb^9-g@@(atN0tisD<|0KrdmWKzYm0HJzzuMg3$jB!T=YYKeo8-lv!57$g@O^qt zXZpdd8YV6i+47C0jq8~Gt+0<|OV>e%jq5u2HRKs#4l3afh9jP9JiYXGb+L%V*HmH{ zSPy5Rqm`+koi;z{PJsNDt4#8N@jYr=`Kv{29Ev2H7_o zu#FB2)EzIc%O#s*5)2lkDlV2JmEx;se&Uil21gnj5eLEIW&3ktO7 z9nUvMjhpc84k&7VTUu~_@)OioS`(}O^0pbfE1rv%hhdFE>^=@10NZq-1F8O|qwh?u z+~B<9fVP)7J59$YrACzDDNA@J;(NT1&g7i{beZX?DpoTwbeRq|4m>=>n8B*Ep<$Qg0I|41N(EP(YePk|k2=1)9ldw2_QRM~FPts8D z2JiWVnMb7i&RAG$KZr`Xp;R&9)*_+<7C)%U&t}%U;ko6(R$6Y!vyHQ_B}`f!q}3JW z4r&Yw{Y~-R<#I)8LnO4}^2VTzkhaH%{lEqTzZamrzS+)^O8b|_!0}ldR!VX|7yMob_gamc&M zu#HCP6XDfW`ycEC=!JYCh!jpSckcOyK8EG@T+nQtE(m z)xL8zACnaZ)EJ-_+Sr(rPmALcFY+Y(!NGy8&n%8NnZ2`5RkJ|R(GwAx*?9FsGdo#E zii4AML;7c{-Yv||B4-;e#)4wFSS?*uX5gJb$%I-|^4>>mjmH`^>+*PuD6EPd?;)Db; z7|nH7UK9?B-W2DBm?XOzfdP|`BhugFC6bbIDz{ayGu>W|PmLu_WSizas#3iVe-=7h zhgHg0_cyNqfr6P=?!kUG1Jb2zoOSA(~a==%I9tUL`5DkmZNy}FUI=|Vyn zqo*hJ5{Zda&uMfJ93I2=?H~5C^QckuV}_1Jk>rk-k;yYhx={`$H?I!%ZuR-*%k2kK zd?oyNhcBwA0On`OzM`n;!&oZCyk2DAlu}Kmg{ld8n!#s%$qoCa2<&h)5pkh0Wk~rC z?In~r%6=s_@QHFm@602~F2ce6{nOpT8H%ep-`OxeIbQ9}44=l1-#+nzY(!y8o?LM5fOW?ti z^TE0M(?cgj0PYLaw3XCrUk1BL4~OT{6=-y;O;cxQ1z57XBjJfhs&@oi{LR`#p6^kN zb8(~*h3-+FxSvBHfoAQC!7iGe-xFol_QUfQ{u14wJT%~hA`!+B?vq zLy|6_X%`2~@7)jz=+7T$B#867yT8$k4fC{=!c}HuBW1-=R*AViPA8HW3z*-Zv5%}Y z)vud05LT=-gc0EpNcoVl{K&g-J6cgpL6DP^TRSw8(^rgOC@FsBA-4RfO{Jm6APjG| zVG{52sDVhlGl>2lZys#xz+89-&>Ed(86s($R(;H8N%sA#6XeWToF-!cS$)Ws&XtG> zDZhsLAJ_6gPcNrfv?~TUFpqf!YKd7{p!H9GzGnx%zG7QN!*M?cAEQaL1;YcHjHyMC}Oy4Z*LE>fJ6#3G)j=Ht|Mxjg1eITmTp(R9LW$a{+^ zc=(7!AX5B@gtP+r_&anxAEf8IS)U)esKEPDv(o1?4JPsz%WC~??{5#Xz3+&+rL@IZ z%gzRVg?wEsy*@uXK)yRsh|C!A{5hU$_{&&pC|!rS^MuVzUmtJ&T8TF(xslIuTme0; z+3rx!N{J1j{<~_hlwA6(xA-%DXtH85#=x;g8Na=JxD*1)kNrJBoY&y_IHl&!xse>8x;?b zULMO?J9I)8ZnAUSobPV9Z!x)McIxkQU;DJXq(vj)VreBpt}`k}&n+Td3hX4C|BX`F zXxzMfNXASFUl_#6z)u*62kK=lFHKViuiq8feo^vt7kZd-K-c?K!B0(1K#*5!Y5Pph zuy;-^5qOh2Y+_qTE0=ug0R3G^1tlS64d|j?fC}+GaOGTQm+e~bseM`PWb%S`8rkQ) ztCmz>bVSS*&hO@W?@fszWhg{X)xsGk&R#}DN-51%Q&(mCXD}(pv#Yfz?CCBQBe=30 z#q!s}#m$xZsG$rTh4+zz1y}L$sWa;W*os~n9k6nJE!lHv$%#fQy^AKS(1vEkPgg& zM_@1dp*^(k=s8YS2q{O{x6RQ_^58xxxad|Ie)3?qGmSd#80XFsZx2>mc@Qo%e`7JQ zfiHx;&X)@6JSyRJX#pnlvBvO-65~ilAmGA|B49OoCA6Ysy)KFFSxap8HlSRuU zB=q(QNFDSNj7u26bBZVS;_hDuYex_toWAetAC{gt6Q&U+{XR2WG763yk(^jRT-K7P zF0%#9dU$XJ{jKDPhq?vC*RB0HR$Vcf6)VAHKoHfmjg{ecC^-S1(Mcj@OuvU z=d3*_jyYk45mV)edO%I%C8gF?#ll48&h59d_w8zyJrzpYgOkpFi?VO}qzDu~+Q|tD zX{;kJ-WUd9-i#f7t~;gE0@QFKL-5{&$}v1mB3Oz4NJPT_BI3|q38DY_9PtgsO)U5u zgBqYGrSy;V$j8VV&AF$5K;W%kfV~*p3TAZgGW&{c1HjD1b|S!b3ZGL~;j9d`M*6dq z6e9gun8>?01@vsLrAN?*c!hU%y_=;~q(hK1?XG9CWruq&dV)-F!1*pWYq8Xae*9Kckn3~kKvVrD_CV-@ zgt$BE%=yw*cqZ#js$^V;Z#7benB5S^tCQ-l3z32* zCuy#Rw4!Jr|{&4f+pL!PrgG`zVIp0ZywdyzKomROS z;CkjZB%o^ytde#fqd&60rEYobauTR=Av@b0)Q{zd(A_@c!chFw?qwN)o!3)~i9p0K zlUu-36+bcrZXK&2tThcCE@3dPEG;!Pdxm`os?5lT)N#_90ETvt2`vQ~m<;@+s>-M&h3}tk`b8D${NKa*TrX&JP64Ox0WuDm5KrSGr>?42MF1-Y&iW3vCf2vY0 z{JGRY?dRu-a@{cKa8iH|`qiXTzPeut>n#phYpHdI8_T2k!TZr$kL_v`!>@8z{lfW4 z()e(^i_&qmNAxUWUc`JeL{9!Eqt7S>Uzs3*8JL~)zg-#TvJ9w(BgT2e9Ye>IANu)Vtc>W{r0Fm@h1EX7 z0>L*uczVEvl+BJ!@`N=}%K+m(2p>?@*ywUuQIY3RSfZ}|IL0XvXW)Cv(&%dCvpg`U zw55K#l`M9b5=zS1nKM3SHIb_1#e;8zGz^6gIQZS{%FmW@Vq1U2Q94ZEu}|qdP{fcH zKB|I3;E%G;R6Z}-u`%Cdls1tq?tK;#S7*Y10H`P+IO)iB$A0O`>df4}}_rRpbqIu;i7;blD_UC;D6H!ELA zY~1S)7=Vhy*vO6Nx_d-dIJZJ(k7GsW?GgLNnOfqFvkAZ+NFkMhsY-j=tF+q%>!zkE z-w#tVS?$C9uQ8ASUzS?bEsI(UG#RejqO&v0#J%- z@u!e4hNwh<(x**u@c@?37+Cva@i9ZboE5{K8-9o?AdtsLW(Gk%2~E;qjXXY9a9VNr zqYd)EgiMngg7Uj*7tH6nDRQ5LRUjMV7PFdVs)YTcIMt+*1kDyzF|b9eId9?j_el-e z5WEkqRuh?+v6P~P`^Q_?-oY^Gz8>2T9!CugBh^AcUN1<6lu5PX_i-Sql#g`Fgzoee zEuWZiseef8p;KKLK=+l60 zFw7ZxoZH{`-nq5KEO1p(8}e}Ck`&3_iH5xi+z@Y6-6f2VY4aoUxt*d>*pTX(YAuO5 zwfNib$nhTGP{AZ})m!8{FPUoJC8+DL;A4;AG__t-jRlxM%xh>A{=a?4gStnpN?%9a zPrb17Nu@d3R7GXD@FIq+76-<#lSi{*$uF2;r$>^j*vQ?tPg6D?o?&H)LyO6bsL=cC z8!B-_puxM4p@xnV0Xo=LWP?_G;GX+ClY1#r@fQa!>#k@~H34os1;8X1zjfK!EJ8s6 zeM=}bx4JwD6${5dqja>PA+#zzlgD!~cVo7$K1luYwWS!vnC|qY0QTQ`Hw#b9^QN?0 zx|%zU&c)dzF7TFs*=!uIH%YF6mqhaN>+M+8;)2hK4XB19xo@W#c;oP@tEDmQ`5ki> zr$|OFK_8@h#3E!(T+0?^p&v|ej8thY&@`Zq&rsjvii81Aba1AJ}zv+J;?^9;vV3=PD93 z2b7;;;g^TdtS_-&n1A|X_p6=tRrtFLpc1oeMO4~v*fM0 zfdavMy=*G{axJZ1S%iY~%M&O; zNWODRou-}n4)^3=O%=D>+v8W7N6mH893Opf9WRP%vzoxdKqjytTeArdMF-gR^-d+y z)pEmEnRI<5I(hXMYzt`vg2Qs4`zLI$WP793exL9glhP$(l2XDqu})eRTTkCm)ej|_ znp_sLvY`0EX_^{&erH%jt@yt6D?T{Hnl-4Yj0~bv}GQ5m4dy%M6tf9nl3m%p@};yK*FLvm09d zhA4l@@H(yc_df;rU!rdw?NNQ*^PI?%Q1!gHTK+4)Zb@dnGRmWOpg|8 z(Kxmgs2G35JZ@CsgDQncm8`xc18~VGKkL*y(~#qG7un)@5`K>bpo)La3cjpN!xwN_ zOEl^FKxIcxDzMnnVjz9GP7i6D&}(bq?$*-7>9erpf>f!qvzPsyX9aevsUfZh23A*U zt_um$sxM3{C6A5fjqHJa+jE77S7Gg8GaY^Q)7a^G>1jYG9nBGxJFiz(JV5*`bkFUu zwjNOMe62m4bN%el*~(}Ioj>>QX)uQj8ciO+e&*WYPXlvsahdGEcpj-`tLHyrCM zU$4LEdt}qUBf!6L+{rnRrB~W+WKkg8#rg9Dy{|q+2`GXQWm>@!4YY2GinrM{=(~=S zef=#1$I1rq--6+E`OAj20A^uN?Q)j);;{6uM#wvAcxc#btqp-$n0H^C-#`pU_&)ip%vatW|DBzr(C~vA^!ck^v4KbsJ z3Lo6=t6K$?!JxTfbL_rNMvd_ar}wLWfT));Bo-BC`e>kk?vbRye;iAC9E0xZA1xq4 ziK8pTx=Hv1{lX)xHuA>5YsTEoyW?YA0bebAPy`Sx5g`J3jh7Iwt1zqYm{KHhL5tJE!fR=Q-@fv$YEWUME8zl3Xb2xs+lNE~RrK5=8qV;i)?EgI+eW+H}r9F1{wrrbyuZ`}WYi z&NS?@^mG0^Q2QN9!^q{ zJ@y-{G{&KTd*qK<(CzxuD%*&@~ zJ~EjA+&poYHcqj{2=;CN>VD2PHVX6erYfsSnJmh%1u@g(yj@^{7vs6!-cQ*tNf3wa z4&VxJol9D|NmsY;Y!?1KxdO$B=`iM{?i&beq$xfW!=FDt-zfp_o3+! zb5OPQ-azH)DPM_S_7XPl;*j+_@r+L%_zNa9I0=xo3_(F^wZ%HmYb(&})!tvA(W+S4 z-{jezXUD?e;=9;#-{&Z z*t*_nUXWL0iS~evLv47rvp@}e>5(ViXdnNt!-TOE$f;M{$RFP6_ElYz>inS zT))*Axvt)sb5+ZDG2Ne}RQsbaAeim;nq5KlLECq)!F$%#qh^1|+Il+!Q;mVglI?L- zKY{hLZ`0jNR^CwQLTq_O-N)tL727{dqJ4oZ5T})VDX5Zx*O#zg$nwkWxJ(MGGWx0Z}Q4~=g7a%Ci{jxA@RIt6-iT&6r?>u@p?=| zc(UXJ#&*Gem{5+vkY)Y*&IyH8p?Td)0Y^KRyMZbAO7r&^pU*8brhF6yQmds>1t3U= z;-NOG<|-U_3i%%qU&A00m9La{9oOX9D%3IF8@y*V5g;u3>zCS5Q?dIc52dnXb-U&7 z>TD{DBuQrhdh=@97m%(8r47bn%pHHEtO~yzQp9;3UH4Qhjini%4%=3YNfGTm7g0-|UFAZWdftX+U-#K= zEcHt{CUtEs`m-(od_Bk3ccYb@JHS_Tq8*)Nu7Rz%4c;}<`(nSlZQF*Zq_&ZQ&JF3m zWq~Jm?E->oS{=m4;s>JzEEILzt$JS~7OpctnD^4u9WR)) zHMrH*EeD{LG40(?GQMHQxnW~-tj+lwwF!CH)GW--iQ+w^hxNQ~Vidc0Cap$g+LBE4 zWfj+YJWjHc32BR3tvy~N=XxfWtDZi13)q9*Y{_AzG*=vCK+b3lW}I47nP08zFalpm zMU;AE&Lc!U(^OremlYhgmlZ9p(n1ReV zefIlfTixs1$yUGVgY(PmKo67aLaX2+lo(udOMW;k{wrU-tmZ5iOIcc`i*toAV5ne~D7X-%p#EHYnFfd@&4blO~gd2Z=&Ii$m0B6fPcR3IH zci#90{m+LY57-hJBuAbJ`K4>6$+;1FG!+#rT?X&nh1~wY{c}Ww(_OS*guU7T_&A#O zPj?-)p>uAU?wkzFm4oYvB74~kiZ`R(nuBh#k&B@aj04{bvz*+L^Xk&;xP5^9O6JpY z+wDw#-rWmjx8)ojjO(Io9L3~JM4jI^@{tX-cbPXTcc_%2=jHs zGG0v)_VM9vA}7x^DQ?I&OoX0%=}Cc5cp!vNNF494sJA0vqba2o2;YgTXt;l;fJ(`cti#cGShi@8?RG&Qa% zUEjI1_#UV1PIj$1bW*D{!sbLt0)*_*a4S>jhqvy^Adl_E3PIvGY{@7rN~Cr09D3{r zd05NSDKoO2#3+jeHM9xP;4mjh!I$HhE> zpApENe)bk*BqhGw-^8_`0gC<1-o3d~^;LR^J@NnatWi4eh22l6eT&Q-GX{vke)y7& zAHPx8`FC+Nu`Itp5$aw^r}wi1E=}K14)f-|^ZLaz{uQ5Sw~9fW?;ukdu9``Cx38U~ zLK9hooT7f1da$0hGH0-cz{GUHqo;fMcO09ho++pICHlqs)!b$$1M7c!VicgbDQff> zdx;i*stGW%i&+3{IwOYOmeU=0HZ-AlOuhfDh)U}J2}5kiHiQ9&1T$KN%*;G?rRu<< z#_)6nyn8>i^{;gl;q-kUCD=MFOB{9F?-;oJE291VPS|t9L&VFhoeA!+S%nT z)~rk{%tH51%^UcMlWzR*u*rq_O-~?%+VJ}GXf}xV8dL)<%!1v|riScsCY7C%kdJ6h zF0NiTR=oVFeeB%nU1`1NuQ4dO}G$yiCty5#b@BEc+ z9;qpceg88&616I#eDSv8&iY~X^HBXi)Gd!LDxr>`eG*C2F(^mCn`%xD z=4R|thf_PZi;Ej8>Rh9@sMBO5;m>E9NpBA9g-lt_dL+e)5$vmiw%^L9rR!S}gB4m{qE4mB2QepNB`teuzR*+QtS zp~2#*55iebcCC^LBbWIyjey9EOc@RkuKU6^=_@<{dOt;d5#gQ)i>~Of$dR1`?>$!Q zxm@vt1PbU!ovm(`l?HOkHT&qb=etgKDl|xOc$YX20#F2Jj4IDiPc7g@2SF4&i02>W zP2Bujo2{c9uGHGvouI31s^!b+ujKEYA=bYu4Jn3lnmG##ZRJPG%YY0yOZn<^>%)xx zMm*`Ei^k&|UL30RP=WO}290(V=^7D+H;*#<_wYMA3SJj4f(u_b1nKWV6#CyfM{SpvYZ8LM1 zZMLH#Mq5%fbvI0IUmTmyH8VAr{Rsm#(xC&0vIb$=ZEZ=Z9lhf(gpN`6dJ%3)V&W%I@FwAr&qDjQ6<0Z4>^kjT;PFSMwmJ*uA8J8 zhD0USw&h~b)&NUBqDv zPG`%~|3ORR6u*T#{~$Vg6%7ZowlXr^R|(7ZMLv(~Y@aP}$do9@yoB4`+3QR?sNzGo zii7IxSEi#S*K6BNv6A7sk5Wmk^2Wf5`f`kV#9w;B9y0seBr*NnF861tDYh{iM9_#` z&?yxahLTblCeoO4fL-WzrYSr83Z}B&oeT9DlS+0*O*L$ff!j2757eeC_MRlmzK!0! zyL<`ppIry5GY-Rb34>&Om%NEKOhBfSx}U9!t`u%#RK2Icl?li+pN79)9HcSZ*2(z# zJmlHr=Gr>Pb?)gk$2|T?f0nTFmxVf+V@}pTit%gRNqXpA+C2t;V%LBHC5%Gtxkb}z zZA3$*(oGC|A-9uVW+nXjH5a={w3~c_#1|DU!GJp1sIxtZSYc?+I5n*V>wU6*_2pZZ zw{@32uhW3KCr}CjA0NKSE1XuN^YZPrZWUbaFf%QM_kpL_GtZD11|>eUvmzf24nq2N zEmj{Uzmd-D4b@vSp}BuTu|ZB!xEb_ngqnZD!-GBuUh~imM0kYqeD^_AK1?+a=xuKnGgBCbJfS>oV8ul0Oij+4%a{EM zxlgHv$FSaQ=`T^4(&Cx^ymEraJDbA$jwrh>rXKIVAa4_)bDt0hAynw?aKKyC(Hbgi z@w!zNd8S_Py7AV5g6J}}Gn+sEE&o+a2scSX@n%W&{@0$!ZQtp-C>}yfCoi}GgbiH( zvUIz$Y{0;Wi7AvjR4s*B;Ved=sUhy^0mR51(KG$Clre+ZMKH?DzWUyM0LujS$WL*; zHB=2QXdu^rt@XMvi%Y`uL@;@O`@0TpDSZJ{cMFd=-@?x2v-{uJY~37)cj3}kK_;_4 zJU2*eg+FIz5c10CW`rWi9P-B(vH&>oQ5Q?9eKQ|gNs5*6j^NY%9!d*oDpD2Y;@2tDF0~eHv~wo#P-3f*qr*-ipzXN1LG=a%e6=D z$LZf9uN< z4KL5eK)t~-qhTw@{e*zx`1K2d{(tpjr|X%D1Eg)sD`4peS^k2Zi`$FG+s)vs>LJp> za#CvQz@6E{8C7pm-vZqx+8BdB=zuZe&W>Ea{Ul!+8-z)-%yhREL*~_{XTr126bV7g zTD0%{aJ{{u9n}e2iscE!QBa1P*6wCtmfr^Ti<$F3~+McGE&vRf`8KJ7k< zcSHCPp6T&;Ndqy(c#$V)`jglKihL56YdCg~3eBHl5)lf@YVZ%+a|i46&x%0mL1!?Je2dSghK9Ak3k@U68i4i@>dyu!U@!pawm+Pzn4VQ1wQm`5PQB$8E0lqwvhO=`!X}7`ur0ZX$$$mG=y5v6SO$X-Q++S)sT=!jNO`X_!Rl_J&}Psd74^|BnVT$`jL%v*$|Z zM3};KkU>ZBjVbFp_}tCOhop_!j>*F_jC{v@SXHRradIBn+O<+aCE@4b=%=Ynfj{Qu z?e5*L>LPU{U=61wqh8)FAkA`2t^PKvf|9apW5t66j6sW|W^knZUW-;?d+smoCKyps zt3+J5lpN{**bO#}V%WsW`k5$ppAO?JZAb>Zu%lZE$!eyCJPJ=X-x$$b#kbEBe$0JD zgOfy|tw2T2xz1o?u(qCU7JsF*+Otw^pN1WmRa7)=w+UhKesw_SY;N*3PZTet??bk~ zJ(A9d$rZdO_!_jiRtbIHc!aJyMbkRpsDu)AAWd*NTEQ-5X1|<2+L)Lyx+hcEVEotH zXk%BSJQKU-lvG3N5R^K!I7ARR{<3FZQatphtYdms%Ca zHppj~+JqDMna|)?;XJ2zKY5;u*(i2gs_@^B&V1vxLs!F(xaw2dz?{0Jn32yy{tJi3U&eAkv zi&Pc8?z;30+hude=IhCiUXNFaD zQ9-$5Y)pH}xP=hX8IwCY?9vZ1x5@3bC^T}|#IB)jUJPPH2l{$m);88# z)H&3<1U@Iea)h2L5Yd2%?KOd^x91Ae_=4-aB;@yk^%)lz(D368g+HNk0xyR-B5lDf z^2pf-m#7HS$qF*$-uTC;tBud^&p-2s!gDI;_42n*HaFOe?o_MV;jhG5?*Pf;{>zP>r#A_Xe;JAeMYV{C+$p6l zh^#~lK-j76&ug`V8H+$$eQ6B9N_{;{^hxkvC&Q&t$q|-WDz=@xJxjEvn#0N2X*a*kF^6 zS;*zIKT5^trvLdn1bf4oWa%R7_&cONdvQcEH*;Urm^D5|Ig|4lV7x2Ka?@rhGl4;QKCzLri* z)FXhv&|&qU;Is=ux_uIwexG~*EiRk|{ZGelq$ukiwR(gNyVSz(Z4H^?vs1_<2Lxg7 z<$#tUpr$aC@Zkims^PDzjZCnIXU^SnPJ||q|MRQV*6WhFT!$5C%NpR+czKs1Vkrma zn5Bgas_>pxH|nh}sZBuEbf!PmW|xQYQ31=c1EKqHEq;)vuk6G+&HL=8XzxaT@vUFB z+hkqG;a@2$3r)cXnVZ8A0^I&rz(u&fuPK%-W*S)i zxT6@omi*zSB{cXvUH~^0MUsS;sumMQ0Z_m&%n6++W6JcRhg|>CO2lLG>hcDXIjmsqSEV42S5fmz-yR>G(zgcA?1wi$1gy09a^mP{ ze|Pd&Jg#A3F0RV8ur4X%&qgR}w3_g5`af2b9`GlrcM+AGYYW;f;K)K688_eKZ;}u9 zrkW6dXni!DsOiXIT$))s2={Q^@itA>!%mB93L-&H_F7(&H0XHl`3;2Ie!4D}z<1*l zBA1;2YuU4c7=M2*6pNp9TUkPfMSpucpYPFxQsPr{OR7sd3E1@5`CPz9cyiLYKGXAmb$&3Z0rUpX|F+hBg-L8| zS^tHNYB>ImUZ@b%j)w;jaybR7pfdMY{*{_6g4k+J-9Ow0$uOwnqB{=v6f)ByqOy4e z-D@H*Dz0GRB7%sATJ0cCy-q73qH0yYeoY-Hg3{{voAD1`%enXty{a^f^&eBwW1G+7 zBhPS3rfM_lc>cKjWjg1_kKfm=3n)V{`PyYpRE^Kn;W$OJ3)8MX8ampP(YtES*RU*j zH}`wo!#_2BdD>b-u(dl{dMZI`VR@fK)6f5wHMT#+)l=2N0}SvdXUOh3<#CvrKcN9s z$HzrNzMgcv5uwE=XQ;Ccz0w@fyiiO*XjrOWXnQinxzqilBN4f_rsz%|uKaM+ zKEKD9x4@3i2l8BXl)rpjj7$r9L|-0;B|56_j=Zy0&T(?N!gr60VZ!*>n9M^jRT`pIxQSbXgWVRa)!4g z-bNBPY9laA^IWVjDAno16Pew*$;e z7T^>3G3%Z|!4aV4ZyO=QSORk~EdeJo&r1I^#=rECEVYbTn{0e*C~}{l2oA z2p%>IrbPHn|65Qh1i0|aK`XE!5q|a-Q^bXzH{RqG_q}MET-2o!a%rC{a{sfC)daBV zAN_n;I5?HDNDp|KKi&^I#tSM><K-C61R!A=rY zR}ZEWfyrAySwgp1TSe$$NQWGHK@HOmkKyOMS#SYCykv3o6_dQ{2c8EnI{;Wp6^Mz6 zA-o|CstVHEVv~A;3gXPX=uMJO0hnvyIZFea68OkuVgJl{oZQw*EAI0E(gfi3z1e`AO?z&$VxpoH-l`E1o2~2!_+} za4`54?VnC|d$>T8siCb5`A-;h#;Bzr*}5gX4mRFax8ukGxk-1fb-Yp$B*0X-^{}yeH z^o&%eaewlc!M~#KYePiI8`w3n!gTbUZ*UV7(|!|zfY{THu0*Z6K{o9Fm}=)kf%=AF z7y4p*3sTaQ#B^f`pcOnD-k>&^z&Hc-4q~GF0vo2(EWw6U)&lMuVwv|XzSH2<`{I)K zi#5(7EB%9@?Zx!WTnXn>*|Bw1tA*FQ-bii9fOcXYLAngT{3;iNDJgl?Gx*&c1ld?9 z@VrCk++uyQ^*a^py_ktrUzpkiu{+>RGjW3Y#^T;KI9J2F)}_~DKw{>AYQJJ7C3hh& zF+tpVkfxF)FDILiSR1I2d-C}0|1q=aQ^(rtryqbxn%$^pGB+A;*O8<`ph^%P9#2XK z>vwf^gQkYs{4HZsoLqz85OOMFnW0uiHfB~1WAbg9KSU?R=Sz*5@%6PyGVvsUu`*b< zT@x-~B!Y6NP;{~AYc3y!gwR?!B-xd;2i5%^+~CI*pTjFs*z7dV*oH3y%SO*az`ND2 zMI*l~S%gLOmD$+~g_1g^92FCqNYSro?J=qaA|h`J&!o>#G~@H@%Y7uod=Aqebkzg4 z|9pMEKNI)7KtVxSk6mh1^enI9xQ?15ym)nBt}&2_k!oyG$r@SpjXS@{1_3D(GsFqd zCXcLjjZ9P??Uvm0Z0)fy%l4yxH1NudPfk*3wldWR|Ghu|^gvU7w_&0O2xZ4B%}7RL zV`WX-iYWi1Ac%+bU&$41*GP1KxFajlchM(WOVqv-0_xQL-(yxGVaxs5GX>26pMojWd$afq3 z0$n#?>rK8Uf_n}nO>J>&E-_3DtPobNE=(&*&O|8G)O>x5I&=wjmXZ}-)X?jx717hD z^xqaFO!)NwA@#SwQjXcld+>u%Hb{|x6Bkd(uf^~8tt)fRxN0m)9@>oxcbrgy7^C?& z?3fN_!TI<$rakVZ9p995m({{$!$sxQm5V&if1mL|MmzaZBtddq;S)~;)K(_K>1 z4bp;igS4cigfvJANH@}rbTjxCePu z^@(vv6(`4_pO7ja)>&EJ>8L|7=@j#{sT&zt>ubhcV$ojyZ0_zKUl@zVt4TqM9ED81 z0VN7ho({-uYH1((3YsY}N@TnQQp6^A+`Td9-pm!031^MDecKX6YH;*RP*L#d*fARG zvIqBH%r%(%z07$=VQgd~XxzxG!&ApolREBL$?eS9*9fFc5shXXWmYwvUaos^xc-g> z5rT1p(J7cB_IiBFf0RoB`xaLoQ~JgQ80H6hNEo47{G`n4ss}DtXA~@-F3g}GhlV(7 z3r%aoaMgUe8R#o4{1%gP6BRwo%yu)=r1EAGBik=ogP|*4xCw4I9iKG4KRMev3)HfX zM=g?JiFrC~Va6|kAJ`T)-4d$tEoko1)I+eK{=HWq0#p>~4hh%_4)~}jVq_|JFKFbd zi$Z89pHn5s!$^pVUbJBTz>nCB9$R~tZyp_ET|xGjO<&>@!lFV7ayq+Xzj?pBlhph^ ztdrG2EA)0_gV+$? z#T23Z@|MoyqMzYV0^g|+c$PV(ks>gj{Z_Tfxw5SfIFAja71)8a&JA7b!BD)YMMaUU zh}|TOl$M}a9g&DLBt|v-Wr*}Eu5wDF`XkIbYa7r(UumZLX8UWxFW9>$6eqH>uJOMZ z`KDhrya}XPFiJr+fXepsJ@b|{W;z+b3FuiJ%6yP}_1nle3IUiFhEH{2dw8DLyVYxI z5I9OD)JuPA5#OZ>YOfV`_+jE*5hGD-T4!!-`Zi}Q!(dCN@F$0(aMJblE>N&B2L~%= z4Hf^I`wIT0O@HSM9)q!=VxEQNg|yc{IwkfuVZ5hz-?1*Mc~3Y_%o1!vrjw^8HP`OO@Mq`%NFGFajBzs12Pxt=Ob^_Q9{ zU1&gJ`VkG29UZMMev5Wb^-mK1f3s^??5>iR>?I2hIk{AhLRv%Lr z-GR4*_^)3qp>L3A%Jud~0 zmF#(S5<~iy-|ODG?*n|(B?8c7c1J_SUkGwUv|wKMlL#8Z`83zHpSRg)%WMe*Z5Zh^ zm&!FHi8G}T_yE+W=Po~7|Ko1pfxe7~lSy3twj-?yX|0TRd;(A0IS+wP1pgTNYbcOw zMzn7l+!I_hcz1JDj~Gp_*(YcB_~A+56U_Se=}LPu@dJ;CFvJ@aLnPwaq>4B2fXgCS z{oGpjduqW*4j3EQ!~RX~F2_pA$-DgvRKaS_iUT5VfB{NB`PrXgs&96F0|8(m!T zWu=Dz*@Dy31o-gj8khh5_#2SO=iXI!ccC5XQ}zx1n;t9fKBMRFZB&3+`K-RwkM%u& zEssK|UY+whznf-bSTMp36qoGGD1a7m;n;nMcZ&|!?3Wp1#|fVrn@V(lP>qn5WPD3$ zn1Ku;c${R^gCHRqyZuQ`UfJ((ynn}SHW&%HwDvTGuPA(jkAej=1>0<)}b%GVv^Ck?tTW58>kLEbB-R*T;Oq%pPGkn@MSW?!k0mmKvmrXA>C zdM2h_?#Z$%0i9(ZQV=e)UOg+@Cu+FxhW`12NKVKYWvcFK=FX!-n!>C?*}ulTbVR)^ zR+Oz-_^inmjOmRir@K}~~llW$h>b)}7Ds>?J?HCfE=Z%o6qGv=ns zw(m4|bU>IeP~J9<+I3w#T}`~Yyjn+Oz{{g4aElepPc*PGho}Ntd)(MEY;f$&e^8^` z#>ek@T26TQmb-f6v!*7#-LZ70*DQ=SSK8ircKnslBGo2zr-|RW&oYSUJj++bd4-AL zKsDF*6Np$#hlk}#iGY}jfwJ=1Jn_I^?gV9|aef|uGk*h8=b`tPyPGA&0n(}JBYC-e zcRqKy@Uf+l!_%JuJt)A}u)X7x7wS0DNeWDc95Kr5f9;9|o;0$py1MX;<1?^%1aUar zai80$FI+A1VI~bflz?oxA@gKtE9b#UIEw`uAfC5&*H37n=D-7FOOh(VL`M;MyUDP=CN$)Og09mq0*fzm49>Z7s;eI3Ey$v-E zCv66OBE<+#5Iz0%a*mF=H}4anpO9V@Vau*RWveUE2e%czXjUnKrN6Qe;yOrINDcmc zWrevUM5N5@W=BB?2s@7ecVAzlwWdPTIQ;;7*g{rSy1QHRnE6O#(|I-INRy%(0dPDl z#2D(NDjf^=_#DTbzKs9;M`WQOYzBmG%k>Zgjp?M0gF+G{5(RZPg_t}?s|%B`pR z%^fR9+kfLeXblwr z(il??!0#4(y9niF{ zg)BvocEw{RPGXYcP10uxD{<7Gxh^v?(3#yWd~R1-{QxPp@y#F47hgbYS z&WxvVjt#m3O_KV!=Lp1Q+N|aPstcIAPl{VmZ=pQbMH^56U7xn_df`M^w0gqu^AnVd zZ-0{|EHj27h8honmOfwtdp=FHs5G2a3Utk?kk`U@YC;4rmWG zZ@yCLCmu4M&(!G0+)|!TOhU!~fJpJjF=r)Y^infGWn~elsR#Gm!W#4xk~8lZ&GSN< zK;{Lj8_(=_+&MdEL#=olR3N5sQExfe6NSd;^wtYv`cD;Vie$(j>c7cWa050O$?mb~ z>4W>EAYZ{VSWt$&S2;~j9FVQ3N>#YMK!`^eoauiZ^!6w;#0>F7_p94Y`v55hFx>xV zBjRD9ek;krf^huP%Ylx-7m<^rw2aGDE94*UWg#tk@L;NMPY^rz0yB!-XP_Tw7)XvBFdEg z_M43G2x^kRCI~fy)KSScrB_7qo zHr(U~PNx%EOd*ynQXfKoavI5jc#T0J;g5-D|K2`Oq-Kp9NDaORBLGODAP+I`uqrtZ zQkJW-0q4RcEsVcz6^^;R5he31$b9+y!2ZSA0g(EM@vA|2fQ5sr@O*lf(T;ua+kYId z@W_Gn0mk@NgOldY#>bm82l{VWmDT;ALH}JA==)3v{UBo=ve?4J*<)JCR=qUcNNoQaFpI=i`pU3dJQD1Dn$F1LQ3;DAY6H4P@x0sfdrgSkYifctw!186qmffgu zsR%aCtIh`&?^(TqPC{);)5GwvukVb@=*Y-aSgp7^x@x8X{UnXI*n!vBJW!Y33!j6S+I2kgnAcf$d$yNJhGa-?m30cF6R4OBrBhdRHkH( z_r`SVQus6^Nrw}4QH0_XV6?ALTj7IvY&HcIpzuh+nV(0;7*Dw-dOUC2h5d!>V3oWs zZx&sLG+=&3r1E4}+IhK*jC4)KHd^@c&8MfK!hvG`c7kCq{I`Jd1sjb;f9z4`eo+~( zXeO*@JmcMCEJTbK4&l-C)3#Xh96csP6jV9PqTXl^4zj}R%eLMGQe$QCO`068)1)-k8}QM+<_N6fCMsS z`8s_&EBz<$y zT|CNcj38;S%by-@SJy;z{kzLclA~hu%5ywWA%g6uVQsY7Z$%!^el*9+g0BGB-rL=5 z;M>{H@a1_Y!Og|uxia$&j}NweLw$)abz5Resvp^ZeRM`(U?@Cg(Lx66(!dGn)|29# zu-2J3IEMWQ1vN=ZUZcEW7wPM#KAy}iAXw0`!Om`_-!mBfFm_hSf;7)(S1XrW?%5$J(jJVAe`cs`0&T~T-vE) z?Egi??@z)&Q;z-%5C6e#LeVjB#qnIzfl|GbiWx%BL0?J%drhB3KL=Qq=4dAQ z%8wg{h0h`9(^7p&swdCQNp!Rvj!w)E!Z%>pvH`|N2n1r9UrQ2i!KlkL!@wX5YoaGE zt|a;+y~6M4G16xc4@Vp>rwR$NVJ);-{ik}E`Ul1;BV!ax%=oXd$>!}(_PgA-iQ?y$ zxHSG-uF$-vbBAq8(iyuMBHu>um+i+qZ^Ihz`VK6qQ@s8o>~ zi!DEG?-q|vYu{9zcv^d#NdsneySOsVQ{h`C{*+S!yJuV5_x!0Dym-e7JX5M^l#XP% zV<=J5JljyVb%wQ>k#TY>&sL<-cY6}Q6dz4rZ1|u_J!|f9|3IUvWY}S>?N~-W-7BMEr1N$Cg7$_Jg5}GX>II*r5;oTqwor?@+`6ptfi@eSKanFd05#nf_q5Pw(-%>I8!8P#neKRw!)P~p_-+OfvC z(=0a$gC%za|d-e(Lu#(o@_Qm^{psVZ2Kkl z&arttEZ@(McT}n+?ZO90xwO-@BQ7=C;M_<13@hx2fi>Lmolg}Lm`Jn?Y68`~c7}rm z?cfzjQkQVCJaoTc{T{$`hPz*T@%%*Ob$WPzsJWBe?hOfzKa~G86`vsdsJ-(d{|JW= zr78ORzE&5H^Wkk~{B0D~y*C?|es?g{QIeQB=n08D-UkE%d7J9(WCX8UgHk(l7B-p` zWkjRzG5|%h;S!bkWPfp$H&?*rqPVdv8<@K z+VtBXgG-OwyIJWd6n^&<3%4vp%cytvb3+5BL1}yhv@GsTP0jg%68=ji)pfrB6(tV} zE03}oRH712g367x{e^FvqaYi2?|8lb?%J-IjFoyn+BkiW{XvasXERSoPD)PZr5C5lS&&z3=fFL+E<2a8Sa(MI>_>YC4+X2dhSbC2Xc_eqv3KnP za%>hdDN4`2)C6aAKB~~rAkb6t;=uuL7voYJk>}a^hM#EX=i-BAejC)cU(N@%yH+5v zb<|u)?if|l!C?ik_pn0l>C2vr@TAv@O`BDq0a)m|5D90+F@A*%aNwod^n!hjIx6!! zt;Z=QlNku0rrUKdKek|Z9U7@?E)zf6)@t+$+NBTaLILM3zmh5mWM=zXd_J+pI`!6y zQ{F4+Y2E)!W$;_wuhQ1z-?4q(uIGGK3&y{%oJ_(@Ax+Gt5AGBExt+bL3;KsUCpX~E zp81ibK5K{ zkt~Jt`+4l?8bG1upZ3zp31fWDiE4!OroUvoUoH<<@Q%tY2`7mz3BR&K!Dk^7JV+>E zKl)tQ3O%G0cYa0lp>jhOrq0`CE6lW^aH3t)fe}*v6=5wBp%QPi76#-EElp1j0{uR; zQk0|juH+UrR0*hWo&D@C}3%;otgOtz&9o9*a%K}dC1J{KO{6o-q8Gh zT(HF1AQQ-bzz1Oy0Va&sk!rZHYjOBosiYg*YHr`+`FY~|wW-2ry{r7Rr2E&sg?G_6 zK^SZtE+K+~hY=y|c(-OPeMw|*3`=;Gwgk^E75$H6Z!T`5R6kpKSOx@ePIb?otR7k) zdvSBr|CT%)dGUNwbwxd86Rd$vM|YO0ljfh}U$}Usv#7aaVJ*d+UXUGuf=-O-MkG4h z=E-iK@T=--cvz}r4NzG0Y^@5r)@a96Y*U&tBv_i?M{;lVu6v8))%Hl@cvk#jI50mcjjHlIGx>uAmJgLfC@*w8k{Zj7O1e`EEkD>3iUoxEqZntMm~zJuGLUDU`Q~@l$vZYWC2ot2o^hGWgk$6r32_>M1a{ zZg6}en%U&vsrX`&z|!@N!NQ78vHa@%bE2G*ANPln0b%bXgXt>yJvihwg8wa=>|{B; zk)G*b;tcs2jOv#0c1~t7<}4>h-=$ob`@WCDtK(?>^jJ>59OwEeWbJ9cdb^8Ka&iau z|CT9#F)%QesAq1ja?d6~z-Vz07Z4~eYy3?CRyP|;Ek~g4q;_5G*%<;xg%RDU8tg3U0-YT%d^yl(q6 zk8y(V!906+Ou4-~<1pl_pmL+lix^zwlrJsjIgr!o;?RT;=xh#~Lru zK)BeJ)9#oTE}`-e5a+2Ab8;wA)VdrYX|*oAa$VpmUAQzuEVJ8+yY#_&Np z$83!D1usiGDqbhV$GQuOXVFG|Up8waoNj7L`X;I_Kd?JR-8;ZLy5Vs#F}+^)SZ}ev zPkxt;&!VHl1HP9=4!*8sYO>*zP6PcWL2I+6{LS;nZ~e1|)CI!o0JgL|vwXAg`y*X% z3}G@+SfBNCrfl@z1~1tq?-68an%MMx3Ls$zft*d2UyR2Pevp#u$I1Z$6U;(-Wn9$2 zt6_rA&@BTQ7z++kuqwgQFF{1mH(x`9F6-_a;NbCFsQ~Wd%-m39U)g)-Qx}5mZJ`;r z4=R%16|Cm#@l)}SGRNJY_24)qJ}O0^*$oKWa0EdDGiDVUgv4T?@32J}prAk?u-xQM zcPT4plaa2Fx1F5HgV0y7s<&bXoX@%t6g|?wHvU*f>>dNCsBtCPV8WN*jPUOchaIG7 z5!gFNB`LlcY`GjKa7QPupm0}+5mEGDDqR@}d=2Hp&*$fHc3J}F&M2u^G!}f{*X^Kl z8XatJ_A6!Ku{Zv%-ObGp*yq97HZW2x+=;yHVm)u}!8I@xfhP3Y5l24s7~2^10{cT& z1O)Qowtu-I*v{Hr0=Y0=Chs?=_g*~t&zDZGdtUfPCY{OSqkOxh;k)0(BCEchGw7hS zG=q;gx(7|dz*@z;zo?6&Pf!>&c^9u%dB6aZpISgyA}&DbufebqNQoZ7nnZa+( zHK}tzNSNT6o~8x^fYunG__PLM$j~$ z!88sUw9gM8VW_-UfWKHf&a+uMHzWe&OS&g21?tJ^G6$DdS-;$SXE}?QSX^**j+T>R zgxDdmK2YhjIwVWpc!2hypt%OJGJ8^*Jbrfc5Fm%Tl(yQt_i)eksc8utG_&L z-UC{D#B3I*2v8!@zcWD}kq|+kGpEQn(okYBJSM@bj+gUC1`^Rs_qr#JnWYhJawvTj zO^!`vZ-|54BBks`j^X{~jnj4Ki2R7mzc-YK3}WTUv#pGtKAG7T!Kb993a;m_PK%dk z_4dfCY2jw*UfaKahw`$ra$jGsYh>fZC1LMJ^XNzO;oL&yQl`?4QP%79GUr*;*bBJa>u9PmRvTBSe$3pIsO8pYYbTw%u z--#;#9fGjIfRoWt+<%vZjjk@)WZ`TjZfEAhUES41P`~s~U9)`h<AVuyI4X%QcIL`A?z$JE$MTqpD#cez8&}o5O;@*?l z1$a-*-ff zHuu!$Hn5ichXi7YkYln}T=^MqCc95d+RRCaWC}sjxe=NXm4gXd*Oj4sUrhyGUm`aj zPOzuk@bJH&@P*&(8kq_oR-Z%Q`=J~&^Ru+vf!?iK6!NHWlZZd|tABE1ToC9jU;OH_ z=H<6{?Eojo9QmR}%Cj}IO&%1Ch-{`O;O^BKFL2}F`0K7o_|O`Y1P@N(6*&&#JZw;W z?U2v@=IG8T20mA%LrsV7`uCEIEteNkZ@+8PZ|2R;?+4D`I0V808mzY7eI!Kbk~-^i zoH~A`x;l{8#c0Ac0%`ftt>uZqTbbO``=90y=asYT=%tYh!2zOaApP&kxz5xJT#Ckj z4TJnOz&Bv-qB(VUnz)4Z1gE-z{2zi)^J#4|l^7vi)9S1Bmrj=(OO+;5rnWJlY?0rz zuVEIFqvaIMqG=MB%jMKB5?qa!IFUua!CxvWjNtKcT+>!K8U z8r4#4%qtIudb%UYyaWZkUx+rGcmj4%Fb^*Kai<#*G$Z-ikra;YEAd~SBJwtdi*7t9 z6-qKdvg)gsr*2m6gV>Xw-iH_9^)pSoXf|y2``r%9ulCC($xcaJ?bMDTFNeyxcfLjxW2d2qqT;oWD6+9KcqDO{? z2+o-!27}cF+CP?eRqDv zp(quXkf!-pBf;doo0F707dALf~7BD?gb%XORHvEG^FI$lp(U+uu6Hc}`;`)2=z z50)0vVxXestLWwJY={CH&SftIx9WNfwDU@a?;%$mr=k9LwzeN*>k-h(J%S#B)(*%d zg{yh^El*FoqFBLt9P}yIch*|D}2W+8|BdYZq1QNs9eHd5~4NcNCcu;i&a@?AUa3| zsD@Tk<^qNL^VU3;U-XG5@a|7&Ml!F{!k(j4QX>MXu;diA3yRP41XcT7eLXW_-v<`9 zEH^z8ht*K#$#{rlrl`Uyy>*p!D%0PM)3;LfvbSH?ByHzqVBt6au#v}*$lSj&wuS_1 zu?Su<=NJ9=pZ1s1CHJpxal9`e9uDws5V^V$?C&Rq|dhPqmBkNsVSJEtLUhv_5c;tipsI58Uf|b_39yu!OllC@aza-LPd_0)uU{Xb}->ioS0*JVOvTJClrT(k@$uGx%HZc;&n#=UA;1C!4h69_@ zRrQDE`1%PC_2laJT(lD~&WpO;!aMTdo5&-xyW--x&-|oHn6Jjt@=N-`fI#7z$J4yO z5WFolPkRlEcm!A@fS+_6I+rk&qB|Jt?#@8O_OB-cg~#8`mxix1gPK*GX@3Zki8KL0 zz}T&>SBIM6eiws|Xt|ns!q2LiCOW*;UAW55?x!|CU;BLO*kY>5IPOs&UXPOxIzGb* zxGDr(ZL}0uKho8`@KZ-!4ThVO8^yuuxLD^`X>wJQt#EANR;Gq^#dhaCTIaCZS?c}JVno{oyP?H=x)fe&Ei>-x;`rLb zR}KcZ;sGuw?D$kD9|B+C!|YmFJrs%Qj^2oDc0w-;-#Hw(?C@i)IV2Ef(P9u5T{20H zbO`6>gTe_t-dZ4UcsWA8lSy$j!P#XjZ)(hUe~l>EOHJB%n)HKy219lHSINwal1O|j zpC}m}!>kj|r>zDDe!=MjvPoZ*ciZeDmrZXDjmyn9wYvJKF`^H3?sZn*_O5P^ zHc_B_RbhEFH_;XG6%?(ylV4ySP2iHpqHa$HORNuaB;vj8)$P~z^q;y|x?@52M zw38Z6p7M4Z;p0z!*Z1yrKny-zL0PY!)H~-_STzQYdyHV_0PNpd0XC@X#2rC!ImO4q zYQbn}sBfvuEJE2&3ip8Lj9|ejJm?{XP*z-t$NO5Ci5!PaKnVcG{)t0!LB)dW&?2nN zq_7|s;C$jTPlC;rkmp&37Id{GMKbLe8M=s}gmw7_7j2nyyW$btB<0nTCgkiCQC4YQI^5ag@;#r6 zk%CQm@71w)UF{oGaDxH~k6qlu)`shWu!W@@ME@FT1#Ok_?OXHwjgJCmFHd&fk{b23 zgQbj2g_C$H7v+hu5!mG(oErkQv!&&C&AyZwe9okw^KyeCj*j@zMusu+e-@O#F4x5l zu*YZpsGe-Sh5~9ikB%9{b{6(VUbsy8F9PX1@RY#GWB z29P)dh$S6IQB}>xBpnrA&+rKmIgS#m8qI{JbhS%an{!MzsTk8$5%V}m&yJ3y*C}b= zdJ8FKRcMrOGuAoV{wT!OLmgor+ATKM|9bI-F7!|$jYZ=fzfw1zg(ao!^@C$*cEC0Yl!$^ncKL$-XUUruTA06y ziVJ^XwLTa3J>(Nd2xO@1K)8^eBf;viS5`-riDsN1BrFW)0}NmO*6Yu}Cf61D&Bd;( zY+x?NorrBZuf6`g3qj@=NUZdiXd&2I=`57#9a!1IYMMAB=)neY2Fp9CmAA2%&@vpM zfLSwq1}$8Z29UxMH%WZ+CmL(DxXDXN(Ww|me8E_0H7bcsWv<%N^UDZ`xCCBmcUm3q zm!7)aVRnfI6_>G@>bBpPP7{l|o_cYbq{nl<7&j7T43H!^IU)3COc_J{b)7bWmmh{4 zrg6G4R|X-BxjYX}j<{uSg3byTbpDWOxI7Hh^aCsYrtqCVm6H!PN zAxCk5~-YyB5B0m=njdOTdzG70|)0EAuO?K1qOPm$NbP` zf{m@ql1meef9+U4J-1&nIAZW6a?=xy0iDX6a-R;R&1resNg`g>C#d~$lT6CCF|QYE3eal>CFpN0sZKlzaVjiqZNSqKvY zMwT~p-G$B;QY&8^|FiastUb^}9dy{^!cxMwJNa8wbd;&+0Q>FEYAEwp-Z@t^go+8t~>ZV3*T@&F{{5hh^QeZpB3d8AHbZG?hf)K%j6` z!|sWRXEZ~Fm&_ZRL+qDIr=>F8 z>Doj21!O+PA|X}fK8s>??X+gwbri}I&)S`r#rX>r(V9@p@GKQNg0{X$_Ko(YQ}IJn-3C$Qd!^jW8Kp(vZ+CWH|KJQ7_z!xMgr8}ChbZ&n zn!5;_8?;n9Q1=P5&MGwb-u>Ym&PSx&N1$pKMw$%B_|snm2}E1OC3K)cQ+*`2KW*qr zwo)EH>9EuZF|{b0L4*sb6koR8Qx-oKgEwj8PCajUKj)Q(>3TdvO!VK6j1G+@?p5!# zm$pbG%PSLZISxYflNokMVD>f+9$*OUL&78T8Ou5L1T?i6gdcMIq~tt&!}CMT!QnkP z0*Y$s)|+dz$#t=v(nh)~)!i86L_JeTDvFX8M83UC8GO3TkPuV)A2I&60K~ zAQfEGk-jdf$|@{O0uy_UTArm}N$MG-6+@*Q5s@V9&HUB^m4U2nH#(Niarp^m5QdV{ zv;Ad<=;N!F^NL|x5~BtS(a#?eNixK#EWHIB>jJsZS8GBls_y5FQ@UbsADBMZ_J&@Y z;{IxOin_ZU7#vF2mk(}b10S=ul)g>>4mNLJZe&h42&^}dt2Ogz636oP+zb>a5$2uv z57|A;nk~gET#VC%%9`C_Sa3q|Z4c5Ly`%!!0llYx5Jv=9E8mG!ObwbzBPiWMh-VG= zr6ss_E?G;{qo|N0FRO^Rp(BN%4)?R_si+c70@6;+F@>jh{hPOSHANdV5Hh8>%9Izv zNjJPgg4B?pr^YaU!$!H^BKsHrV+a}Ph$tk{ zsu|8e<3Isk4|I0c)%!85G-6;5zd1UY9Ow3JDxynLoaz8~p`Uw|p(5%*{>M~Ui`NacU0p@^* z(OvuV8|x*+Rj!VMe<&XLxt$YWqbpF*cA&NUd z)+6Z?gdR89pMgQ{350X5hg(xOXBWO||5wn&rFLdNFpS8BmmKmerTTga$26w&y|c5Q zFTuWI(Pdn@lD9^NE02(aFY`R~qw0!s`PR>0It-8YwJMGu@!n zt{<8)kloy_6}vM#b1VaGQiXJ0s&^Xl*oR404ezG~>HgPVB$uq7yZ5vL?W!yBhl@BTE4YM8U|c{(2p2Cn848?4u;B}}1;TGn6!pmrx z$ensFvUYLaz^q+(;r8H?eIlFoBZ=pv*EKCOWhdKhZWZYnwT!DH?fa7QW;*`@@f+s& zb+oG84r8Y;tpy?-ZbVE#M|3c+|1A8{iz{ia6Up>9Im~29$>OZxalDH4z>lwz+NLqa`OWg32iu|!S9@3XS zs6AcyL)z=!8}PSnwmVEfOJf~4mWBTQ{^5I7neCtj*`bPn+ES$@D4vyVYE_V}a1g-& z2Ua`rW?)wnZBR;Aq&>E`zzvvV=QW@+PHEc4Mqpq6&8Z{fWvh+VyR?bFxNG8p-T)fp z>=1aDes8ok0ihU_)HcIE#lU;Bw(RRW2ewJm)3V}e7f_|PV8KTFi<^a`TA(x0m0;#t`-p?G*s+!vjsBzWzmZrw(?<-d)+D%2C2tHs?3H0@j-T2P>G_&?2=+ zk|m+yb}gixo%{SI{uWHHH|xi6auFstMs0Leg45a+mB!mk(sZOf^=?d0@*J!jD4Fhe zBQi!N?h^Uyk+Azumm8^;rl+MPj*}OcS1%Q=-oCIE+4t;a&^nj6+|>3W+qXw4t4NdH z9=dUyk*K0Pc>`4xJsiMNdri(i8p#ohZs z_7~Q)}S#?Y4+lUBrAUq?Mgd zAk9ug6%jZti=i4x$2$4KUc4yq@4Nd>$x=>~+LJtNPAQpxS}8st5UBjJ;->^HCzW65 zLHccQD{|IsWW*vn>|(BK?S|zbpOI0@qy^P1|2MsjpT+7%G%#JB?#L)}VUL_pAQ>ot zq|Kstm1RLe$21t|Fx+c(c28el2HusQEuMvb8z_80ZnV;7 zUSco5P^-;C&XJa1W#Kr}Cp&b8Z;|qz@KBCHptZ%S%v1Ng;9WBj5s}dG$%&WL{M>c{ z(Hy)X!tqVC#w$a;5z^|3_sk83_<=EZ~Ec%)$5U&hDX4c zwjh5XtyY!b4|7Pzu@s`Ms#5|;V;EX}`fgFu6Z^#NqDOT4RBeAbtHs;w#pwKWUXM^xSq))HNT_mUn%km%E_%Mw-3EFhsQFR+J6@i6^9}O`;Ln2! zs}T^B2iLa`w?_)@Zu`(_f~c6tz#c@Q;Ij^v)Ylovf2zXacX2`T&>^rmqs}L=yw(a| zymaWfCqzWHhy-`pNWW2Vw=7vm^L7aF#NZjjZ{^>7@3DPY9$*1akDNiwbYbpX^GDAG zEx);S9u_o>Ngi~P8scK-`^Y_41&EYO$NWt+CnF9*A`bZz>@CO>Z=-}A22LF0G3SNACUV{;g%W%w2`&{o2ecI-+5e62Mc>L}4U)(KBd+)~tc-h^Q?Yk(DwWOT zJ9M3$Z3z>vhs$)JLm@BI$EOj^dqb=HFZLAB-AyH3t9Z0d6Ml0T`KwXP`@Z{|Fm=KTVHXzA@Wi;`DJx5Y=e1p0Nih)ecudhglrGhOMiI{-<-c+@bJ71A)ZFDA zV3E-6sSt$XSYc*~dVKpLlwD5*@*xM7Zr7-%L3g;esd3*C^V21M;9;=)cxkl>d1Swx z-jA^5Yp@#Z8t03>MMDnZmA4#Qpx_{7u zo;)s7?@0i44NQ8V&xW8TDK2&TA}xwFrl#IO#;jpfR$ci#%lJ0Q)UZyp;6iA zonq%G+9;Ja*IryBz%glA?7WC5rUZD!2%K>0=TTvV)kd7&;4>Q{3SDOmGJaa%$(bNQ zorT{-WGrgE9azdWiDb8Xw!d^Vg2{4ML}6)SBDos4DNedsSJgVt#eC+0&Vk`nAE5PL z_stP}74V^A-EHck!N0rS>vLA!3g2E^e3E)kW5{$@9%hae8QS!k#Bc%vcJ-6iMT9g$+^?QlI$^Ww36t(K7bs$|Nrp z;2>a80sXqoOvZLjQghP8wuex{R|LsLRi-3HqwMk7x47|Vabvq{a4CHA{fqftk$^x^ zS&1)xktG`K*QFE4!DXWzf+%z}z2r*4&(0vfe+eq))EtzZhFo*^qf^tJUL75*>LPCL zu);Z^2o@_cqNTq$ro|qi*y{AB*Zlr~g7VR?YrhhSqkZR4kfM$6dPtf6)&#KH+iRU2 zn93{*3p|`}S+*x@Ex&oA3Oop>zmN)FymE?05K-W2U}X1~%pdu^1+-}f{3?Ia=&Fli z6_@Gg3N9Kc@4n!uS_)IA%-DSOor-aYzTC>_rsgdSP@uV*h5>)MG7Fx{H=rRIrY|f8>ock^{QdLPkVaYmqqqc-c4O1Tkzgx=Nqj*difzOgr{!#cUXMKZ3;Vn6oDt2JYHDyTL zU7U5^v8M--=dXeD4OCygV>v82? zhdPPssWPiaj@64?o;7NG!mm>t@f@FC_zEDeyt?e#YQWp7-jX2sRpBiS2O~SU}!H#pZKNT2Ot9N zXYC;JWqT7{lQNBt#kR*_{9DUQql7HgE1sWSHs6)CK+ke%b;-%e<31L7c-gV3iAqGc zJ^)kjjvzcZKRw;N7M?}L5=M%);Q|d7#Rm{HIUcYqvg~NK{db8hU4%qT8F<3NzSq{| zz3O~LwL~}q20PY0>_)kgnID*Iacyu3`hBMw+Y`oNqgX*DrnWEld$pzxIav)gaZR35 zZeU-vz&jKY!NB1sxSFlwUppHObJEk?T!VK(fs^*Yvy~Xfrf@g>N~%Cs@r$f=+a_ zzry`DjA2xbS8o;(UDxM56-g~O(-kfE3dNrsY$eL+_H)q2voq#e0Iw=hJNmT%9xH%zMnHVgk93Aq#rIaQ`1HC%oKY6)%cn7RXb>Sw4Hxd|j8u9}# zt2BdWeLVNm3-ZG(7+HJsNrZP$Fv+gRg$28VHs{Ff2qnn81lRi8nGYYInhP#3_5J1 z$BM)nHTw&(&wECI$7mu|39mr^^B;(lT>4_vaw*Gt_mKgWIv^n;RqY zcHg&8i@tc_+$V>08wPW>H8Iogf9uXfdf?SQsixW_aW^2iKov@jdcY`J;20gXs$iU=p#I?6W*xFB`Lvh{b@VIm%D8=`J!MaTv`3 z!-xG@?QPOpK|&K=@81*OfO+O-0!w>z*>juasxBtola!QpKx{e z!zHr#Dhn*T{9+n+RMhL$kx|q5xh5TnRID}(^Dn$$q+HZ5>HDb|KqCVBX|U=rF$K_x zQwNpf)n=Lqrfj6#^zn0QBdNWwgO(Rs#CLWM?@1g&cjwj-xUUasO0mT5AXB{Cbu${nG``WY~Sl0z0olm&FeVm$mb3rET z<*avy{1B6X@pRln#+6TNe*ttcQui0drxiy>7=>d`2yXC5fNnYiJSRo2Yve7-S}d)ixN` zHolCyaWFe%o6m~T+}zZ7kRd?i(b{HzUow4+ff1)|XRUE|k4tU4xAvyi=SU=s&tGYJ z5D~>bJb_TA>(q%>57?H^c?STYV58XFh>>58WZ}^)H_y%RHC+37V$&H+)>q{uHrs~~K*;L+{rwCym@D zAAiWZ1VkX|kw342RiipXz@bqNLDiZbdF*WQaef6BPv8l&Zp~ z1?!RJ*cOF^-SP)BVhZS)p$;WCT2gjD=9bzN)K1b-za(-o1Q?2_Aa-@d8SRg?HtYyfK_is(2jjmDrl-*HQvcq zr>TYxDnQPc@u9kKRK|C6i5oO2Pv8@uSZPH1(yIF%e+Bi(AN%4*Q4B<9u@S~#l$K_s zHA^57DzHvl_;+*?w_Az~-1OhHmk1xuY+vds+rB;M`1+am`Y<$D(#s5l1y9>6t{yqP za*Z5mhlimFL&yuM%GVA$HL`*mYVue8lNLv{;HjEX%~KT^3;U-ZnBo!%?-EeXUwaS zAg$C(AIW6X3BngR1q3(<{~GR;pW`n4bCZ)2D|>5TqMuQXK4tX|HLF`m*ZDnP-Q836 zxp=Ovr|%MgG3&BAS}#mry}0xloZ#tGVR-0Ii_eG#u!C;g#dvT!P)?ga(jH!(*-YnT z0?i=z;X>>4mu?qyaq0%q1&nlSrA%uvf+cN+oDsVe-xeT#&+W>h^e1ie%$O8&YGdm1 zj#dH;oSV>}t7NQydWF}FlExCvQ}N^b3)3?<8ujXMIZv=mmXl4W%LklCIDbvTL@1-2 znaVlla$W5{@GB}}PVokLT{^uHdQrMJ(_>`{fXb`TLYTTx}M>B`C~^Ja4UoX24$sQ+>e z=Lj&nIf{64ocR64Q4&Rn4(_H(8IsLyN!tRH_tFlWkgmKkj=6>#$HO`{YC5c@2H{L9 zStVNVO4ZU)k35|L%Tv)~)f1g6#__L8n@kOrlp0H7VmhN799YPg8AZHSPW7|1iJidW zenReR`N^u*fAMJ`T}uo_PFVInTrtSwz>T^GOpLx_Q1kIw_t+Zh)y2boApxw65^bnT zs9gnU78)YXo+HMAX+?p?baRZ1<_vUelaRd+OPEIH#!l>}7e5fiP)ZzlathMMrlxNi zN8)^uO7{0lL|<#HCe;nlG522Y{gh^E-V!QHd>OUWQwTwi(MM(LEnF(g8uz=b9rG6F zb2%h6Yirty@JAb`8>q}ny8(ZS34c@o;%>bsS9KhRXWnt^AMP`h++Uj()^C#_I>R-{ zA?l9gnz9QL;e3BAN6Ak*PEjWDS-f=R8v&k$M~gv^9Mt6$vVWRJS2Jw-NtxO1?h|lb z=Y+kh<&79y-J*0y0IQm7PQaW`^nYy*q>oO&V2Pt#Y%P~x-&1K!7`Ad+O&?mBwtkFF zn2aakbzo|oouLH#116V4S6}W7$zXD-RdW#O@XxlFu`qSCRLG?eJzlzK9f%&`HEgo< zy%9eN=^DH`KbTj|uCqPXDJ*CIp?e3Vo`MN@!}}N8;ZZU;&i?*<$ZlH|QWzpADj9n# zoX3h+acq$Sk|R_%8h_avMPb zEQLZcFuy6+=dc+ZWb~BXMSrySvUDlaqt`pC%tDDoHz84N=WsrPTl!eNCCAdO=EC^q zCCc9U(j~-?>0;;Lz-xG6$Q}wU-o2E^=dMc$dZh1OMdiM*t-`d;&4=VcSGW}2uXs41 zl7ZsEXDD^XGObc}qCG*V6P@a3mA>?d3a85<;3C7>QGsc)YwWYVrM-H&gZ*ry`F6^_jBW|D$Hl~7F{u)!bFeMLLmS#w7|Pa{{HU+ zK~+gde;@R_AYtn1es60G3Zw=71q-O(?ZFm+X3c`rho zTdf84w?c+vWMt^N2uq0GuJV}NAC90jFw)KsK!nA*_!B%~1(K?&oNs@^rr#CqbZtHn zip#t6K$JAtZW>zDjLieDNbC^sO5l_&d0D=Gw)`MZ~-IJYae#<1oGt9 z2+V9wfq@u=VZYrtuNN0s+lCb@-J+(d%;{Ok#<*)5e&zQTsO!~?EN6)p3M*xGm!OUe zEcKr9`&wS59pdBS7_y#*EniV**aEXSPjVbfprsn&e5 zTg;9#egWdlXpeAA_v|OOZyeNG&u2A0iQ3`J2CAG1MDFT0h6UL2@6MQg_j1+UReIz3 zC*(qDuMmM1T6?wp%GB6Cx??k5l1Av?y2&w!`SLIL4X69-262Ly zFBH>BOC2q=jMP1xZ-X)I5&FO&-iqSH^mLzAQ&WwI=hC-BJSlV$ci4tapXq61joRG; zXEw9g_T>6;5uSKZYkBdm8Wjuuj9a)b#ZZSk=E1o)A#nCUF09Qlk6)oyoEAuFrOm z?odVobdi>tTYc%%?(4hGE@~~iv()QuGqdWA7KZFisDp!oRe=s$*b_jY8<8c>j+c%9 zkA_`?gr`N~F#}pp2wuelM%LE-BZlqoxGdK23D@W=zH)N8y+h>TsxLl8jUcTmdK18t zF|`Bj+oGo7Uuk3(aidMG0><6j8y)neuIyvukF!cY`vByma?wGY6Or~VueYa zceFvf$$enQQI|(uD_{Z>ZaH{>K&$*1cDVU%GzYfm^{6rqoNlyRu74DF(;pgrKZX>K z$*O7cI~4*9p@i5rzw1N$7x`fG^5jv2t-#E$yl|<3Qtf7*p03WKgzcNTMjw(2uKKr% zhTjNn$~cV=<}$dguXaRr2{~fWPm1)7-)%0A8t+F(DK-4G7Pbe=5a(?@yB~A<@xlyD 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 z z#Sin+uW2oTG6U%~1gUyoClqiU74f>$;()bRBjpJ|V08}*;{S{~(0}};_`vup3eX02 zbB%s$A1S@V3kKYtbLYkp?WWT4EJ%=Hzly2!v<`9R4o$bNh`RcB+;}X0xdQaRu!Swh zEJB+PlM){u-N(A&WPC4K5pQD-ZvqU}AJVt8iFmF1bhtM0V?F&NX^mgg@Y9RQGRJV0kEL!@~|XvlgCgI5Aoqu zjB_NwOV5B1kX6JxXeEyAEh}Z1I{S-5L7PTfmz9$#Wjx&pm*w@|z5v~k%>lpfs1nMT z6wjWwm*Vkg;kwB#T z0Q;uHrKJr%+ltR(R>$gZOZ9;OdZDRlUA!Yy1ws5n=!qecAK9w=k!s-b@XgvhoH{ z$!$Am#+q%`aCZ8fvm7__${*x!(zo_(-+ZfRoBaCc;Y<$O>y{mMaoAXP=d$j$<#O6z z+v;9Pmaq0UOR~z_$TMZ>t(Lxzb( Date: Sat, 28 Sep 2024 19:43:13 +0200 Subject: [PATCH 04/29] feat: rewrite and complete the migration guide from custom arch (#725) --- config/docusaurus/routes.js | 18 +- .../current/get-started/overview.mdx | 2 +- .../current/guides/index.mdx | 4 +- .../current/guides/migration/from-custom.md | 313 ++++ .../current/guides/migration/from-legacy.mdx | 120 -- .../current/get-started/overview.mdx | 2 +- .../current/get-started/overview.mdx | 2 +- .../current/guides/index.mdx | 4 +- .../current/guides/migration/from-custom.md | 311 ++++ .../current/guides/migration/from-legacy.mdx | 121 -- package.json | 40 +- pnpm-lock.yaml | 1333 ++++++++++------- src/app/theme.scss | 19 + static/img/approaches.png | Bin 129024 -> 0 bytes 14 files changed, 1458 insertions(+), 831 deletions(-) create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md delete mode 100644 i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx create mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md delete mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx delete mode 100644 static/img/approaches.png diff --git a/config/docusaurus/routes.js b/config/docusaurus/routes.js index 9051a065ec..6b06359c86 100644 --- a/config/docusaurus/routes.js +++ b/config/docusaurus/routes.js @@ -10,7 +10,7 @@ const SECTIONS = { }, MIGRATION: { shortPath: "/docs/guides/migration", - fullPath: "/docs/guides/migration/from-legacy", + fullPath: "/docs/guides/migration/from-custom", }, }; @@ -249,7 +249,7 @@ const LEGACY_ROUTES = [ { title: "Migration from Legacy", from: "/docs/guides/migration-from-legacy", - to: "/docs/guides/migration/from-legacy", + to: "/docs/guides/migration/from-custom", }, ], }, @@ -264,6 +264,18 @@ const LEGACY_ROUTES = [ }, ], }, + { + group: "Rename 'legacy' to 'custom'", + details: + "'Legacy' is derogatory, we don't get to call people's projects legacy", + children: [ + { + title: "Rename 'legacy' to custom", + from: "/docs/guides/migration/from-legacy", + to: "/docs/guides/migration/from-custom", + }, + ], + }, ]; // @returns { from, to }[] @@ -314,7 +326,7 @@ const _TOTAL_ROUTES = [ "/docs/guides/examples/theme", "/docs/guides/examples/types", "/docs/guides/examples/white-labels", - "/docs/guides/migration/from-legacy", + "/docs/guides/migration/from-custom", "/docs/guides/migration/from-v1", "/docs/guides/tech/with-nextjs", "/docs/", diff --git a/i18n/en/docusaurus-plugin-content-docs/current/get-started/overview.mdx b/i18n/en/docusaurus-plugin-content-docs/current/get-started/overview.mdx index a35f521066..8231526cf9 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/get-started/overview.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/get-started/overview.mdx @@ -131,7 +131,7 @@ It's advised to refrain from adding new large entities while refactoring or refa [tutorial]: /docs/get-started/tutorial [examples]: /examples -[migration]: /docs/guides/migration/from-legacy +[migration]: /docs/guides/migration/from-custom [ext-steiger]: https://github.com/feature-sliced/steiger [ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools [ext-telegram]: https://t.me/feature_sliced diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/index.mdx b/i18n/en/docusaurus-plugin-content-docs/current/guides/index.mdx index 17d7beeeca..319ebbf93f 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/index.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/index.mdx @@ -25,10 +25,10 @@ import { ToolOutlined, ImportOutlined, BugOutlined, FunctionOutlined } from "@an /> + 📁 src +
    +
  • +
    + 📁 actions +
      +
    • 📁 product
    • +
    • 📁 order
    • +
    +
    +
  • +
  • 📁 api
  • +
  • 📁 components
  • +
  • 📁 containers
  • +
  • 📁 constants
  • +
  • 📁 i18n
  • +
  • 📁 modules
  • +
  • 📁 helpers
  • +
  • +
    + 📁 routes +
      +
    • 📁 products.jsx
    • +
    • 📄 products.[id].jsx
    • +
    +
    +
  • +
  • 📁 utils
  • +
  • 📁 reducers
  • +
  • 📁 selectors
  • +
  • 📁 styles
  • +
  • 📄 App.jsx
  • +
  • 📄 index.js
  • +
+ + +## Before you start {#before-you-start} + +The most important question to ask your team when considering to switch to Feature-Sliced Design is — _do you really need it?_ We love Feature-Sliced Design, but even we recognize that some projects are perfectly fine without it. + +Here are some reasons to consider making the switch: + +1. New team members are complaining that it's hard to get to a productive level +2. Making modifications to one part of the code **often** causes another unrelated part to break +3. Adding new functionality is difficult due to the sheer amount of things you need to think about + +**Avoid switching to FSD against the will of your teammates**, even if you are the lead. +First, convince your teammates that the benefits outweigh the cost of migration and the cost of learning a new architecture instead of the established one. + +Also keep in mind that any kind of architectural changes are not immediately observable to the management. Make sure they are on board with the switch before starting and explain to them why it might benefit the project. + +:::tip + +If you need help convincing the project manager that FSD is beneficial, consider some of these points: +1. Migration to FSD can happen incrementally, so it will not halt the development of new features +2. A good architecture can significantly decrease the time that a new developer needs to get productive +3. FSD is a documented architecture, so the team doesn't have to continuously spend time on maintaining their own documentation + +::: + +--- + +If you made the decision to start migrating, then the first thing you want to do is to set up an alias for `📁 src`. It will be helpful later to refer to top-level folders. We will consider `@` as an alias for `./src` for the rest of this guide. + +## Step 1. Divide the code by pages {#divide-code-by-pages} + +Most custom architectures already have a division by pages, however small or large in logic. If you already have `📁 pages`, you may skip this step. + +If you only have `📁 routes`, create `📁 pages` and try to move as much component code from `📁 routes` as possible. Ideally, you would have a tiny route and a larger page. As you're moving code, create a folder for each page and add an index file: + +:::note + +For now, it's okay if your pages reference each other. You can tackle that later, but for now, focus on establishing a prominent division by pages. + +::: + +Route file: + +```js title="src/routes/products.[id].js" +export { ProductPage as default } from "@/pages/product" +``` + +Page index file: + +```js title="src/pages/product/index.js" +export { ProductPage } from "./ProductPage.jsx" +``` + +Page component file: + +```jsx title="src/pages/product/ProductPage.jsx" +export function ProductPage(props) { + return
; +} +``` + +## Step 2. Separate everything else from the pages {#separate-everything-else-from-pages} + +Create a folder `📁 src/shared` and move everything that doesn't import from `📁 pages` or `📁 routes` there. Create a folder `📁 src/app` and move everything that does import the pages or routes there, including the routes themselves. + +Remember that the Shared layer doesn't have slices, so it's fine if segments import from each other. + +You should end up with a file structure like this: + +
+ 📁 src +
    +
  • +
    + 📁 app +
      +
    • +
      + 📁 routes +
        +
      • 📄 products.jsx
      • +
      • 📄 products.[id].jsx
      • +
      +
      +
    • +
    • 📄 App.jsx
    • +
    • 📄 index.js
    • +
    +
    +
  • +
  • +
    + 📁 pages +
      +
    • +
      + 📁 product +
        +
      • +
        + 📁 ui +
          +
        • 📄 ProductPage.jsx
        • +
        +
        +
      • +
      • 📄 index.js
      • +
      +
      +
    • +
    • 📁 catalog
    • +
    +
    +
  • +
  • +
    + 📁 shared +
      +
    • 📁 actions
    • +
    • 📁 api
    • +
    • 📁 components
    • +
    • 📁 containers
    • +
    • 📁 constants
    • +
    • 📁 i18n
    • +
    • 📁 modules
    • +
    • 📁 helpers
    • +
    • 📁 utils
    • +
    • 📁 reducers
    • +
    • 📁 selectors
    • +
    • 📁 styles
    • +
    +
    +
  • +
+
+ +## Step 3. Tackle cross-imports between pages {#tackle-cross-imports-between-pages} + + + + +Find all instances where one page is importing from the other and do one of the two things: + +1. Copy-paste the imported code into the depending page to remove the dependency +2. Move the code to a proper segment in Shared: + - if it's a part of the UI kit, move it to `📁 shared/ui`; + - if it's a configuration constant, move it to `📁 shared/config`; + - if it's a backend interaction, move it to `📁 shared/api`. + +:::note + +**Copy-pasting isn't architecturally wrong**, in fact, sometimes it may be more correct to duplicate than to abstract into a new reusable module. The reason is that sometimes the shared parts of pages start drifting apart, and you don't want dependencies getting in your way in these cases. + +However, there is still sense in the DRY ("don't repeat yourself") principle, so make sure you're not copy-pasting business logic. Otherwise you will need to remember to fix bugs in several places at once. + +::: + +## Step 4. Unpack the Shared layer {#unpack-shared-layer} + +You might have a lot of stuff in the Shared layer on this step, and you generally want to avoid that. The reason is that the Shared layer may be a dependency for any other layer in your codebase, so making changes to that code is automatically more prone to unintended consequences. + +Find all the objects that are only used on one page and move it to the slice of that page. And yes, _that applies to actions, reducers, and selectors, too_. There is no benefit in grouping all actions together, but there is benefit in colocating relevant actions close to their usage. + +You should end up with a file structure like this: + +
+ 📁 src +
    +
  • 📁 app (unchanged)
  • +
  • +
    + 📁 pages +
      +
    • +
      + 📁 product +
        +
      • 📁 actions
      • +
      • 📁 reducers
      • +
      • 📁 selectors
      • +
      • +
        + 📁 ui +
          +
        • 📄 Component.jsx
        • +
        • 📄 Container.jsx
        • +
        • 📄 ProductPage.jsx
        • +
        +
        +
      • +
      • 📄 index.js
      • +
      +
      +
    • +
    • 📁 catalog
    • +
    +
    +
  • +
  • +
    + 📁 shared (only objects that are reused) +
      +
    • 📁 actions
    • +
    • 📁 api
    • +
    • 📁 components
    • +
    • 📁 containers
    • +
    • 📁 constants
    • +
    • 📁 i18n
    • +
    • 📁 modules
    • +
    • 📁 helpers
    • +
    • 📁 utils
    • +
    • 📁 reducers
    • +
    • 📁 selectors
    • +
    • 📁 styles
    • +
    +
    +
  • +
+
+ +## Step 5. Organize code by technical purpose {#organize-by-technical-purpose} + +In FSD, division by technical purpose is done with _segments_. There are a few common ones: + +- `ui` — everything related to UI display: UI components, date formatters, styles, etc. +- `api` — backend interactions: request functions, data types, mappers, etc. +- `model` — the data model: schemas, interfaces, stores, and business logic. +- `lib` — library code that other modules on this slice need. +- `config` — configuration files and feature flags. + +You can create your own segments, too, if you need. Make sure not to create segments that group code by what it is, like `components`, `actions`, `types`, `utils`. Instead, group the code by what it's for. + +Reorganize your pages to separate code by segments. You should already have a `ui` segment, now it's time to create other segments, like `model` for your actions, reducers, and selectors, or `api` for your thunks and mutations. + +Also reorganize the Shared layer to remove these folders: +- `📁 components`, `📁 containers` — most of it should become `📁 shared/ui`; +- `📁 helpers`, `📁 utils` — if there are some reused helpers left, group them together by function, like dates or type conversions, and move theses groups to `📁 shared/lib`; +- `📁 constants` — again, group by function and move to `📁 shared/config`. + +## Optional steps {#optional-steps} + +### Step 6. Form entities/features from Redux slices that are used on several pages {#form-entities-features-from-redux} + +Usually, these reused Redux slices will describe something relevant to the business, for example, products or users, so these can be moved to the Entities layer, one entity per one folder. If the Redux slice is related to an action that your users want to do in your app, like comments, then you can move it to the Features layer. + +Entities and features are meant to be independent from each other. If your business domain contains inherent connections between entities, refer to the [guide on business entities][business-entities-cross-relations] for advice on how to organize these connections. + +The API functions related to these slices can stay in `📁 shared/api`. + +### Step 7. Refactor your modules {#refactor-your-modules} + +The `📁 modules` folder is commonly used for business logic, so it's already pretty similar in nature to the Features layer from FSD. Some modules might also be describe large chunks of the UI, like an app header. In that case, you should migrate them to the Widgets layer. + +### Step 8. Form a clean UI foundation in `shared/ui` {#form-clean-ui-foundation} + +`📁 shared/ui` should ideally contain a set of UI elements that don't have any business logic encoded in them. They should also be highly reusable. + +Refactor the UI components that used to be in `📁 components` and `📁 containers` to separate out the business logic. Move that business logic to the higher layers. If it's not used in too many places, you could even consider copy-pasting. + +## See also {#see-also} + +- [(Talk in Russian) Ilya Klimov — Крысиные бега бесконечного рефакторинга: как не дать техническому долгу убить мотивацию и продукт](https://youtu.be/aOiJ3k2UvO4) + +[ext-steiger]: https://github.com/feature-sliced/steiger +[business-entities-cross-relations]: /docs/guides/examples/types#business-entities-and-their-cross-references diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx deleted file mode 100644 index 67ee065c12..0000000000 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx +++ /dev/null @@ -1,120 +0,0 @@ ---- -sidebar_position: 3 -sidebar_class_name: sidebar-item--wip ---- - -import WIP from '@site/src/shared/ui/wip/tmpl.mdx' - -# Migration from legacy - - - -> The article aggregates the experience of several companies and projects on moving to Feature-Sliced Design with different initial conditions - -## Why? - -> How much does the move need? "Death by a thousand cuts" and those debt. What is missing? How can the methodology help? - -> See the talk of [Ilya Klimov about the need and procedure for refactoring](http://youtu.be/aOiJ3k2UvO4) - -![approaches-themed-bordered](/img/approaches.png) - -## What's the plan? - -### 1. Unification of the code base - -```diff -- ├── products/ -- | ├── components/ -- | ├── containers/ -- | ├── store/ -- | ├── styles/ -- ├── checkout/ -- | ├── components/ -- | ├── containers/ -- | ├── helpers/ -- | ├── styles/ -+ └── src/ - ├── actions/ - ├── api/ -+ ├── components/ -+ ├── containers/ - ├── constants/ - ├── epics/ -+ ├── i18n/ - ├── modules/ -+ ├── helpers/ -+ ├── pages/ -- ├── routes/ -- ├── utils/ - ├── reducers/ -- ├── redux/ - ├── selectors/ -+ ├── store -+ ├── styles/ - ├── App.jsx - └── index.jsx -``` - -### 2. Putting together the destructive decoupled - -```diff - └── src/ -- ├── actions/ - ├── api/ -- ├── components/ -- ├── containers/ -- ├── constants/ -- ├── epics/ -+ ├── entities/{...} -+ | ├── ui -+ | ├── model/{actions, selectors, ...} -+ | ├── lib - ├── i18n/ - | # We can temporarily put the remaining segments here -+ ├── modules/{helpers, constants} -- ├── helpers/ - ├── pages/ -- ├── reducers/ -- ├── selectors/ -- ├── store/ - ├── styles/ - ├── App.jsx - └── index.jsx -``` - -### 3. Allocate scopes of responsibility - -```diff - └── src/ -- ├── api/ -+ ├── app/ -+ | ├── index.jsx -+ | ├── style.css - ├── pages/ -+ ├── features/ -+ | ├── add-to-cart/{ui, model, lib} -+ | ├── choose-delivery/{ui, model, lib} -+ ├── entities/{...} -+ | ├── delivery/{ui, model, lib} -+ | ├── cart/{ui, model, lib} -+ | ├── product/{ui, model, lib} -+ ├── shared/ -+ | ├── api/ -+ | ├── lib/ # helpers -+ | | ├── i18n/ -+ | ├── config/ # constants -- ├── i18n/ -- ├── modules/{helpers, constants} - └── index.jsx -``` - -### 4. Final ? - -> About the remaining problems and how much it is worth eliminating them - -## See also - -- [(Talk) Ilya Klimov-The Rat Race of endless refactoring: how not to let technical debt kill motivation and product](https://youtu.be/aOiJ3k2UvO4) -- [(Talk) Ilya Azin - Architecture of Frontend projects](https://youtu.be/SnzPAr_FJ7w) - - There is also discussed approaches for architecture and costs of refactoring \ No newline at end of file diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/get-started/overview.mdx b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/overview.mdx index 75d7f69a32..88f619bb93 100644 --- a/i18n/kr/docusaurus-plugin-content-docs/current/get-started/overview.mdx +++ b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/overview.mdx @@ -130,7 +130,7 @@ FSD로 마이그레이션하고자 하는 기존 코드베이스가 있다면, [tutorial]: /docs/get-started/tutorial [examples]: /examples -[migration]: /docs/guides/migration/from-legacy +[migration]: /docs/guides/migration/from-custom [ext-steiger]: https://github.com/feature-sliced/steiger [ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools [ext-telegram]: https://t.me/feature_sliced diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/overview.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/overview.mdx index 776f75a0b1..84e7ba0ca8 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/overview.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/overview.mdx @@ -131,7 +131,7 @@ _\* — эти слои, App и Shared, в отличие от других сл [tutorial]: /docs/get-started/tutorial [examples]: /examples -[migration]: /docs/guides/migration/from-legacy +[migration]: /docs/guides/migration/from-custom [ext-steiger]: https://github.com/feature-sliced/steiger [ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools [ext-telegram]: https://t.me/feature_sliced diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/index.mdx index 74b124da46..f720736132 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/index.mdx @@ -25,10 +25,10 @@ import { ToolOutlined, ImportOutlined, BugOutlined, FunctionOutlined } from "@an /> + 📁 src +
    +
  • +
    + 📁 actions +
      +
    • 📁 product
    • +
    • 📁 order
    • +
    +
    +
  • +
  • 📁 api
  • +
  • 📁 components
  • +
  • 📁 containers
  • +
  • 📁 constants
  • +
  • 📁 i18n
  • +
  • 📁 modules
  • +
  • 📁 helpers
  • +
  • +
    + 📁 routes +
      +
    • 📁 products.jsx
    • +
    • 📄 products.[id].jsx
    • +
    +
    +
  • +
  • 📁 utils
  • +
  • 📁 reducers
  • +
  • 📁 selectors
  • +
  • 📁 styles
  • +
  • 📄 App.jsx
  • +
  • 📄 index.js
  • +
+ + +## Перед началом {#before-you-start} + +Самый важный вопрос, который нужно задать своей команде при рассмотрении перехода на Feature-Sliced Design, — _действительно ли вам это нужно?_ Мы любим Feature-Sliced Design, но даже мы признаем, что некоторые проекты прекрасно обойдутся и без него. + +Вот несколько причин, по которым стоит рассмотреть переход: + +1. Новые члены команды жалуются, что сложно достичь продуктивного уровня +2. Внесение изменений в одну часть кода **часто** приводит к тому, что ломается другая несвязанная часть +3. Добавление новой функциональности затруднено из-за огромного количества вещей, о которых нужно думать + +**Избегайте перехода на FSD против воли ваших коллег**, даже если вы являетесь тимлидом. +Сначала убедите своих коллег в том, что преимущества перевешивают стоимость миграции и стоимость изучения новой архитектуры вместо установленной. + +Также имейте в виду, что любые изменения в архитектуре незаметны для руководства в моменте. Убедитесь, что они поддерживают переход, прежде чем начинать, и объясните им, как этот переход может быть полезен для проекта. + +:::tip + +Если вам нужна помощь в убеждении менеджера проекта в том, что FSD вам полезен, вот несколько идей: + +1. Миграция на FSD может происходить постепенно, поэтому она не остановит разработку новых функций +2. Хорошая архитектура может значительно сократить время, которое потребуется новым разработчикам для достижения производительности +3. FSD — это документированная архитектура, поэтому команде не нужно постоянно тратить время на поддержание собственной документации + +::: + +--- + +Если вы всё-таки приняли решение начать миграцию, то первое, что вам следует сделать, — настроить алиас для `📁 src`. Это будет полезно позже, чтоб ссылаться на папки верхнего уровня. Далее в тексте мы будем считать `@` псевдонимом для `./src`. + +## Шаг 1. Разделите код по страницам {#divide-code-by-pages} + +Большинство кастомных архитектур уже имеют разделение по страницам, независимо от размера логики. Если у вас уже есть `📁 pages`, вы можете пропустить этот шаг. + +Если у вас есть только `📁 routes`, создайте `📁 pages` и попробуйте переместить как можно больше кода компонентов из `📁 routes`. Идеально, если у вас будет маленький файл роута и больший файл страницы. При перемещении кода создайте папку для каждой страницы и добавьте в нее индекс-файл: + +:::note + +Пока что ваши страницы могут импортировать друг из друга, это нормально. Позже будет отдельный шаг для устранения этих зависимостей, но сейчас сосредоточьтесь на установлении явного разделения по страницам. + +::: + +Файл роута: + +```js title="src/routes/products.[id].js" +export { ProductPage as default } from "@/pages/product" +``` + +Индекс-файл страницы: + +```js title="src/pages/product/index.js" +export { ProductPage } from "./ProductPage.jsx" +``` + +Файл с компонентом страницы: + +```jsx title="src/pages/product/ProductPage.jsx" +export function ProductPage(props) { + return
; +} +``` + +## Шаг 2. Отделите все остальное от страниц {#separate-everything-else-from-pages} + +Создайте папку `📁 src/shared` и переместите туда все, что не импортируется из `📁 pages` или `📁 routes`. Создайте папку `📁 src/app` и переместите туда все, что импортирует страницы или роуты, включая сами роуты. + +Помните, что у слоя Shared нет слайсов, поэтому сегменты могут импортировать друг из друга. + +В итоге у вас должна получиться структура файлов, похожая на эту: + +
+ 📁 src +
    +
  • +
    + 📁 app +
      +
    • +
      + 📁 routes +
        +
      • 📄 products.jsx
      • +
      • 📄 products.[id].jsx
      • +
      +
      +
    • +
    • 📄 App.jsx
    • +
    • 📄 index.js
    • +
    +
    +
  • +
  • +
    + 📁 pages +
      +
    • +
      + 📁 product +
        +
      • +
        + 📁 ui +
          +
        • 📄 ProductPage.jsx
        • +
        +
        +
      • +
      • 📄 index.js
      • +
      +
      +
    • +
    • 📁 catalog
    • +
    +
    +
  • +
  • +
    + 📁 shared +
      +
    • 📁 actions
    • +
    • 📁 api
    • +
    • 📁 components
    • +
    • 📁 containers
    • +
    • 📁 constants
    • +
    • 📁 i18n
    • +
    • 📁 modules
    • +
    • 📁 helpers
    • +
    • 📁 utils
    • +
    • 📁 reducers
    • +
    • 📁 selectors
    • +
    • 📁 styles
    • +
    +
    +
  • +
+
+ +## Шаг 3. Устраните кросс-импорты между страницами {#tackle-cross-imports-between-pages} + +Найдите все случаи, когда одна страница импортирует что-то из другой, и сделайте одно из двух: + +1. Скопируйте код, который импортируется, в зависимую страницу, чтобы убрать зависимость +2. Переместите код в соответствующий сегмент в Shared: + - если это часть UI-кита, переместите в `📁 shared/ui`; + - если это константа конфигурации, переместите в `📁 shared/config`; + - если это взаимодействие с бэкендом, переместите в `📁 shared/api`. + +:::note + +**Копирование само по себе не является архитектурной проблемой**, на самом деле иногда даже правильнее продублировать что-то, чем абстрагировать в новый переиспользуемый модуль. Дело в том, что иногда общие части страниц начинают расходиться, и в этих случаях вам не нужно, чтобы эти зависимости мешались. + +Однако существует смысл в принципе DRY ("don't repeat yourself" — "не повторяйтесь"), поэтому убедитесь, что вы не копируете бизнес-логику. В противном случае вам придется держать в голове, что баги нужно исправлять в нескольких местах одновременно. + +::: + +## Шаг 4. Разберите слой Shared {#unpack-shared-layer} + +На данном этапе у вас может быть много всего в слое Shared, и в целом, следует избегать таких ситуаций. Причина этому в том, что слой Shared может быть зависимостью для любого другого слоя в вашем коде, поэтому внесение изменений в этот код автоматически более чревато непредвиденными последствиями. + +Найдите все объекты, которые используются только на одной странице, и переместите их в слайс этой страницы. И да, _это относится и к экшнам (actions), редьюсерам (reducers) и селекторам (selectors)_. Нет никакой пользы в группировке всех экшнов вместе, но есть польза в том, чтобы поместить актуальные экшны рядом с их местом использования. + +В итоге у вас должна получиться структура файлов, похожая на эту: + +
+ 📁 src +
    +
  • 📁 app (unchanged)
  • +
  • +
    + 📁 pages +
      +
    • +
      + 📁 product +
        +
      • 📁 actions
      • +
      • 📁 reducers
      • +
      • 📁 selectors
      • +
      • +
        + 📁 ui +
          +
        • 📄 Component.jsx
        • +
        • 📄 Container.jsx
        • +
        • 📄 ProductPage.jsx
        • +
        +
        +
      • +
      • 📄 index.js
      • +
      +
      +
    • +
    • 📁 catalog
    • +
    +
    +
  • +
  • +
    + 📁 shared (only objects that are reused) +
      +
    • 📁 actions
    • +
    • 📁 api
    • +
    • 📁 components
    • +
    • 📁 containers
    • +
    • 📁 constants
    • +
    • 📁 i18n
    • +
    • 📁 modules
    • +
    • 📁 helpers
    • +
    • 📁 utils
    • +
    • 📁 reducers
    • +
    • 📁 selectors
    • +
    • 📁 styles
    • +
    +
    +
  • +
+
+ +## Шаг 5. Распределите код по техническому назначению {#organize-by-technical-purpose} + +В FSD разделение по техническому назначению происходит с помощью _сегментов_. Существует несколько часто встречающихся сегментов: + +- `ui` — всё, что связано с отображением интерфейса: компоненты UI, форматирование дат, стили и т. д. +- `api` — взаимодействие с бэкендом: функции запросов, типы данных, мапперы и т. д. +- `model` — модель данных: схемы, интерфейсы, хранилища и бизнес-логика. +- `lib` — библиотечный код, который нужен другим модулям на этом слайсе. +- `config` — файлы конфигурации и фиче-флаги. + +Вы можете создавать свои собственные сегменты, если это необходимо. Убедитесь, что не создаете сегменты, которые группируют код по тому, чем он является, например, `components`, `actions`, `types`, `utils`. Вместо этого группируйте код по тому, для чего он предназначен. + +Перераспределите код ваших страниц по сегментам. У вас уже должен быть сегмент `ui`, теперь пришло время создать другие сегменты, например, `model` для ваших экшнов, редьюсеров и селекторов, или `api` для ваших thunk-ов и мутаций. + +Также перераспределите слой Shared, чтобы удалить следующие папки: +- `📁 components`, `📁 containers` — большинство из их содержимого должно стать `📁 shared/ui`; +- `📁 helpers`, `📁 utils` — если остались какие-то повторно используемые хелперы, сгруппируйте их по назначению, например, даты или преобразования типов, и переместите эти группы в `📁 shared/lib`; +- `📁 constants` — так же сгруппируйте по назначению и переместите в `📁 shared/config`. + +## Шаги по желанию {#optional-steps} + +### Шаг 6. Создайте сущности/фичи ёмкостью из Redux-слайсов, которые используются на нескольких страницах {#form-entities-features-from-redux} + +Обычно эти переиспользуемые Redux-слайсы будут описывать что-то, что имеет отношение к бизнесу, например, продукты или пользователи, поэтому их можно переместить в слой Entities, одна сущность на одну папку. Если Redux-слайс скорее связан с действием, которое ваши пользователи хотят совершить в вашем приложении, например, комментарии, то его можно переместить в слой Features. + +Сущности и фичи должны быть независимы друг от друга. Если ваша бизнес-область содержит встроенные связи между сущностями, обратитесь к [руководству по бизнес-сущностям][business-entities-cross-relations] за советом по организации этих связей. + +API-функции, связанные с этими слайсами, могут остаться в `📁 shared/api`. + +### Шаг 7. Проведите рефакторинг modules {#refactor-your-modules} + +Папка `📁 modules` обычно используется для бизнес-логики, поэтому она уже довольно похожа по своей природе на слой Features из FSD. Некоторые модули могут также описывать большие части пользовательского интерфейса, например, шапку приложения. В этом случае их можно переместить в слой Widgets. + +### Шаг 8. Сформируйте чистый фундамент UI в `shared/ui` {#form-clean-ui-foundation} + +`📁 shared/ui`, в идеале, должен содержать набор UI-элементов, в которых нет бизнес-логики. Они также должны быть очень переиспользуемыми. + +Проведите рефакторинг UI-компонентов, которые раньше находились в `📁 components` и `📁 containers`, чтобы отделить бизнес-логику. Переместите эту бизнес-логику в верхние слои. Если она не используется в слишком многих местах, вы даже можете рассмотреть копирование как вариант. + +## See also {#see-also} + +- [(Доклад) Ilya Klimov — Крысиные бега бесконечного рефакторинга: как не дать техническому долгу убить мотивацию и продукт](https://youtu.be/aOiJ3k2UvO4) + +[ext-steiger]: https://github.com/feature-sliced/steiger +[business-entities-cross-relations]: /docs/guides/examples/types#business-entities-and-their-cross-references diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx deleted file mode 100644 index 7bc5252981..0000000000 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-legacy.mdx +++ /dev/null @@ -1,121 +0,0 @@ ---- -sidebar_position: 3 -sidebar_class_name: sidebar-item--wip ---- - -import WIP from '@site/src/shared/ui/wip/tmpl.mdx' - -# Миграция с legacy - - - -> В статье агрегируется опыт нескольких компаний и проектов по переезду на Feature-Sliced Design с разными изначальными условиями - -## Зачем? {#why} - -> Насколько нужен переезд? "Смерть от тысячи порезов" и тех долг. Чего не хватает? Чем может помочь методология? - -> См. доклад [Илья Климова про необходимость и порядок рефакторинга](https://youtu.be/aOiJ3k2UvO4) - -![approaches-themed-bordered](/img/approaches.png) - -## Какой план? {#whats-the-plan} - -### 1. Унификация кодовой базы {#1-unification-of-the-code-base} - -```diff -- ├── products/ -- | ├── components/ -- | ├── containers/ -- | ├── store/ -- | ├── styles/ -- ├── checkout/ -- | ├── components/ -- | ├── containers/ -- | ├── helpers/ -- | ├── styles/ -+ └── src/ - ├── actions/ - ├── api/ -+ ├── components/ -+ ├── containers/ - ├── constants/ - ├── epics/ -+ ├── i18n/ - ├── modules/ -+ ├── helpers/ -+ ├── pages/ -- ├── routes/ -- ├── utils/ - ├── reducers/ -- ├── redux/ - ├── selectors/ -+ ├── store -+ ├── styles/ - ├── App.jsx - └── index.jsx -``` - - -### 2. Собираем вместе излишне раздробленное {#2-putting-together-the-destructive-decoupled} - -```diff - └── src/ -- ├── actions/ - ├── api/ -- ├── components/ -- ├── containers/ -- ├── constants/ -- ├── epics/ -+ ├── entities/{...} -+ | ├── ui -+ | ├── model/{actions, selectors, ...} -+ | ├── lib - ├── i18n/ - | # Временно можем положить сюда оставшиеся сегменты -+ ├── modules/{helpers, constants} -- ├── helpers/ - ├── pages/ -- ├── reducers/ -- ├── selectors/ -- ├── store/ - ├── styles/ - ├── App.jsx - └── index.jsx -``` - -### 3. Выделяем скоупы ответственности {#3-allocate-scopes-of-responsibility} - -```diff - └── src/ -- ├── api/ -+ ├── app/ -+ | ├── index.jsx -+ | ├── style.css - ├── pages/ -+ ├── features/ -+ | ├── add-to-cart/{ui, model, lib} -+ | ├── choose-delivery/{ui, model, lib} -+ ├── entities/{...} -+ | ├── delivery/{ui, model, lib} -+ | ├── cart/{ui, model, lib} -+ | ├── product/{ui, model, lib} -+ ├── shared/ -+ | ├── api/ -+ | ├── lib/ # helpers -+ | | ├── i18n/ -+ | ├── config/ # constants -- ├── i18n/ -- ├── modules/{helpers, constants} - └── index.jsx -``` - -### 4. Final ? - -> Про оставшиеся проблемы и насколько стоит их устранять - -## См. также {#see-also} - -- [(Доклад) Илья Климов - Крысиные бега бесконечного рефакторинга: как не дать техническому долгу убить мотивацию и продукт](https://youtu.be/aOiJ3k2UvO4) -- [(Доклад) Илья Азин - Архитектура Frontend проектов](https://youtu.be/SnzPAr_FJ7w) - - В докладе в том числе рассмотрены подходы к архитектуре и стоимости рефакторинга \ No newline at end of file diff --git a/package.json b/package.json index aa67f23134..76c6fe73c5 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ "node": ">= 20.0" }, "dependencies": { - "@ant-design/icons": "^5.4.0", - "@docusaurus/core": "^3.5.1", - "@docusaurus/plugin-client-redirects": "^3.5.1", - "@docusaurus/plugin-content-docs": "^3.5.1", - "@docusaurus/plugin-ideal-image": "^3.5.1", - "@docusaurus/preset-classic": "^3.5.1", - "@fontsource-variable/overpass": "^5.0.19", + "@ant-design/icons": "^5.5.1", + "@docusaurus/core": "^3.5.2", + "@docusaurus/plugin-client-redirects": "^3.5.2", + "@docusaurus/plugin-content-docs": "^3.5.2", + "@docusaurus/plugin-ideal-image": "^3.5.2", + "@docusaurus/preset-classic": "^3.5.2", + "@fontsource-variable/overpass": "^5.1.0", "@mdx-js/react": "^3.0.1", "@svgr/webpack": "^8.1.0", "@types/lodash-es": "^4.17.12", @@ -40,16 +40,16 @@ "dotenv": "^16.4.5", "file-loader": "^6.2.0", "lodash-es": "^4.17.21", - "picocolors": "^1.0.1", + "picocolors": "^1.1.0", "plugin-image-zoom": "^1.2.0", - "prism-react-renderer": "^2.3.1", - "pushfeedback": "^0.1.40", - "pushfeedback-react": "^0.1.40", + "prism-react-renderer": "^2.4.0", + "pushfeedback": "^0.1.44", + "pushfeedback-react": "^0.1.44", "react": "^18.3.1", "react-dom": "^18.3.1", "react-fast-marquee": "^1.6.5", "sha1": "^1.1.1", - "sharp": "^0.33.4", + "sharp": "^0.33.5", "superstruct": "^1.0.4", "text-to-svg": "^3.1.5", "url-loader": "^4.1.1" @@ -68,15 +68,15 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.25.1", - "@docusaurus/module-type-aliases": "^3.5.1", - "@docusaurus/theme-classic": "^3.5.1", - "@docusaurus/tsconfig": "^3.5.1", - "@docusaurus/types": "^3.5.1", + "@docusaurus/module-type-aliases": "^3.5.2", + "@docusaurus/theme-classic": "^3.5.2", + "@docusaurus/tsconfig": "^3.5.2", + "@docusaurus/types": "^3.5.2", "@eslint-kit/eslint-config-base": "4.1.0", "@eslint-kit/eslint-config-patch": "^1.0.0", "@eslint-kit/eslint-config-react": "^3.0.0", - "@types/node": "^22.2.0", - "@types/react": "^18.3.3", + "@types/node": "^22.7.4", + "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -86,12 +86,12 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "1.1.2", "prettier": "^3.3.3", - "sass": "^1.77.8", + "sass": "^1.79.3", "stylelint": "^15.11.0", "stylelint-config-recess-order": "^4.6.0", "stylelint-config-recommended": "^13.0.0", "stylelint-config-standard-scss": "^11.1.0", - "typescript": "^5.5.4" + "typescript": "^5.6.2" }, "packageManager": "pnpm@9.6.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 260b2840df..c344337132 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,32 +9,32 @@ importers: .: dependencies: '@ant-design/icons': - specifier: ^5.4.0 - version: 5.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^5.5.1 + version: 5.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/core': - specifier: ^3.5.1 - version: 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) + specifier: ^3.5.2 + version: 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@docusaurus/plugin-client-redirects': - specifier: ^3.5.1 - version: 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) + specifier: ^3.5.2 + version: 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@docusaurus/plugin-content-docs': - specifier: ^3.5.1 - version: 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) + specifier: ^3.5.2 + version: 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@docusaurus/plugin-ideal-image': - specifier: ^3.5.1 - version: 3.5.1(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) + specifier: ^3.5.2 + version: 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@docusaurus/preset-classic': - specifier: ^3.5.1 - version: 3.5.1(@algolia/client-search@4.24.0)(@types/react@18.3.3)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4) + specifier: ^3.5.2 + version: 3.5.2(@algolia/client-search@4.24.0)(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2) '@fontsource-variable/overpass': - specifier: ^5.0.19 - version: 5.0.19 + specifier: ^5.1.0 + version: 5.1.0 '@mdx-js/react': specifier: ^3.0.1 - version: 3.0.1(@types/react@18.3.3)(react@18.3.1) + version: 3.0.1(@types/react@18.3.10)(react@18.3.1) '@svgr/webpack': specifier: ^8.1.0 - version: 8.1.0(typescript@5.5.4) + version: 8.1.0(typescript@5.6.2) '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 @@ -51,20 +51,20 @@ importers: specifier: ^4.17.21 version: 4.17.21 picocolors: - specifier: ^1.0.1 - version: 1.0.1 + specifier: ^1.1.0 + version: 1.1.0 plugin-image-zoom: specifier: ^1.2.0 version: 1.2.0 prism-react-renderer: - specifier: ^2.3.1 - version: 2.3.1(react@18.3.1) + specifier: ^2.4.0 + version: 2.4.0(react@18.3.1) pushfeedback: - specifier: ^0.1.40 - version: 0.1.40 + specifier: ^0.1.44 + version: 0.1.44 pushfeedback-react: - specifier: ^0.1.40 - version: 0.1.40 + specifier: ^0.1.44 + version: 0.1.44 react: specifier: ^18.3.1 version: 18.3.1 @@ -78,8 +78,8 @@ importers: specifier: ^1.1.1 version: 1.1.1 sharp: - specifier: ^0.33.4 - version: 0.33.4 + specifier: ^0.33.5 + version: 0.33.5 superstruct: specifier: ^1.0.4 version: 1.0.4 @@ -94,20 +94,20 @@ importers: specifier: ^7.25.1 version: 7.25.1(@babel/core@7.25.2)(eslint@7.32.0) '@docusaurus/module-type-aliases': - specifier: ^3.5.1 - version: 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^3.5.2 + version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/theme-classic': - specifier: ^3.5.1 - version: 3.5.1(@types/react@18.3.3)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) + specifier: ^3.5.2 + version: 3.5.2(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@docusaurus/tsconfig': - specifier: ^3.5.1 - version: 3.5.1 + specifier: ^3.5.2 + version: 3.5.2 '@docusaurus/types': - specifier: ^3.5.1 - version: 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^3.5.2 + version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@eslint-kit/eslint-config-base': specifier: 4.1.0 - version: 4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0) + version: 4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0) '@eslint-kit/eslint-config-patch': specifier: ^1.0.0 version: 1.0.0(eslint@7.32.0) @@ -115,26 +115,26 @@ importers: specifier: ^3.0.0 version: 3.0.0(eslint@7.32.0) '@types/node': - specifier: ^22.2.0 - version: 22.2.0 + specifier: ^22.7.4 + version: 22.7.4 '@types/react': - specifier: ^18.3.3 - version: 18.3.3 + specifier: ^18.3.10 + version: 18.3.10 '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 '@typescript-eslint/eslint-plugin': specifier: ^6.21.0 - version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0)(typescript@5.5.4) + version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)(typescript@5.6.2) '@typescript-eslint/parser': specifier: ^6.21.0 - version: 6.21.0(eslint@7.32.0)(typescript@5.5.4) + version: 6.21.0(eslint@7.32.0)(typescript@5.6.2) all-contributors-cli: specifier: ^6.26.1 version: 6.26.1 docusaurus-plugin-sass: specifier: ^0.2.5 - version: 0.2.5(@docusaurus/core@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(sass@1.77.8)(webpack@5.93.0) + version: 0.2.5(@docusaurus/core@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(sass@1.79.3)(webpack@5.93.0) eslint: specifier: ^7.32.0 version: 7.32.0 @@ -143,28 +143,28 @@ importers: version: 9.1.0(eslint@7.32.0) eslint-import-resolver-alias: specifier: 1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)) prettier: specifier: ^3.3.3 version: 3.3.3 sass: - specifier: ^1.77.8 - version: 1.77.8 + specifier: ^1.79.3 + version: 1.79.3 stylelint: specifier: ^15.11.0 - version: 15.11.0(typescript@5.5.4) + version: 15.11.0(typescript@5.6.2) stylelint-config-recess-order: specifier: ^4.6.0 - version: 4.6.0(stylelint@15.11.0(typescript@5.5.4)) + version: 4.6.0(stylelint@15.11.0(typescript@5.6.2)) stylelint-config-recommended: specifier: ^13.0.0 - version: 13.0.0(stylelint@15.11.0(typescript@5.5.4)) + version: 13.0.0(stylelint@15.11.0(typescript@5.6.2)) stylelint-config-standard-scss: specifier: ^11.1.0 - version: 11.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.5.4)) + version: 11.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)) typescript: - specifier: ^5.5.4 - version: 5.5.4 + specifier: ^5.6.2 + version: 5.6.2 packages: @@ -246,8 +246,8 @@ packages: '@ant-design/icons-svg@4.4.2': resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} - '@ant-design/icons@5.4.0': - resolution: {integrity: sha512-QZbWC5xQYexCI5q4/fehSEkchJr5UGtvAJweT743qKUQQGs9IH2DehNLP49DJ3Ii9m9CijD2HN6fNy3WKhIFdA==} + '@ant-design/icons@5.5.1': + resolution: {integrity: sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==} engines: {node: '>=8'} peerDependencies: react: '>=16.0.0' @@ -940,11 +940,11 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@docsearch/css@3.6.1': - resolution: {integrity: sha512-VtVb5DS+0hRIprU2CO6ZQjK2Zg4QU5HrDM1+ix6rT0umsYvFvatMAnf97NHZlVWDaaLlx7GRfR/7FikANiM2Fg==} + '@docsearch/css@3.6.2': + resolution: {integrity: sha512-vKNZepO2j7MrYBTZIGXvlUOIR+v9KRf70FApRgovWrj3GTs1EITz/Xb0AOlm1xsQBp16clVZj1SY/qaOJbQtZw==} - '@docsearch/react@3.6.1': - resolution: {integrity: sha512-qXZkEPvybVhSXj0K7U3bXc233tk5e8PfhoZ6MhPOiik/qUQxYC+Dn9DnoS7CxHQQhHfCvTiN0eY9M12oRghEXw==} + '@docsearch/react@3.6.2': + resolution: {integrity: sha512-rtZce46OOkVflCQH71IdbXSFK+S8iJZlUF56XBW5rIgx/eG5qoomC7Ag3anZson1bBac/JFQn7XOBfved/IMRA==} peerDependencies: '@types/react': '>= 16.8.0 < 19.0.0' react: '>= 16.8.0 < 19.0.0' @@ -960,98 +960,99 @@ packages: search-insights: optional: true - '@docusaurus/core@3.5.1': - resolution: {integrity: sha512-N3+9IbGI2jbkiRc6ZbEnU9dC02nHQXi8ivM1VJldkPQyP7WlyHXS+NDhmL3rwaYOMbGH96X2LcKigCKg7pEEqg==} + '@docusaurus/core@3.5.2': + resolution: {integrity: sha512-4Z1WkhCSkX4KO0Fw5m/Vuc7Q3NxBG53NE5u59Rs96fWkMPZVSrzEPP16/Nk6cWb/shK7xXPndTmalJtw7twL/w==} engines: {node: '>=18.0'} hasBin: true peerDependencies: + '@mdx-js/react': ^3.0.0 react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/cssnano-preset@3.5.1': - resolution: {integrity: sha512-mvtWPLWePlm+4doepxMUT5ynsJQ3CgPtDdbaQh9wm3iAE/7OATBpSgLlfz5N+YtxI5bjIErjbkH8yzISP+S65g==} + '@docusaurus/cssnano-preset@3.5.2': + resolution: {integrity: sha512-D3KiQXOMA8+O0tqORBrTOEQyQxNIfPm9jEaJoALjjSjc2M/ZAWcUfPQEnwr2JB2TadHw2gqWgpZckQmrVWkytA==} engines: {node: '>=18.0'} - '@docusaurus/logger@3.5.1': - resolution: {integrity: sha512-B36a88CEHCtxIylAV1HNuiiISpoKBqm0UxA6a/JwtHX++Dxb7LNDSGs8ELBlQsZN0OG2tX3tBsCWyaLPwYorkQ==} + '@docusaurus/logger@3.5.2': + resolution: {integrity: sha512-LHC540SGkeLfyT3RHK3gAMK6aS5TRqOD4R72BEU/DE2M/TY8WwEUAMY576UUc/oNJXv8pGhBmQB6N9p3pt8LQw==} engines: {node: '>=18.0'} - '@docusaurus/lqip-loader@3.5.1': - resolution: {integrity: sha512-6zH81/yQyJlRxyVUKUXUt1XmsrbcRlWWwQmnq+xfVHgLymkZnLXD4C28ZSUWVt6SBVXOj4f0FTAo31UrMXfYdQ==} + '@docusaurus/lqip-loader@3.5.2': + resolution: {integrity: sha512-yUD90PgwbGciCHHiQTWXZvpLv9nVTpXrX8Ilz5Sl6oJ1bwnLgGsbl7h+EseVbwBnKhVCoujW/EKRU6+3HqeeXQ==} engines: {node: '>=18.0'} - '@docusaurus/mdx-loader@3.5.1': - resolution: {integrity: sha512-D6Ea2dt32xhoqH+1EuHLGDVSX2HLFiR4QpI0GTU46qOu2hb2ChpQENIUZ2inOsdGFunNa0fCnDG3qn7Kdbzq1A==} + '@docusaurus/mdx-loader@3.5.2': + resolution: {integrity: sha512-ku3xO9vZdwpiMIVd8BzWV0DCqGEbCP5zs1iHfKX50vw6jX8vQo0ylYo1YJMZyz6e+JFJ17HYHT5FzVidz2IflA==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/module-type-aliases@3.5.1': - resolution: {integrity: sha512-SKKdA5RnvZr3pvFXkxtfsBVNgflRGa/bN1HbNi+1s0HNVYPuhB9DFC/CrKe2OoOfUXx7F7k2gg0Jg9gJYDy4rA==} + '@docusaurus/module-type-aliases@3.5.2': + resolution: {integrity: sha512-Z+Xu3+2rvKef/YKTMxZHsEXp1y92ac0ngjDiExRdqGTmEKtCUpkbNYH8v5eXo5Ls+dnW88n6WTa+Q54kLOkwPg==} peerDependencies: react: '*' react-dom: '*' - '@docusaurus/plugin-client-redirects@3.5.1': - resolution: {integrity: sha512-0At2RdS+7gDA25IMQROp4CcKx526jfER7bsna0EdWtPkC+rimSwxcxEHy0A+7xkBuUPh4SZNNuPVJAnYnvggrA==} + '@docusaurus/plugin-client-redirects@3.5.2': + resolution: {integrity: sha512-GMU0ZNoVG1DEsZlBbwLPdh0iwibrVZiRfmdppvX17SnByCVP74mb/Nne7Ss7ALgxQLtM4IHbXi8ij90VVjAJ+Q==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-content-blog@3.5.1': - resolution: {integrity: sha512-aPmrMV5cDa2QUZ+kPVJID5O6r+ZuLFtHEyneVl9AgryL/9ECudhtpTUdmdnmapnWfUzSSgqYRZ1JtydGLheSzw==} + '@docusaurus/plugin-content-blog@3.5.2': + resolution: {integrity: sha512-R7ghWnMvjSf+aeNDH0K4fjyQnt5L0KzUEnUhmf1e3jZrv3wogeytZNN6n7X8yHcMsuZHPOrctQhXWnmxu+IRRg==} engines: {node: '>=18.0'} peerDependencies: '@docusaurus/plugin-content-docs': '*' react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-content-docs@3.5.1': - resolution: {integrity: sha512-DX+I3eVyXak9KqYXg8dgptomqz/O4twjydpLJT8ZSe9lsZ0Pa1ZNPwmftWYn160O3o6GGeUYzr13Y1Got3iXRQ==} + '@docusaurus/plugin-content-docs@3.5.2': + resolution: {integrity: sha512-Bt+OXn/CPtVqM3Di44vHjE7rPCEsRCB/DMo2qoOuozB9f7+lsdrHvD0QCHdBs0uhz6deYJDppAr2VgqybKPlVQ==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-content-pages@3.5.1': - resolution: {integrity: sha512-V2PDVrO2vHYJ7uhrEHpfzg3TTuwfrgNC0pGhM5gXaMfCbdhKm7iwV0huGLcyIX5Peyh7EMP2e8GFccUzWFMYOg==} + '@docusaurus/plugin-content-pages@3.5.2': + resolution: {integrity: sha512-WzhHjNpoQAUz/ueO10cnundRz+VUtkjFhhaQ9jApyv1a46FPURO4cef89pyNIOMny1fjDz/NUN2z6Yi+5WUrCw==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-debug@3.5.1': - resolution: {integrity: sha512-teFZamoECDiELwM1cx5OXd6dBpRtHarc7kWGL1iQozAkYcobZmqOWykBl4joMjSWUbJlx5v9/CVciykWbFNXjA==} + '@docusaurus/plugin-debug@3.5.2': + resolution: {integrity: sha512-kBK6GlN0itCkrmHuCS6aX1wmoWc5wpd5KJlqQ1FyrF0cLDnvsYSnh7+ftdwzt7G6lGBho8lrVwkkL9/iQvaSOA==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-google-analytics@3.5.1': - resolution: {integrity: sha512-5FUiYZQWPXTPucMzaOOM25R7IwIPvMKbiB0SNVGtxVsGyFyo5i5fzrkBQl4mkZd7uqmslEPzwYbC28ZeFnrxjg==} + '@docusaurus/plugin-google-analytics@3.5.2': + resolution: {integrity: sha512-rjEkJH/tJ8OXRE9bwhV2mb/WP93V441rD6XnM6MIluu7rk8qg38iSxS43ga2V2Q/2ib53PcqbDEJDG/yWQRJhQ==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-google-gtag@3.5.1': - resolution: {integrity: sha512-jxBtLBPMv9BJXPXrwJSs69qYcHP/evT1NkVza2yOai7wi5r3E1tVm0bAxdciWitpM0dgS/HDa30qXE7vA1NRDg==} + '@docusaurus/plugin-google-gtag@3.5.2': + resolution: {integrity: sha512-lm8XL3xLkTPHFKKjLjEEAHUrW0SZBSHBE1I+i/tmYMBsjCcUB5UJ52geS5PSiOCFVR74tbPGcPHEV/gaaxFeSA==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-google-tag-manager@3.5.1': - resolution: {integrity: sha512-W5WsKoRmb3lDmg2IBfmKsZDlQAkEx/dXuwr4bj7sSQdM8qd829Rsc4Gp5RddUrQdUz/W3Iocn7LayRM5aacJlA==} + '@docusaurus/plugin-google-tag-manager@3.5.2': + resolution: {integrity: sha512-QkpX68PMOMu10Mvgvr5CfZAzZQFx8WLlOiUQ/Qmmcl6mjGK6H21WLT5x7xDmcpCoKA/3CegsqIqBR+nA137lQg==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-ideal-image@3.5.1': - resolution: {integrity: sha512-gBdjBTIHyHR5Na3kCKKf2k/29KQ7wljh32zICSJkd59ts5VQzAbFgacNDmA/ZLpHFX88QMXJrwOQ6u/WAayGaw==} + '@docusaurus/plugin-ideal-image@3.5.2': + resolution: {integrity: sha512-FnHi3a5DjYRvjN1XbXRe1Cmiqfc+tAI2VmThN1Mr9teLB0ibuRi++P98q6+KyamBWKrJmuskWLMdr71acwHM8Q==} engines: {node: '>=18.0'} peerDependencies: jimp: '*' @@ -1061,15 +1062,15 @@ packages: jimp: optional: true - '@docusaurus/plugin-sitemap@3.5.1': - resolution: {integrity: sha512-VXMGJM6uy4jx6HUsFs+kn8MujWGjN7S7p7PYUYSf1bmcFNlf+Qg5vDZtwBElHa2hapeH2AIj2b3QmTgmWeyOHw==} + '@docusaurus/plugin-sitemap@3.5.2': + resolution: {integrity: sha512-DnlqYyRAdQ4NHY28TfHuVk414ft2uruP4QWCH//jzpHjqvKyXjj2fmDtI8RPUBh9K8iZKFMHRnLtzJKySPWvFA==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/preset-classic@3.5.1': - resolution: {integrity: sha512-afDMZoNYxdloJ7qJJbd3Lmv9uYXKKsEAOtvnvu2945kqe1LUGIIwOo1nMAKgB9y21E5FEvWKnla0MvkMraumZA==} + '@docusaurus/preset-classic@3.5.2': + resolution: {integrity: sha512-3ihfXQ95aOHiLB5uCu+9PRy2gZCeSZoDcqpnDvf3B+sTrMvMTr8qRUzBvWkoIqc82yG5prCboRjk1SVILKx6sg==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 @@ -1092,43 +1093,43 @@ packages: sharp: optional: true - '@docusaurus/theme-classic@3.5.1': - resolution: {integrity: sha512-k8rLMwHuTc3SqYekc20s1uZHjabt9yi6mt1RUjbkwmjsJlAB6zrtYvsB+ZxrhY5yeUD8DZm3h0qVvKbClHVCCA==} + '@docusaurus/theme-classic@3.5.2': + resolution: {integrity: sha512-XRpinSix3NBv95Rk7xeMF9k4safMkwnpSgThn0UNQNumKvmcIYjfkwfh2BhwYh/BxMXQHJ/PdmNh22TQFpIaYg==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/theme-common@3.5.1': - resolution: {integrity: sha512-r34YDzSjggX+B+8W+mG2dVh1ps4JJRCiyq8E1LnZIKLU6F89I2KpAZpPQ2/njKsKhBRLtQ1x92HVkD0FZ3xjrg==} + '@docusaurus/theme-common@3.5.2': + resolution: {integrity: sha512-QXqlm9S6x9Ibwjs7I2yEDgsCocp708DrCrgHgKwg2n2AY0YQ6IjU0gAK35lHRLOvAoJUfCKpQAwUykB0R7+Eew==} engines: {node: '>=18.0'} peerDependencies: '@docusaurus/plugin-content-docs': '*' react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/theme-search-algolia@3.5.1': - resolution: {integrity: sha512-IcUbgh9YcedANhpa0Q3+67WUKY8G7YkN/pZxVBEFjq3d2bniRKktPv41Nh/+AtGLSNJIcspZwEAs/r/mKSZGug==} + '@docusaurus/theme-search-algolia@3.5.2': + resolution: {integrity: sha512-qW53kp3VzMnEqZGjakaV90sst3iN1o32PH+nawv1uepROO8aEGxptcq2R5rsv7aBShSRbZwIobdvSYKsZ5pqvA==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/theme-translations@3.5.1': - resolution: {integrity: sha512-fyzQOWrTm0+ZpTlS0/xHsIK4f+LA4qVFrq8rCzIHjxZRip/noYUOwF64lA95vcuw6qnOVBoNE/LyfbBvExnpcw==} + '@docusaurus/theme-translations@3.5.2': + resolution: {integrity: sha512-GPZLcu4aT1EmqSTmbdpVrDENGR2yObFEX8ssEFYTCiAIVc0EihNSdOIBTazUvgNqwvnoU1A8vIs1xyzc3LITTw==} engines: {node: '>=18.0'} - '@docusaurus/tsconfig@3.5.1': - resolution: {integrity: sha512-6OO63/xQ11Tu4reCRuB4zfjqdZYmQwkOTVI8zxxEHCLma4pplsx4HTCB2lVgztEL+Qr6hcHY952ZrpmoAt5rUA==} + '@docusaurus/tsconfig@3.5.2': + resolution: {integrity: sha512-rQ7toURCFnWAIn8ubcquDs0ewhPwviMzxh6WpRjBW7sJVCXb6yzwUaY3HMNa0VXCFw+qkIbFywrMTf+Pb4uHWQ==} - '@docusaurus/types@3.5.1': - resolution: {integrity: sha512-IXTGQBoXAGFliGF5Cn3F+gSGskgzAL8+4y6dDY1gcePA0r8WngHj8oovS1YPv+b9JOff32nv8YGGZITHOMXJsA==} + '@docusaurus/types@3.5.2': + resolution: {integrity: sha512-N6GntLXoLVUwkZw7zCxwy9QiuEXIcTVzA9AkmNw16oc0AP3SXLrMmDMMBIfgqwuKWa6Ox6epHol9kMtJqekACw==} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/utils-common@3.5.1': - resolution: {integrity: sha512-374n6/IW34gHR65JMMN33XLFogTCsrGVPQDVbv2vG96EYHvYzE/plfcGV7xSbXB8yS1YHsxVfvNgVUGi973bfQ==} + '@docusaurus/utils-common@3.5.2': + resolution: {integrity: sha512-i0AZjHiRgJU6d7faQngIhuHKNrszpL/SHQPgF1zH4H+Ij6E9NBYGy6pkcGWToIv7IVPbs+pQLh1P3whn0gWXVg==} engines: {node: '>=18.0'} peerDependencies: '@docusaurus/types': '*' @@ -1136,12 +1137,12 @@ packages: '@docusaurus/types': optional: true - '@docusaurus/utils-validation@3.5.1': - resolution: {integrity: sha512-LZdQnqVVLStgTCn0rfvf4wuOQkjPbGtLXJIQ449em1wJeSFO7lfmn5VGUNLt+xKHvIPfN272EHG8BuvijCI0+A==} + '@docusaurus/utils-validation@3.5.2': + resolution: {integrity: sha512-m+Foq7augzXqB6HufdS139PFxDC5d5q2QKZy8q0qYYvGdI6nnlNsGH4cIGsgBnV7smz+mopl3g4asbSDvMV0jA==} engines: {node: '>=18.0'} - '@docusaurus/utils@3.5.1': - resolution: {integrity: sha512-/4QAvXyiQviz2FQ4ct5l1ckvDihIdjS8FsOExC0T+Y1UD38jgPbjTwRJXsDaRsDRCCrDAtXvlonxXw2kixcnXw==} + '@docusaurus/utils@3.5.2': + resolution: {integrity: sha512-33QvcNFh+Gv+C2dP9Y9xWEzMgf3JzrpL2nW9PopidiohS1nDcyknKRx2DWaFvyVTTYIkkABVSr073VTj/NITNA==} engines: {node: '>=18.0'} peerDependencies: '@docusaurus/types': '*' @@ -1181,8 +1182,8 @@ packages: resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} engines: {node: ^10.12.0 || >=12.0.0} - '@fontsource-variable/overpass@5.0.19': - resolution: {integrity: sha512-MGeaVYF/ItkSIbNNVBlCC68srrUSFJCSqIuRY9L3qyIsKdDUuF3ZCsIQ2SBWfWo/0zZ3Pa7TuVNOojgHENbioQ==} + '@fontsource-variable/overpass@5.1.0': + resolution: {integrity: sha512-Fz7+ZTNSW6YeoTGHvUvDsydiW6bXt0pAbhUaL23FCnRZaRv5qqH+JNkkQdtj4R5qqrTwi5iAZn9r3dCJm+sDfw==} '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} @@ -1199,116 +1200,108 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.4': - resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==} - engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.4': - resolution: {integrity: sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==} - engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.2': - resolution: {integrity: sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==} - engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.2': - resolution: {integrity: sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==} - engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.2': - resolution: {integrity: sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==} - engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.2': - resolution: {integrity: sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==} - engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.2': - resolution: {integrity: sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==} - engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.2': - resolution: {integrity: sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==} - engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.2': - resolution: {integrity: sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==} - engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.2': - resolution: {integrity: sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==} - engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.4': - resolution: {integrity: sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==} - engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.4': - resolution: {integrity: sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==} - engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.4': - resolution: {integrity: sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==} - engines: {glibc: '>=2.31', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.4': - resolution: {integrity: sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==} - engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.4': - resolution: {integrity: sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==} - engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.4': - resolution: {integrity: sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==} - engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.4': - resolution: {integrity: sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.4': - resolution: {integrity: sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.4': - resolution: {integrity: sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -1538,6 +1531,9 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/express-serve-static-core@4.19.5': resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==} @@ -1607,8 +1603,8 @@ packages: '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} - '@types/node@22.2.0': - resolution: {integrity: sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==} + '@types/node@22.7.4': + resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1640,8 +1636,8 @@ packages: '@types/react-router@5.1.20': resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} - '@types/react@18.3.3': - resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + '@types/react@18.3.10': + resolution: {integrity: sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==} '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} @@ -1670,6 +1666,9 @@ packages: '@types/unist@3.0.2': resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/ws@8.5.12': resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} @@ -1851,8 +1850,8 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - algoliasearch-helper@3.22.3: - resolution: {integrity: sha512-2eoEz8mG4KHE+DzfrBTrCmDPxVXv7aZZWPojAJFtARpxxMO6lkos1dJ+XDCXdPvq7q3tpYWRi6xXmVQikejtpA==} + algoliasearch-helper@3.22.5: + resolution: {integrity: sha512-lWvhdnc+aKOKx8jyA3bsdEgHzm/sglC4cYdMG4xSQyRiPLJVJtH/IVYZG3Hp6PkTEhQqhyVYkeP9z2IlcHJsWw==} peerDependencies: algoliasearch: '>= 3.1 < 6' @@ -2079,6 +2078,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.24.0: + resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2138,6 +2142,9 @@ packages: caniuse-lite@1.0.30001651: resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==} + caniuse-lite@1.0.30001664: + resolution: {integrity: sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2186,6 +2193,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -2702,6 +2713,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.29: + resolution: {integrity: sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==} + electron-to-chromium@1.5.6: resolution: {integrity: sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==} @@ -2780,6 +2794,10 @@ packages: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-goat@4.0.0: resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} engines: {node: '>=12'} @@ -2814,6 +2832,27 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + eslint-module-utils@2.8.1: resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} @@ -3610,6 +3649,10 @@ packages: resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==} engines: {node: '>= 0.4'} + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} engines: {node: '>= 0.4'} @@ -3991,8 +4034,8 @@ packages: mdast-util-frontmatter@2.0.1: resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} - mdast-util-gfm-autolink-literal@2.0.0: - resolution: {integrity: sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==} + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} mdast-util-gfm-footnote@2.0.0: resolution: {integrity: sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==} @@ -4071,8 +4114,8 @@ packages: micromark-core-commonmark@2.0.1: resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==} - micromark-extension-directive@3.0.1: - resolution: {integrity: sha512-VGV2uxUzhEZmaP7NSFo2vtq7M2nUD+WfmYQD+d8i/1nHbzE+rMy9uzTvUybBbNiVbrhOZibg3gbyoARGqgDWyg==} + micromark-extension-directive@3.0.2: + resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} micromark-extension-frontmatter@2.0.0: resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} @@ -4195,6 +4238,10 @@ packages: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.33.0: resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} engines: {node: '>= 0.6'} @@ -4585,8 +4632,8 @@ packages: periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} - picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -4844,6 +4891,10 @@ packages: resolution: {integrity: sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==} engines: {node: '>=4'} + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + postcss-sort-media-queries@5.2.0: resolution: {integrity: sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==} engines: {node: '>=14.0.0'} @@ -4906,8 +4957,8 @@ packages: resolution: {integrity: sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==} engines: {node: '>=4'} - prism-react-renderer@2.3.1: - resolution: {integrity: sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==} + prism-react-renderer@2.4.0: + resolution: {integrity: sha512-327BsVCD/unU4CNLZTWVHyUHKnsqcvj2qbPlQ8MiBE2eq2rgctjigPA1Gp9HLF83kZ20zNN6jgizHJeEsyFYOw==} peerDependencies: react: '>=16.0.0' @@ -4953,11 +5004,11 @@ packages: resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==} engines: {node: '>=12.20'} - pushfeedback-react@0.1.40: - resolution: {integrity: sha512-He2ssVfWi4MTRb46+i0gGlV4+CC9NolF+Hb2aZHgm+GqNHtOEd/Hw5IstxmcDUyjlD//Pvtbx+0ZeE4+HEOrxA==} + pushfeedback-react@0.1.44: + resolution: {integrity: sha512-2ZrySoKPTXr/H0o6DwBsRiGzwUgSzHLODC2iVu7dA8Sl2M7cG5RrDGdabdMDlYu9GwkRD5H1MqjRVb9Wyp4uWQ==} - pushfeedback@0.1.40: - resolution: {integrity: sha512-ft2+KIZTeFnH7JWOaW0ZmaK2Co5Z0V8NlvtZqaCMIj1wWW3Aa4ylMyPfAtYRQ2mmRyf9O7K4BNhjkORw/1zIuA==} + pushfeedback@0.1.44: + resolution: {integrity: sha512-eezqumWKeWu348bdL4TIiPCm1NJq6jr457CVCx9lCSQ61TDkOHOb/fUcaQMx4inPD/b4dw5G96NRiWBCe+deZw==} qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} @@ -5045,8 +5096,8 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-json-view-lite@1.4.0: - resolution: {integrity: sha512-wh6F6uJyYAmQ4fK0e8dSQMEWuvTs2Wr3el3sLD9bambX1+pSWUVXIz1RFaoy3TI1mZ0FqdpKq9YgbgTTgyrmXA==} + react-json-view-lite@1.5.0: + resolution: {integrity: sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw==} engines: {node: '>=14'} peerDependencies: react: ^16.13.1 || ^17.0.0 || ^18.0.0 @@ -5118,6 +5169,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.1: + resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} + engines: {node: '>= 14.16.0'} + reading-time@1.5.0: resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==} @@ -5330,8 +5385,8 @@ packages: sass: optional: true - sass@1.77.8: - resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==} + sass@1.79.3: + resolution: {integrity: sha512-m7dZxh0W9EZ3cw50Me5GOuYm/tVAJAn91SUnohLRo9cXBixGUOdvmryN+dXpwR831bhoY3Zv7rEFt85PUwTmzA==} engines: {node: '>=14.0.0'} hasBin: true @@ -5433,9 +5488,9 @@ packages: resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} engines: {node: '>=14.15.0'} - sharp@0.33.4: - resolution: {integrity: sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==} - engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -5862,6 +5917,9 @@ packages: tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -5916,16 +5974,16 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typescript@5.5.4: - resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + typescript@5.6.2: + resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} engines: {node: '>=14.17'} hasBin: true unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@6.13.0: - resolution: {integrity: sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} unicode-canonical-property-names-ecmascript@2.0.0: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} @@ -5989,6 +6047,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + update-notifier@6.0.2: resolution: {integrity: sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==} engines: {node: '>=14.16'} @@ -6049,10 +6113,17 @@ packages: vfile@6.0.2: resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==} + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + watchpack@2.4.1: resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==} engines: {node: '>=10.13.0'} + watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + engines: {node: '>=10.13.0'} + wbuf@1.7.3: resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} @@ -6104,6 +6175,16 @@ packages: webpack-cli: optional: true + webpack@5.95.0: + resolution: {integrity: sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + webpackbar@5.0.2: resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} engines: {node: '>=12'} @@ -6356,7 +6437,7 @@ snapshots: '@ant-design/icons-svg@4.4.2': {} - '@ant-design/icons@5.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@ant-design/icons@5.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 @@ -6373,7 +6454,7 @@ snapshots: '@babel/code-frame@7.24.7': dependencies: '@babel/highlight': 7.24.7 - picocolors: 1.0.1 + picocolors: 1.1.0 '@babel/compat-data@7.25.2': {} @@ -6548,7 +6629,7 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.1 + picocolors: 1.1.0 '@babel/parser@7.25.3': dependencies: @@ -7256,23 +7337,23 @@ snapshots: '@discoveryjs/json-ext@0.5.7': {} - '@docsearch/css@3.6.1': {} + '@docsearch/css@3.6.2': {} - '@docsearch/react@3.6.1(@algolia/client-search@4.24.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)': + '@docsearch/react@3.6.2(@algolia/client-search@4.24.0)(@types/react@18.3.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)': dependencies: '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0) '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) - '@docsearch/css': 3.6.1 + '@docsearch/css': 3.6.2 algoliasearch: 4.24.0 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) search-insights: 2.15.0 transitivePeerDependencies: - '@algolia/client-search' - '@docusaurus/core@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/core@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: '@babel/core': 7.25.2 '@babel/generator': 7.25.0 @@ -7284,12 +7365,13 @@ snapshots: '@babel/runtime': 7.25.0 '@babel/runtime-corejs3': 7.25.0 '@babel/traverse': 7.25.3 - '@docusaurus/cssnano-preset': 3.5.1 - '@docusaurus/logger': 3.5.1 - '@docusaurus/mdx-loader': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/cssnano-preset': 3.5.2 + '@docusaurus/logger': 3.5.2 + '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@mdx-js/react': 3.0.1(@types/react@18.3.10)(react@18.3.1) autoprefixer: 10.4.20(postcss@8.4.41) babel-loader: 9.1.3(@babel/core@7.25.2)(webpack@5.93.0) babel-plugin-dynamic-import-node: 2.3.3 @@ -7320,10 +7402,10 @@ snapshots: mini-css-extract-plugin: 2.9.0(webpack@5.93.0) p-map: 4.0.0 postcss: 8.4.41 - postcss-loader: 7.3.4(postcss@8.4.41)(typescript@5.5.4)(webpack@5.93.0) + postcss-loader: 7.3.4(postcss@8.4.41)(typescript@5.6.2)(webpack@5.93.0) prompts: 2.4.2 react: 18.3.1 - react-dev-utils: 12.0.1(eslint@7.32.0)(typescript@5.5.4)(webpack@5.93.0) + react-dev-utils: 12.0.1(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0) react-dom: 18.3.1(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)' @@ -7363,21 +7445,21 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/cssnano-preset@3.5.1': + '@docusaurus/cssnano-preset@3.5.2': dependencies: cssnano-preset-advanced: 6.1.2(postcss@8.4.41) postcss: 8.4.41 postcss-sort-media-queries: 5.2.0(postcss@8.4.41) tslib: 2.6.3 - '@docusaurus/logger@3.5.1': + '@docusaurus/logger@3.5.2': dependencies: chalk: 4.1.2 tslib: 2.6.3 - '@docusaurus/lqip-loader@3.5.1(webpack@5.93.0)': + '@docusaurus/lqip-loader@3.5.2(webpack@5.93.0)': dependencies: - '@docusaurus/logger': 3.5.1 + '@docusaurus/logger': 3.5.2 file-loader: 6.2.0(webpack@5.93.0) lodash: 4.17.21 sharp: 0.32.6 @@ -7385,16 +7467,16 @@ snapshots: transitivePeerDependencies: - webpack - '@docusaurus/mdx-loader@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/mdx-loader@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/logger': 3.5.1 - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/logger': 3.5.2 + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) '@mdx-js/mdx': 3.0.1 '@slorber/remark-comment': 1.0.0 escape-html: 1.0.3 estree-util-value-to-estree: 3.1.2 - file-loader: 6.2.0(webpack@5.93.0) + file-loader: 6.2.0(webpack@5.95.0) fs-extra: 11.2.0 image-size: 1.1.1 mdast-util-mdx: 3.0.0 @@ -7410,9 +7492,9 @@ snapshots: tslib: 2.6.3 unified: 11.0.5 unist-util-visit: 5.0.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0) - vfile: 6.0.2 - webpack: 5.93.0 + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.95.0) + vfile: 6.0.3 + webpack: 5.95.0 transitivePeerDependencies: - '@docusaurus/types' - '@swc/core' @@ -7422,11 +7504,11 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/module-type-aliases@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/module-type-aliases@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/history': 4.7.11 - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-router-config': 5.0.11 '@types/react-router-dom': 5.3.3 react: 18.3.1 @@ -7440,13 +7522,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-client-redirects@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-client-redirects@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/logger': 3.5.1 - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/logger': 3.5.2 + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) eta: 2.2.0 fs-extra: 11.2.0 lodash: 4.17.21 @@ -7455,6 +7537,7 @@ snapshots: tslib: 2.6.3 transitivePeerDependencies: - '@docusaurus/types' + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7472,17 +7555,17 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-blog@3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': - dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/logger': 3.5.1 - '@docusaurus/mdx-loader': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-content-docs': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-common': 3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/plugin-content-blog@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + dependencies: + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/logger': 3.5.2 + '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) cheerio: 1.0.0-rc.12 feed: 4.2.2 fs-extra: 11.2.0 @@ -7494,8 +7577,9 @@ snapshots: tslib: 2.6.3 unist-util-visit: 5.0.0 utility-types: 3.11.0 - webpack: 5.93.0 + webpack: 5.95.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7513,17 +7597,17 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': - dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/logger': 3.5.1 - '@docusaurus/mdx-loader': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/module-type-aliases': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + dependencies: + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/logger': 3.5.2 + '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 fs-extra: 11.2.0 @@ -7535,6 +7619,7 @@ snapshots: utility-types: 3.11.0 webpack: 5.93.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7552,19 +7637,20 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-pages@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-content-pages@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/mdx-loader': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.6.3 - webpack: 5.93.0 + webpack: 5.95.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7582,17 +7668,18 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-debug@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-debug@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-json-view-lite: 1.4.0(react@18.3.1) - tslib: 2.6.3 + react-json-view-lite: 1.5.0(react@18.3.1) + tslib: 2.7.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7610,15 +7697,16 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-analytics@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-google-analytics@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7636,16 +7724,17 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-gtag@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-google-gtag@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) '@types/gtag.js': 0.0.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7663,15 +7752,16 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-google-tag-manager@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7689,14 +7779,14 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-ideal-image@3.5.1(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-ideal-image@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/lqip-loader': 3.5.1(webpack@5.93.0) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/lqip-loader': 3.5.2(webpack@5.93.0) '@docusaurus/responsive-loader': 1.7.0(sharp@0.32.6) - '@docusaurus/theme-translations': 3.5.1 - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/theme-translations': 3.5.2 + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) '@slorber/react-ideal-image': 0.0.12(prop-types@15.8.1)(react-waypoint@10.3.0(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7705,6 +7795,7 @@ snapshots: tslib: 2.6.3 webpack: 5.93.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7723,20 +7814,21 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-sitemap@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/plugin-sitemap@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/logger': 3.5.1 - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/logger': 3.5.2 + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) sitemap: 7.1.2 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7754,25 +7846,26 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/preset-classic@3.5.1(@algolia/client-search@4.24.0)(@types/react@18.3.3)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4)': - dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-content-blog': 3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-content-docs': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-content-pages': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-debug': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-google-analytics': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-google-gtag': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-google-tag-manager': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-sitemap': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-classic': 3.5.1(@types/react@18.3.3)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-common': 3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-search-algolia': 3.5.1(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4) - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/preset-classic@3.5.2(@algolia/client-search@4.24.0)(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2)': + dependencies: + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-content-blog': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-content-pages': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-debug': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-google-analytics': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-google-gtag': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-google-tag-manager': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-sitemap': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-classic': 3.5.2(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-search-algolia': 3.5.2(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - '@algolia/client-search' + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7794,7 +7887,7 @@ snapshots: '@docusaurus/react-loadable@6.0.0(react@18.3.1)': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 react: 18.3.1 '@docusaurus/responsive-loader@1.7.0(sharp@0.32.6)': @@ -7803,28 +7896,28 @@ snapshots: optionalDependencies: sharp: 0.32.6 - '@docusaurus/theme-classic@3.5.1(@types/react@18.3.3)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': - dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/mdx-loader': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/module-type-aliases': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-blog': 3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-content-docs': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/plugin-content-pages': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-common': 3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-translations': 3.5.1 - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1) + '@docusaurus/theme-classic@3.5.2(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + dependencies: + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-blog': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/plugin-content-pages': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-translations': 3.5.2 + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@mdx-js/react': 3.0.1(@types/react@18.3.10)(react@18.3.1) clsx: 2.1.1 copy-text-to-clipboard: 3.2.0 infima: 0.2.0-alpha.44 lodash: 4.17.21 nprogress: 0.2.0 postcss: 8.4.41 - prism-react-renderer: 2.3.1(react@18.3.1) + prism-react-renderer: 2.4.0(react@18.3.1) prismjs: 1.29.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7851,19 +7944,19 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-common@3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': + '@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: - '@docusaurus/mdx-loader': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/module-type-aliases': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-docs': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) '@types/history': 4.7.11 - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-router-config': 5.0.11 clsx: 2.1.1 parse-numeric-range: 1.3.0 - prism-react-renderer: 2.3.1(react@18.3.1) + prism-react-renderer: 2.4.0(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.6.3 @@ -7877,29 +7970,30 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-search-algolia@3.5.1(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4)': + '@docusaurus/theme-search-algolia@3.5.2(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2)': dependencies: - '@docsearch/react': 3.6.1(@algolia/client-search@4.24.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0) - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/logger': 3.5.1 - '@docusaurus/plugin-content-docs': 3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-common': 3.5.1(@docusaurus/plugin-content-docs@3.5.1(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - '@docusaurus/theme-translations': 3.5.1 - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-validation': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) + '@docsearch/react': 3.6.2(@algolia/client-search@4.24.0)(@types/react@18.3.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/logger': 3.5.2 + '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@docusaurus/theme-translations': 3.5.2 + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) algoliasearch: 4.24.0 - algoliasearch-helper: 3.22.3(algoliasearch@4.24.0) + algoliasearch-helper: 3.22.5(algoliasearch@4.24.0) clsx: 2.1.1 eta: 2.2.0 fs-extra: 11.2.0 lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 utility-types: 3.11.0 transitivePeerDependencies: - '@algolia/client-search' - '@docusaurus/types' + - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' @@ -7919,18 +8013,18 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-translations@3.5.1': + '@docusaurus/theme-translations@3.5.2': dependencies: fs-extra: 11.2.0 tslib: 2.6.3 - '@docusaurus/tsconfig@3.5.1': {} + '@docusaurus/tsconfig@3.5.2': {} - '@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@mdx-js/mdx': 3.0.1 '@types/history': 4.7.11 - '@types/react': 18.3.3 + '@types/react': 18.3.10 commander: 5.1.0 joi: 17.13.3 react: 18.3.1 @@ -7946,17 +8040,17 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-common@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@docusaurus/utils-common@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: tslib: 2.6.3 optionalDependencies: - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)': + '@docusaurus/utils-validation@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2)': dependencies: - '@docusaurus/logger': 3.5.1 - '@docusaurus/utils': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4) - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/logger': 3.5.2 + '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) fs-extra: 11.2.0 joi: 17.13.3 js-yaml: 4.1.0 @@ -7971,13 +8065,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)': + '@docusaurus/utils@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2)': dependencies: - '@docusaurus/logger': 3.5.1 - '@docusaurus/utils-common': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@svgr/webpack': 8.1.0(typescript@5.5.4) + '@docusaurus/logger': 3.5.2 + '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@svgr/webpack': 8.1.0(typescript@5.6.2) escape-string-regexp: 4.0.0 - file-loader: 6.2.0(webpack@5.93.0) + file-loader: 6.2.0(webpack@5.95.0) fs-extra: 11.2.0 github-slugger: 1.5.0 globby: 11.1.0 @@ -7985,16 +8079,16 @@ snapshots: jiti: 1.21.6 js-yaml: 4.1.0 lodash: 4.17.21 - micromatch: 4.0.7 + micromatch: 4.0.8 prompts: 2.4.2 resolve-pathname: 3.0.0 shelljs: 0.8.5 tslib: 2.6.3 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.95.0) utility-types: 3.11.0 - webpack: 5.93.0 + webpack: 5.95.0 optionalDependencies: - '@docusaurus/types': 3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@swc/core' - esbuild @@ -8005,7 +8099,7 @@ snapshots: '@emnapi/runtime@1.2.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 optional: true '@eslint-community/eslint-utils@4.4.0(eslint@7.32.0)': @@ -8015,10 +8109,10 @@ snapshots: '@eslint-community/regexpp@4.11.0': {} - '@eslint-kit/eslint-config-base@4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0)': + '@eslint-kit/eslint-config-base@4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)': dependencies: eslint: 7.32.0 - eslint-plugin-import: 2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0) + eslint-plugin-import: 2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0) eslint-plugin-sonarjs: 0.7.0(eslint@7.32.0) eslint-plugin-unicorn: 32.0.1(eslint@7.32.0) transitivePeerDependencies: @@ -8052,7 +8146,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@fontsource-variable/overpass@5.0.19': {} + '@fontsource-variable/overpass@5.1.0': {} '@hapi/hoek@9.3.0': {} @@ -8070,79 +8164,79 @@ snapshots: '@humanwhocodes/object-schema@1.2.1': {} - '@img/sharp-darwin-arm64@0.33.4': + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.2 + '@img/sharp-libvips-darwin-arm64': 1.0.4 optional: true - '@img/sharp-darwin-x64@0.33.4': + '@img/sharp-darwin-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.2 + '@img/sharp-libvips-darwin-x64': 1.0.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.0.2': + '@img/sharp-libvips-darwin-arm64@1.0.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.2': + '@img/sharp-libvips-darwin-x64@1.0.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.2': + '@img/sharp-libvips-linux-arm64@1.0.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.2': + '@img/sharp-libvips-linux-arm@1.0.5': optional: true - '@img/sharp-libvips-linux-s390x@1.0.2': + '@img/sharp-libvips-linux-s390x@1.0.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.2': + '@img/sharp-libvips-linux-x64@1.0.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.2': + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.2': + '@img/sharp-libvips-linuxmusl-x64@1.0.4': optional: true - '@img/sharp-linux-arm64@0.33.4': + '@img/sharp-linux-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.2 + '@img/sharp-libvips-linux-arm64': 1.0.4 optional: true - '@img/sharp-linux-arm@0.33.4': + '@img/sharp-linux-arm@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.2 + '@img/sharp-libvips-linux-arm': 1.0.5 optional: true - '@img/sharp-linux-s390x@0.33.4': + '@img/sharp-linux-s390x@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.2 + '@img/sharp-libvips-linux-s390x': 1.0.4 optional: true - '@img/sharp-linux-x64@0.33.4': + '@img/sharp-linux-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.2 + '@img/sharp-libvips-linux-x64': 1.0.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.4': + '@img/sharp-linuxmusl-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.4': + '@img/sharp-linuxmusl-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.2 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 optional: true - '@img/sharp-wasm32@0.33.4': + '@img/sharp-wasm32@0.33.5': dependencies: '@emnapi/runtime': 1.2.0 optional: true - '@img/sharp-win32-ia32@0.33.4': + '@img/sharp-win32-ia32@0.33.5': optional: true - '@img/sharp-win32-x64@0.33.4': + '@img/sharp-win32-x64@0.33.5': optional: true '@jest/schemas@29.6.3': @@ -8154,7 +8248,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -8210,10 +8304,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1)': + '@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 18.3.3 + '@types/react': 18.3.10 react: 18.3.1 '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': @@ -8320,12 +8414,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.25.2) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.25.2) - '@svgr/core@8.1.0(typescript@5.5.4)': + '@svgr/core@8.1.0(typescript@5.6.2)': dependencies: '@babel/core': 7.25.2 '@svgr/babel-preset': 8.1.0(@babel/core@7.25.2) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.5.4) + cosmiconfig: 8.3.6(typescript@5.6.2) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -8336,35 +8430,35 @@ snapshots: '@babel/types': 7.25.2 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.5.4))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.6.2))': dependencies: '@babel/core': 7.25.2 '@svgr/babel-preset': 8.1.0(@babel/core@7.25.2) - '@svgr/core': 8.1.0(typescript@5.5.4) + '@svgr/core': 8.1.0(typescript@5.6.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.5.4))(typescript@5.5.4)': + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.6.2))(typescript@5.6.2)': dependencies: - '@svgr/core': 8.1.0(typescript@5.5.4) - cosmiconfig: 8.3.6(typescript@5.5.4) + '@svgr/core': 8.1.0(typescript@5.6.2) + cosmiconfig: 8.3.6(typescript@5.6.2) deepmerge: 4.3.1 svgo: 3.3.2 transitivePeerDependencies: - typescript - '@svgr/webpack@8.1.0(typescript@5.5.4)': + '@svgr/webpack@8.1.0(typescript@5.6.2)': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-react-constant-elements': 7.25.1(@babel/core@7.25.2) '@babel/preset-env': 7.25.3(@babel/core@7.25.2) '@babel/preset-react': 7.24.7(@babel/core@7.25.2) '@babel/preset-typescript': 7.24.7(@babel/core@7.25.2) - '@svgr/core': 8.1.0(typescript@5.5.4) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4))(typescript@5.5.4) + '@svgr/core': 8.1.0(typescript@5.6.2) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.6.2)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.6.2))(typescript@5.6.2) transitivePeerDependencies: - supports-color - typescript @@ -8382,20 +8476,20 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/bonjour@3.5.13': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 4.19.5 - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/connect@3.4.38': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/debug@4.1.12': dependencies: @@ -8417,9 +8511,11 @@ snapshots: '@types/estree@1.0.5': {} + '@types/estree@1.0.6': {} + '@types/express-serve-static-core@4.19.5': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -8447,7 +8543,7 @@ snapshots: '@types/http-proxy@1.17.15': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/istanbul-lib-coverage@2.0.6': {} @@ -8483,13 +8579,13 @@ snapshots: '@types/node-forge@1.3.11': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/node@17.0.45': {} - '@types/node@22.2.0': + '@types/node@22.7.4': dependencies: - undici-types: 6.13.0 + undici-types: 6.19.8 '@types/normalize-package-data@2.4.4': {} @@ -8505,26 +8601,26 @@ snapshots: '@types/react-dom@18.3.0': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-router-config@5.0.11': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-router': 5.1.20 '@types/react-router-dom@5.3.3': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-router': 5.1.20 '@types/react-router@5.1.20': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@types/react@18.3.3': + '@types/react@18.3.10': dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 @@ -8533,14 +8629,14 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/semver@7.5.8': {} '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/serve-index@1.9.4': dependencies: @@ -8549,20 +8645,22 @@ snapshots: '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/send': 0.17.4 '@types/sockjs@0.3.36': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/unist@2.0.10': {} '@types/unist@3.0.2': {} + '@types/unist@3.0.3': {} + '@types/ws@8.5.12': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 '@types/yargs-parser@21.0.3': {} @@ -8570,13 +8668,13 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0)(typescript@5.5.4)': + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)(typescript@5.6.2)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.5.4) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@7.32.0)(typescript@5.5.4) - '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.5.4) + '@typescript-eslint/type-utils': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.6.2) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.6 eslint: 7.32.0 @@ -8584,22 +8682,22 @@ snapshots: ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.5.4) + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4)': + '@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2)': dependencies: '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.2) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.6 eslint: 7.32.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color @@ -8608,21 +8706,21 @@ snapshots: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/type-utils@6.21.0(eslint@7.32.0)(typescript@5.5.4)': + '@typescript-eslint/type-utils@6.21.0(eslint@7.32.0)(typescript@5.6.2)': dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.4) - '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.2) + '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.6.2) debug: 4.3.6 eslint: 7.32.0 - ts-api-utils: 1.3.0(typescript@5.5.4) + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.5.4)': + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.2)': dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 @@ -8631,20 +8729,20 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.5.4) + ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.21.0(eslint@7.32.0)(typescript@5.5.4)': + '@typescript-eslint/utils@6.21.0(eslint@7.32.0)(typescript@5.6.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@7.32.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.2) eslint: 7.32.0 semver: 7.6.3 transitivePeerDependencies: @@ -8797,7 +8895,7 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - algoliasearch-helper@3.22.3(algoliasearch@4.24.0): + algoliasearch-helper@3.22.5(algoliasearch@4.24.0): dependencies: '@algolia/events': 4.0.1 algoliasearch: 4.24.0 @@ -8944,7 +9042,7 @@ snapshots: caniuse-lite: 1.0.30001651 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.0.1 + picocolors: 1.1.0 postcss: 8.4.41 postcss-value-parser: 4.2.0 @@ -9100,6 +9198,13 @@ snapshots: node-releases: 2.0.18 update-browserslist-db: 1.1.0(browserslist@4.23.3) + browserslist@4.24.0: + dependencies: + caniuse-lite: 1.0.30001664 + electron-to-chromium: 1.5.29 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.0) + buffer-from@1.1.2: {} buffer@5.7.1: @@ -9162,6 +9267,8 @@ snapshots: caniuse-lite@1.0.30001651: {} + caniuse-lite@1.0.30001664: {} + ccount@2.0.1: {} chalk@2.4.2: @@ -9222,6 +9329,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.1: + dependencies: + readdirp: 4.0.1 + chownr@1.1.4: {} chrome-trace-event@1.0.4: {} @@ -9398,14 +9509,14 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - cosmiconfig@8.3.6(typescript@5.5.4): + cosmiconfig@8.3.6(typescript@5.6.2): dependencies: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 cross-spawn@7.0.3: dependencies: @@ -9487,7 +9598,7 @@ snapshots: cssnano-preset-advanced@6.1.2(postcss@8.4.41): dependencies: autoprefixer: 10.4.20(postcss@8.4.41) - browserslist: 4.23.3 + browserslist: 4.24.0 cssnano-preset-default: 6.1.2(postcss@8.4.41) postcss: 8.4.41 postcss-discard-unused: 6.0.5(postcss@8.4.41) @@ -9679,11 +9790,11 @@ snapshots: dependencies: esutils: 2.0.3 - docusaurus-plugin-sass@0.2.5(@docusaurus/core@3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(sass@1.77.8)(webpack@5.93.0): + docusaurus-plugin-sass@0.2.5(@docusaurus/core@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(sass@1.79.3)(webpack@5.93.0): dependencies: - '@docusaurus/core': 3.5.1(@docusaurus/types@3.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) - sass: 1.77.8 - sass-loader: 10.5.2(sass@1.77.8)(webpack@5.93.0) + '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + sass: 1.79.3 + sass-loader: 10.5.2(sass@1.79.3)(webpack@5.93.0) transitivePeerDependencies: - fibers - node-sass @@ -9744,6 +9855,8 @@ snapshots: ee-first@1.1.1: {} + electron-to-chromium@1.5.29: {} + electron-to-chromium@1.5.6: {} emoji-regex@8.0.0: {} @@ -9859,6 +9972,8 @@ snapshots: escalade@3.1.2: {} + escalade@3.2.0: {} + escape-goat@4.0.0: {} escape-html@1.0.3: {} @@ -9873,9 +9988,9 @@ snapshots: dependencies: eslint: 7.32.0 - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)): dependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0) eslint-import-resolver-node@0.3.9: dependencies: @@ -9885,17 +10000,27 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.5.4) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + eslint: 7.32.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0): dependencies: array-includes: 3.1.8 array.prototype.flat: 1.3.2 @@ -9904,7 +10029,7 @@ snapshots: doctrine: 2.1.0 eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) find-up: 2.1.0 has: 1.0.4 is-core-module: 2.15.0 @@ -9915,13 +10040,13 @@ snapshots: resolve: 1.22.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.5.4) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -9931,9 +10056,9 @@ snapshots: doctrine: 2.1.0 eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) hasown: 2.0.2 - is-core-module: 2.15.0 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 @@ -9942,7 +10067,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.5.4) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -10103,7 +10228,7 @@ snapshots: estree-util-value-to-estree@3.1.2: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 estree-util-visit@2.0.0: dependencies: @@ -10122,7 +10247,7 @@ snapshots: eval@0.1.8: dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 require-like: 0.1.2 eventemitter3@4.0.7: {} @@ -10249,6 +10374,12 @@ snapshots: schema-utils: 3.3.0 webpack: 5.93.0 + file-loader@6.2.0(webpack@5.95.0): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.95.0 + filesize@8.0.7: {} fill-range@7.1.1: @@ -10311,7 +10442,7 @@ snapshots: dependencies: is-callable: 1.2.7 - fork-ts-checker-webpack-plugin@6.5.3(eslint@7.32.0)(typescript@5.5.4)(webpack@5.93.0): + fork-ts-checker-webpack-plugin@6.5.3(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0): dependencies: '@babel/code-frame': 7.24.7 '@types/json-schema': 7.0.15 @@ -10326,7 +10457,7 @@ snapshots: schema-utils: 2.7.0 semver: 7.6.3 tapable: 1.1.3 - typescript: 5.5.4 + typescript: 5.6.2 webpack: 5.93.0 optionalDependencies: eslint: 7.32.0 @@ -10533,11 +10664,11 @@ snapshots: hast-util-from-parse5@8.0.1: dependencies: '@types/hast': 3.0.4 - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 devlop: 1.1.0 hastscript: 8.0.0 property-information: 6.5.0 - vfile: 6.0.2 + vfile: 6.0.3 vfile-location: 5.0.3 web-namespaces: 2.0.1 @@ -10548,7 +10679,7 @@ snapshots: hast-util-raw@9.0.4: dependencies: '@types/hast': 3.0.4 - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 '@ungap/structured-clone': 1.2.0 hast-util-from-parse5: 8.0.1 hast-util-to-parse5: 8.0.0 @@ -10557,7 +10688,7 @@ snapshots: parse5: 7.1.2 unist-util-position: 5.0.0 unist-util-visit: 5.0.0 - vfile: 6.0.2 + vfile: 6.0.3 web-namespaces: 2.0.1 zwitch: 2.0.4 @@ -10888,6 +11019,10 @@ snapshots: dependencies: hasown: 2.0.2 + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + is-data-view@1.0.1: dependencies: is-typed-array: 1.1.13 @@ -11003,7 +11138,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.2.0 + '@types/node': 22.7.4 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -11011,13 +11146,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 22.2.0 + '@types/node': 22.7.4 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -11102,7 +11237,7 @@ snapshots: launch-editor@2.8.1: dependencies: - picocolors: 1.0.1 + picocolors: 1.1.0 shell-quote: 1.8.1 leven@3.1.0: {} @@ -11202,7 +11337,7 @@ snapshots: mdast-util-directive@3.0.0: dependencies: '@types/mdast': 4.0.4 - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 devlop: 1.1.0 mdast-util-from-markdown: 2.0.1 mdast-util-to-markdown: 2.1.0 @@ -11247,7 +11382,7 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-gfm-autolink-literal@2.0.0: + mdast-util-gfm-autolink-literal@2.0.1: dependencies: '@types/mdast': 4.0.4 ccount: 2.0.1 @@ -11295,7 +11430,7 @@ snapshots: mdast-util-gfm@3.0.0: dependencies: mdast-util-from-markdown: 2.0.1 - mdast-util-gfm-autolink-literal: 2.0.0 + mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.0.0 mdast-util-gfm-strikethrough: 2.0.0 mdast-util-gfm-table: 2.0.0 @@ -11440,7 +11575,7 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 - micromark-extension-directive@3.0.1: + micromark-extension-directive@3.0.2: dependencies: devlop: 1.1.0 micromark-factory-space: 2.0.0 @@ -11721,6 +11856,11 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + mime-db@1.33.0: {} mime-db@1.52.0: {} @@ -12084,7 +12224,7 @@ snapshots: estree-walker: 3.0.3 is-reference: 3.0.2 - picocolors@1.0.1: {} + picocolors@1.1.0: {} picomatch@2.3.1: {} @@ -12151,11 +12291,11 @@ snapshots: postcss-discard-unused@6.0.5(postcss@8.4.41): dependencies: postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + postcss-selector-parser: 6.1.2 - postcss-loader@7.3.4(postcss@8.4.41)(typescript@5.5.4)(webpack@5.93.0): + postcss-loader@7.3.4(postcss@8.4.41)(typescript@5.6.2)(webpack@5.93.0): dependencies: - cosmiconfig: 8.3.6(typescript@5.5.4) + cosmiconfig: 8.3.6(typescript@5.6.2) jiti: 1.21.6 postcss: 8.4.41 semver: 7.6.3 @@ -12312,6 +12452,11 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-sort-media-queries@5.2.0(postcss@8.4.41): dependencies: postcss: 8.4.41 @@ -12341,7 +12486,7 @@ snapshots: postcss@8.4.41: dependencies: nanoid: 3.3.7 - picocolors: 1.0.1 + picocolors: 1.1.0 source-map-js: 1.2.0 prebuild-install@7.1.2: @@ -12373,7 +12518,7 @@ snapshots: pretty-time@1.1.0: {} - prism-react-renderer@2.3.1(react@18.3.1): + prism-react-renderer@2.4.0(react@18.3.1): dependencies: '@types/prismjs': 1.26.4 clsx: 2.1.1 @@ -12418,11 +12563,11 @@ snapshots: dependencies: escape-goat: 4.0.0 - pushfeedback-react@0.1.40: + pushfeedback-react@0.1.44: dependencies: - pushfeedback: 0.1.40 + pushfeedback: 0.1.44 - pushfeedback@0.1.40: + pushfeedback@0.1.44: dependencies: '@stencil/core': 2.22.3 html2canvas: 1.4.1 @@ -12470,7 +12615,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dev-utils@12.0.1(eslint@7.32.0)(typescript@5.5.4)(webpack@5.93.0): + react-dev-utils@12.0.1(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0): dependencies: '@babel/code-frame': 7.24.7 address: 1.2.2 @@ -12481,7 +12626,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@7.32.0)(typescript@5.5.4)(webpack@5.93.0) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -12498,7 +12643,7 @@ snapshots: text-table: 0.2.0 webpack: 5.93.0 optionalDependencies: - typescript: 5.5.4 + typescript: 5.6.2 transitivePeerDependencies: - eslint - supports-color @@ -12540,7 +12685,7 @@ snapshots: react-is@18.3.1: {} - react-json-view-lite@1.4.0(react@18.3.1): + react-json-view-lite@1.5.0(react@18.3.1): dependencies: react: 18.3.1 @@ -12649,6 +12794,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.1: {} + reading-time@1.5.0: {} rechoir@0.6.2: @@ -12712,7 +12859,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 hast-util-raw: 9.0.4 - vfile: 6.0.2 + vfile: 6.0.3 relateurl@0.2.7: {} @@ -12720,7 +12867,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 mdast-util-directive: 3.0.0 - micromark-extension-directive: 3.0.1 + micromark-extension-directive: 3.0.2 unified: 11.0.5 transitivePeerDependencies: - supports-color @@ -12847,7 +12994,7 @@ snapshots: rtlcss@4.2.0: dependencies: escalade: 3.1.2 - picocolors: 1.0.1 + picocolors: 1.1.0 postcss: 8.4.41 strip-json-comments: 3.1.1 @@ -12884,7 +13031,7 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@10.5.2(sass@1.77.8)(webpack@5.93.0): + sass-loader@10.5.2(sass@1.79.3)(webpack@5.93.0): dependencies: klona: 2.0.6 loader-utils: 2.0.4 @@ -12893,11 +13040,11 @@ snapshots: semver: 7.6.3 webpack: 5.93.0 optionalDependencies: - sass: 1.77.8 + sass: 1.79.3 - sass@1.77.8: + sass@1.79.3: dependencies: - chokidar: 3.6.0 + chokidar: 4.0.1 immutable: 4.3.7 source-map-js: 1.2.0 @@ -13048,31 +13195,31 @@ snapshots: tar-fs: 3.0.6 tunnel-agent: 0.6.0 - sharp@0.33.4: + sharp@0.33.5: dependencies: color: 4.2.3 detect-libc: 2.0.3 semver: 7.6.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.4 - '@img/sharp-darwin-x64': 0.33.4 - '@img/sharp-libvips-darwin-arm64': 1.0.2 - '@img/sharp-libvips-darwin-x64': 1.0.2 - '@img/sharp-libvips-linux-arm': 1.0.2 - '@img/sharp-libvips-linux-arm64': 1.0.2 - '@img/sharp-libvips-linux-s390x': 1.0.2 - '@img/sharp-libvips-linux-x64': 1.0.2 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.2 - '@img/sharp-libvips-linuxmusl-x64': 1.0.2 - '@img/sharp-linux-arm': 0.33.4 - '@img/sharp-linux-arm64': 0.33.4 - '@img/sharp-linux-s390x': 0.33.4 - '@img/sharp-linux-x64': 0.33.4 - '@img/sharp-linuxmusl-arm64': 0.33.4 - '@img/sharp-linuxmusl-x64': 0.33.4 - '@img/sharp-wasm32': 0.33.4 - '@img/sharp-win32-ia32': 0.33.4 - '@img/sharp-win32-x64': 0.33.4 + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 shebang-command@2.0.0: dependencies: @@ -13324,53 +13471,53 @@ snapshots: postcss: 8.4.41 postcss-selector-parser: 6.1.1 - stylelint-config-recess-order@4.6.0(stylelint@15.11.0(typescript@5.5.4)): + stylelint-config-recess-order@4.6.0(stylelint@15.11.0(typescript@5.6.2)): dependencies: - stylelint: 15.11.0(typescript@5.5.4) - stylelint-order: 6.0.4(stylelint@15.11.0(typescript@5.5.4)) + stylelint: 15.11.0(typescript@5.6.2) + stylelint-order: 6.0.4(stylelint@15.11.0(typescript@5.6.2)) - stylelint-config-recommended-scss@13.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.5.4)): + stylelint-config-recommended-scss@13.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)): dependencies: postcss-scss: 4.0.9(postcss@8.4.41) - stylelint: 15.11.0(typescript@5.5.4) - stylelint-config-recommended: 13.0.0(stylelint@15.11.0(typescript@5.5.4)) - stylelint-scss: 5.3.2(stylelint@15.11.0(typescript@5.5.4)) + stylelint: 15.11.0(typescript@5.6.2) + stylelint-config-recommended: 13.0.0(stylelint@15.11.0(typescript@5.6.2)) + stylelint-scss: 5.3.2(stylelint@15.11.0(typescript@5.6.2)) optionalDependencies: postcss: 8.4.41 - stylelint-config-recommended@13.0.0(stylelint@15.11.0(typescript@5.5.4)): + stylelint-config-recommended@13.0.0(stylelint@15.11.0(typescript@5.6.2)): dependencies: - stylelint: 15.11.0(typescript@5.5.4) + stylelint: 15.11.0(typescript@5.6.2) - stylelint-config-standard-scss@11.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.5.4)): + stylelint-config-standard-scss@11.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)): dependencies: - stylelint: 15.11.0(typescript@5.5.4) - stylelint-config-recommended-scss: 13.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.5.4)) - stylelint-config-standard: 34.0.0(stylelint@15.11.0(typescript@5.5.4)) + stylelint: 15.11.0(typescript@5.6.2) + stylelint-config-recommended-scss: 13.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)) + stylelint-config-standard: 34.0.0(stylelint@15.11.0(typescript@5.6.2)) optionalDependencies: postcss: 8.4.41 - stylelint-config-standard@34.0.0(stylelint@15.11.0(typescript@5.5.4)): + stylelint-config-standard@34.0.0(stylelint@15.11.0(typescript@5.6.2)): dependencies: - stylelint: 15.11.0(typescript@5.5.4) - stylelint-config-recommended: 13.0.0(stylelint@15.11.0(typescript@5.5.4)) + stylelint: 15.11.0(typescript@5.6.2) + stylelint-config-recommended: 13.0.0(stylelint@15.11.0(typescript@5.6.2)) - stylelint-order@6.0.4(stylelint@15.11.0(typescript@5.5.4)): + stylelint-order@6.0.4(stylelint@15.11.0(typescript@5.6.2)): dependencies: postcss: 8.4.41 postcss-sorting: 8.0.2(postcss@8.4.41) - stylelint: 15.11.0(typescript@5.5.4) + stylelint: 15.11.0(typescript@5.6.2) - stylelint-scss@5.3.2(stylelint@15.11.0(typescript@5.5.4)): + stylelint-scss@5.3.2(stylelint@15.11.0(typescript@5.6.2)): dependencies: known-css-properties: 0.29.0 postcss-media-query-parser: 0.2.3 postcss-resolve-nested-selector: 0.1.5 postcss-selector-parser: 6.1.1 postcss-value-parser: 4.2.0 - stylelint: 15.11.0(typescript@5.5.4) + stylelint: 15.11.0(typescript@5.6.2) - stylelint@15.11.0(typescript@5.5.4): + stylelint@15.11.0(typescript@5.6.2): dependencies: '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) '@csstools/css-tokenizer': 2.4.1 @@ -13378,7 +13525,7 @@ snapshots: '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.1) balanced-match: 2.0.0 colord: 2.9.3 - cosmiconfig: 8.3.6(typescript@5.5.4) + cosmiconfig: 8.3.6(typescript@5.6.2) css-functions-list: 3.2.2 css-tree: 2.3.1 debug: 4.3.6 @@ -13398,7 +13545,7 @@ snapshots: meow: 10.1.5 micromatch: 4.0.7 normalize-path: 3.0.0 - picocolors: 1.0.1 + picocolors: 1.1.0 postcss: 8.4.41 postcss-resolve-nested-selector: 0.1.5 postcss-safe-parser: 6.0.0(postcss@8.4.41) @@ -13449,7 +13596,7 @@ snapshots: css-tree: 2.3.1 css-what: 6.1.0 csso: 5.0.5 - picocolors: 1.0.1 + picocolors: 1.1.0 table@6.8.2: dependencies: @@ -13501,6 +13648,15 @@ snapshots: terser: 5.31.5 webpack: 5.93.0 + terser-webpack-plugin@5.3.10(webpack@5.95.0): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.31.5 + webpack: 5.95.0 + terser@5.31.5: dependencies: '@jridgewell/source-map': 0.3.6 @@ -13555,9 +13711,9 @@ snapshots: trough@2.2.0: {} - ts-api-utils@1.3.0(typescript@5.5.4): + ts-api-utils@1.3.0(typescript@5.6.2): dependencies: - typescript: 5.5.4 + typescript: 5.6.2 tsconfig-paths@3.15.0: dependencies: @@ -13570,6 +13726,8 @@ snapshots: tslib@2.6.3: {} + tslib@2.7.0: {} + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 @@ -13631,7 +13789,7 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript@5.5.4: {} + typescript@5.6.2: {} unbox-primitive@1.0.2: dependencies: @@ -13640,7 +13798,7 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - undici-types@6.13.0: {} + undici-types@6.19.8: {} unicode-canonical-property-names-ecmascript@2.0.0: {} @@ -13709,7 +13867,13 @@ snapshots: dependencies: browserslist: 4.23.3 escalade: 3.1.2 - picocolors: 1.0.1 + picocolors: 1.1.0 + + update-browserslist-db@1.1.1(browserslist@4.24.0): + dependencies: + browserslist: 4.24.0 + escalade: 3.2.0 + picocolors: 1.1.0 update-notifier@6.0.2: dependencies: @@ -13741,6 +13905,15 @@ snapshots: optionalDependencies: file-loader: 6.2.0(webpack@5.93.0) + url-loader@4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.95.0): + dependencies: + loader-utils: 2.0.4 + mime-types: 2.1.35 + schema-utils: 3.3.0 + webpack: 5.95.0 + optionalDependencies: + file-loader: 6.2.0(webpack@5.93.0) + util-deprecate@1.0.2: {} utila@0.4.0: {} @@ -13768,8 +13941,8 @@ snapshots: vfile-location@5.0.3: dependencies: - '@types/unist': 3.0.2 - vfile: 6.0.2 + '@types/unist': 3.0.3 + vfile: 6.0.3 vfile-message@4.0.2: dependencies: @@ -13782,11 +13955,21 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.2 + watchpack@2.4.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + watchpack@2.4.2: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + wbuf@1.7.3: dependencies: minimalistic-assert: 1.0.1 @@ -13806,7 +13989,7 @@ snapshots: gzip-size: 6.0.0 html-escaper: 2.0.2 opener: 1.5.2 - picocolors: 1.0.1 + picocolors: 1.1.0 sirv: 2.0.4 ws: 7.5.10 transitivePeerDependencies: @@ -13901,6 +14084,36 @@ snapshots: - esbuild - uglify-js + webpack@5.95.0: + dependencies: + '@types/estree': 1.0.6 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.12.1 + acorn-import-attributes: 1.9.5(acorn@8.12.1) + browserslist: 4.24.0 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.5.4 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(webpack@5.95.0) + watchpack: 2.4.2 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + webpackbar@5.0.2(webpack@5.93.0): dependencies: chalk: 4.1.2 diff --git a/src/app/theme.scss b/src/app/theme.scss index 0cd03133b8..e04b3c89c8 100644 --- a/src/app/theme.scss +++ b/src/app/theme.scss @@ -38,3 +38,22 @@ html[data-theme="dark"] { img { height: unset; } + +.alert.file-tree { + padding-top: 0; + padding-bottom: 0; + margin-bottom: 0; + background: none; + border: 0; + box-shadow: none; + + .file-tree & { + padding: 0; + } + + & summary + div > div { + padding-top: 0; + margin-top: 0; + border: 0; + } +} diff --git a/static/img/approaches.png b/static/img/approaches.png deleted file mode 100644 index 82472f5759e94159a652e45b75a823be020f7400..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 129024 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
_|Ij67d58vOICz}f?mmi40l{D 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 z�UPhz!C(>Y)%<k2$(_b!+e%Qzh| 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 Gp$Py(gsKw& From ae9c3868a278e998cd72d21b91896dc654a47b61 Mon Sep 17 00:00:00 2001 From: ratomiru <166593964+ratomiru@users.noreply.github.com> Date: Sun, 29 Sep 2024 20:02:46 +0900 Subject: [PATCH 05/29] feat: Japanese full support (#728) --- DEV.md | 3 + config/docusaurus/i18n.js | 5 +- i18n/ja/code.json | 410 +++ .../community/index.mdx | 40 + .../community/team.mdx | 18 + .../current.json | 54 + .../current/about/alternatives.mdx | 103 + .../current/about/index.mdx | 44 + .../current/about/mission.md | 50 + .../current/about/motivation.md | 133 + .../current/about/promote/_category_.yaml | 3 + .../current/about/promote/for-company.mdx | 10 + .../current/about/promote/for-team.mdx | 10 + .../current/about/promote/integration.mdx | 16 + .../about/promote/partial-application.mdx | 10 + .../about/understanding/_category_.yaml | 2 + .../about/understanding/abstractions.mdx | 18 + .../about/understanding/architecture.md | 94 + .../about/understanding/knowledge-types.md | 23 + .../current/about/understanding/naming.md | 36 + .../about/understanding/needs-driven.md | 153 ++ .../current/about/understanding/signals.mdx | 10 + .../current/branding.md | 80 + .../current/get-started/cheatsheet.mdx | 28 + .../current/get-started/faq.md | 68 + .../current/get-started/index.mdx | 38 + .../current/get-started/overview.mdx | 137 + .../current/get-started/tutorial.md | 2264 +++++++++++++++++ .../current/guides/examples/_category_.yaml | 2 + .../current/guides/examples/auth.md | 229 ++ .../current/guides/examples/autocompleted.mdx | 13 + .../current/guides/examples/browser-api.mdx | 10 + .../current/guides/examples/cms.mdx | 10 + .../current/guides/examples/feedback.mdx | 10 + .../current/guides/examples/i18n.mdx | 11 + .../current/guides/examples/index.mdx | 36 + .../current/guides/examples/metric.mdx | 10 + .../current/guides/examples/monorepo.mdx | 11 + .../current/guides/examples/page-layout.md | 104 + .../current/guides/examples/platforms.mdx | 10 + .../current/guides/examples/ssr.mdx | 10 + .../current/guides/examples/theme.mdx | 11 + .../current/guides/examples/types.md | 436 ++++ .../current/guides/examples/white-labels.mdx | 11 + .../current/guides/index.mdx | 46 + .../current/guides/issues/_category_.yaml | 2 + .../current/guides/issues/cross-imports.mdx | 13 + .../current/guides/issues/desegmented.mdx | 96 + .../current/guides/issues/routes.mdx | 42 + .../current/guides/migration/_category_.yaml | 2 + .../current/guides/migration/from-custom.md | 306 +++ .../current/guides/migration/from-v1.md | 154 ++ .../current/guides/tech/_category_.yaml | 2 + .../current/guides/tech/with-nextjs.mdx | 109 + .../current/guides/tech/with-nuxtjs.mdx | 178 ++ .../current/guides/tech/with-react-query.mdx | 434 ++++ .../current/guides/tech/with-sveltekit.mdx | 96 + .../current/intro.mdx | 69 + .../current/reference/index.mdx | 38 + .../reference/isolation/_category_.yaml | 1 + .../reference/isolation/coupling-cohesion.md | 147 ++ .../reference/isolation/decouple-entities.mdx | 21 + .../current/reference/isolation/index.md | 63 + .../current/reference/layers.mdx | 181 ++ .../current/reference/public-api.md | 216 ++ .../current/reference/slices-segments.mdx | 57 + i18n/ja/docusaurus-theme-classic/footer.json | 66 + i18n/ja/docusaurus-theme-classic/navbar.json | 50 + package.json | 1 + 69 files changed, 7173 insertions(+), 1 deletion(-) create mode 100644 i18n/ja/code.json create mode 100644 i18n/ja/docusaurus-plugin-content-docs/community/index.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/community/team.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current.json create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/alternatives.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/index.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/mission.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/motivation.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/promote/_category_.yaml create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-company.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-team.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/promote/integration.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/promote/partial-application.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/_category_.yaml create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/abstractions.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/architecture.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/knowledge-types.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/naming.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/needs-driven.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/signals.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/branding.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/get-started/cheatsheet.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/get-started/index.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/get-started/overview.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/_category_.yaml create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/autocompleted.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/browser-api.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/cms.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/feedback.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/i18n.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/index.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/metric.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/monorepo.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/platforms.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/ssr.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/theme.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/white-labels.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/index.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/_category_.yaml create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/cross-imports.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/desegmented.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/routes.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/_category_.yaml create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/_category_.yaml create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/intro.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/layers.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/public-api.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx create mode 100644 i18n/ja/docusaurus-theme-classic/footer.json create mode 100644 i18n/ja/docusaurus-theme-classic/navbar.json diff --git a/DEV.md b/DEV.md index c9c70bdf51..c540678a38 100644 --- a/DEV.md +++ b/DEV.md @@ -7,6 +7,7 @@ This website is built using [Docusaurus 2](https://docusaurus.io/), a modern sta - [Russian docs version](i18n/ru) - [English docs version](i18n/en) - [Uzbek docs version](i18n/uz) +- [Japanese docs version](i18n/ja) ## Installation @@ -20,6 +21,8 @@ pnpm install pnpm start # for default locale pnpm start:ru # for RU locale pnpm start:en # for EN locale +pnpm start:uz # for UZ locale +pnpm start:ja # for JA locale ``` > About [docusaurus/i18n commands](https://docusaurus.io/docs/i18n/git#translate-the-files) diff --git a/config/docusaurus/i18n.js b/config/docusaurus/i18n.js index bea96e6a50..2cef5f9050 100644 --- a/config/docusaurus/i18n.js +++ b/config/docusaurus/i18n.js @@ -3,7 +3,7 @@ const { DEFAULT_LOCALE } = require("./consts"); /** @type {import('@docusaurus/types').DocusaurusConfig["i18n"]} */ const i18n = { defaultLocale: DEFAULT_LOCALE, - locales: ["ru", "en", "uz", "kr"], + locales: ["ru", "en", "uz", "kr", "ja"], localeConfigs: { ru: { label: "Русский", @@ -17,6 +17,9 @@ const i18n = { kr: { label: "한국어", }, + ja: { + label: "日本語", + }, }, }; diff --git a/i18n/ja/code.json b/i18n/ja/code.json new file mode 100644 index 0000000000..738036b4d7 --- /dev/null +++ b/i18n/ja/code.json @@ -0,0 +1,410 @@ +{ + "pages.home.features.title": { + "message": "利点", + "description": "Features" + }, + "pages.home.features.logic.title": { + "message": "明確なビジネスロジック", + "description": "Feature title" + }, + "pages.home.features.logic.description": { + "message": "アーキテクチャはドメインモジュールで構成されているため、習得が容易である", + "description": "Feature description" + }, + "pages.home.features.adaptability.title": { + "message": "適応性", + "description": "Feature title" + }, + "pages.home.features.adaptability.description": { + "message": "アーキテクチャのコンポーネントは柔軟に交換したり、新しい条件に応じて追加したりすることができる", + "description": "Feature description" + }, + "pages.home.features.debt.title": { + "message": "技術的負債", + "description": "Feature title" + }, + "pages.home.features.debt.description": { + "message": "各モジュールは副作用なしに独立して変更/再作成できる", + "description": "Feature description" + }, + "pages.home.features.shared.title": { + "message": "明確な再利用性", + "description": "Feature title" + }, + "pages.home.features.shared.description": { + "message": "DRYとローカルカスタマイズのバランスが保たれている", + "description": "Feature description" + }, + "pages.home.concepts.title": { + "message": "コンセプト", + "description": "Concepts" + }, + "pages.home.concepts.public.title": { + "message": "公開API", + "description": "Concept title" + }, + "pages.home.concepts.public.description": { + "message": "各モジュールはその公開APIをトップレベルで宣言する必要がある", + "description": "Concept description" + }, + "pages.home.concepts.isolation.title": { + "message": "分離", + "description": "Concept title" + }, + "pages.home.concepts.isolation.description": { + "message": "モジュールは同じレイヤーや上層レイヤーの他のモジュールに直接依存してはいけない", + "description": "Concept description" + }, + "pages.home.concepts.needs.title": { + "message": "ニーズの理解", + "description": "Concept title" + }, + "pages.home.concepts.needs.description": { + "message": "ビジネスとユーザーのニーズに焦点を当てる", + "description": "Concept description" + }, + "pages.home.scheme.title": { + "message": "構造", + "description": "Scheme" + }, + "pages.home.companies.using": { + "message": "FSDを使用している企業", + "description": "Companies using methodology" + }, + "pages.home.companies.add_me": { + "message": "あなたの会社でFSDが使用されていますか?", + "description": "Methodology is used in your company?" + }, + "pages.home.companies.tell_us": { + "message": "教えてください", + "description": "Tell us" + }, + "pages.examples.title": { + "message": "実装例", + "description": "Page title" + }, + "pages.examples.subtitle": { + "message": "FSDを使って作られたプロジェクト一覧", + "description": "Page subtitle" + }, + "pages.examples.add_me.title": { + "message": "実装例を追加", + "description": "Request to add example" + }, + "pages.examples.repo.title": { + "message": "リポジトリ", + "description": "Examples repository label" + }, + "pages.examples.versions": { + "message": "バージョン一覧も参照してください", + "description": "Versions reminder" + }, + "pages.versions.title": { + "message": "Feature-Sliced Designのバージョン", + "description": "Feature-Sliced Design versions" + }, + "pages.versions.current": { + "message": "ここで現在公開されているバージョンのドキュメントを見つけることができます", + "description": "Description for current version" + }, + "pages.versions.legacy": { + "message": "ここで古いバージョンのドキュメントを見つけることができます", + "description": "Description for legacy version" + }, + "pages.nav.title": { + "message": "🧭 ナビゲーション", + "description": "NavPage title" + }, + "pages.nav.legacy.title": { + "message": "古いリンク", + "description": "NavPage section=legacy title" + }, + "pages.nav.legacy.details": { + "message": "ドキュメントの再構成後、一部の記事リンクが変更されました。以下に探しているページが見つかるかもしれません。", + "description": "NavPage section=legacy details" + }, + "pages.nav.legacy.subdetails": { + "message": "互換性のために古いリンクからのリダイレクトがあります", + "description": "NavPage section=legacy subdetails" + }, + "features.feedback-badge.label": { + "message": "ドキュメントのフィードバックを共有する 🤙", + "description": "Feedback share button label" + }, + "features.feedback-badge.url": { + "message": "https://forms.gle/7p4anU2shHAzmfqc8", + "description": "Feedback share form url" + }, + "features.feedback-doc.thanks": { + "message": "フィードバックありがとうございます!", + "description": "DocFeedback block=Thanks" + }, + "features.feedback-doc.title": { + "message": "このページは役に立ちましたか?", + "description": "DocFeedback block=Title" + }, + "features.feedback-doc.subtitle": { + "message": "あなたのフィードバックはドキュメントの改善に役立ちます", + "description": "DocFeedback block=Subtitle" + }, + "features.feedback-doc.button-text": { + "message": "フィードバックを送る", + "description": "The text on a floating button to leave feedback about the docs" + }, + "features.feedback-doc.email-placeholder": { + "message": "メールアドレスを入力してください(任意)", + "description": "The placeholder for email input" + }, + "features.feedback-doc.error-message": { + "message": "後でもう一度お試しください。", + "description": "The error message displayed when feedback form submission fails" + }, + "features.feedback-doc.modal-title-error-403": { + "message": "リクエストURLがこのプロジェクトのPushFeedbackに指定されたURLと一致しません。", + "description": "The title of the modal displayed when the feedback form submission fails with 403 error" + }, + "features.feedback-doc.modal-title-error-404": { + "message": "提供されたプロジェクトIDをPushFeedbackで見つけることができませんでした。", + "description": "The title of the modal displayed when the feedback form submission fails with 404 error" + }, + "features.feedback-doc.message-placeholder": { + "message": "ここにフィードバックを書いてください…", + "description": "The placeholder for message input" + }, + "features.feedback-doc.modal-title": { + "message": "あなたの意見を共有してください", + "description": "The title of the modal displayed when the feedback form is opened" + }, + "features.feedback-doc.modal-title-error": { + "message": "おっと!", + "description": "The title of the modal displayed when the feedback form submission fails" + }, + "features.feedback-doc.modal-title-success": { + "message": "フィードバックありがとうございます!", + "description": "The title of the modal displayed when the feedback form submission is successful" + }, + "features.feedback-doc.rating-placeholder": { + "message": "このページは役に立ちましたか?", + "description": "The placeholder for rating input" + }, + "features.feedback-doc.rating-stars-placeholder": { + "message": "このページをどう評価しますか", + "description": "The placeholder for rating stars input" + }, + "features.feedback-doc.screenshot-button-text": { + "message": "スクリーンショットを撮る", + "description": "The text on a button to take a screenshot" + }, + "features.feedback-doc.screenshot-topbar-text": { + "message": "ページ上の要素を選択してください", + "description": "The text displayed in the top bar of the screenshot tool" + }, + "features.feedback-doc.send-button-text": { + "message": "送信", + "description": "The text on a button to send feedback" + }, + "features.hero.tagline": { + "message": "フロントエンドアーキテクチャの設計方法論", + "description": "Architectural methodology for frontend projects" + }, + "features.hero.get_started": { + "message": "始める", + "description": "Get Started" + }, + "features.hero.examples": { + "message": "実装例", + "description": "Examples" + }, + "features.hero.previous": { + "message": "前のバージョン", + "description": "Previous version" + }, + "shared.wip.title": { + "message": "この記事は執筆中です", + "description": "Admonition title" + }, + "shared.wip.subtitle": { + "message": "その公開を早めるために、以下の方法があります。", + "description": "Admonition subtitle" + }, + "shared.wip.var.feedback.base": { + "message": "📢 フィードバックを共有する ", + "description": "Variant for contribute (base)" + }, + "shared.wip.var.feedback.link": { + "message": "(チケットでのコメント/絵文字リアクション)", + "description": "Variant for contribute (link)" + }, + "shared.wip.var.material.base": { + "message": "💬 チャットでの議論結果をチケットにまとめる ", + "description": "Variant for contribute (base)" + }, + "shared.wip.var.material.link": { + "message": "(チャットURL)", + "description": "Variant for contribute (link)" + }, + "shared.wip.var.contribute.base": { + "message": "⚒️ 他の方法で", + "description": "Variant for contribute (base)" + }, + "shared.wip.var.contribute.link": { + "message": "貢献する", + "description": "Variant for contribute (link)" + }, + "theme.NotFound.title": { + "message": "ページが見つかりません", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "申し訳ありませんが、リクエストされたページが見つかりませんでした。", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "リンク元のサイトの所有者に連絡して、リンクが機能しないことを知らせてください。", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "閉じる", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "ブログリストページのナビゲーション", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "次のエントリ", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "前のエントリ", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.readingTime.plurals": { + "message": "{readingTime} 分の読書", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.tags.tagsListLabel": { + "message": "タグ:", + "description": "The label alongside a tag list" + }, + "theme.blog.post.readMore": { + "message": "続きを読む", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "ブログ投稿ページのナビゲーション", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "次の投稿", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "前の投稿", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.tags.tagsPageTitle": { + "message": "タグ", + "description": "The title of the tag list page" + }, + "theme.blog.post.plurals": { + "message": "{count} 投稿|{count} 投稿|{count} 投稿", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} のタグ \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "すべてのタグを見る", + "description": "The label of the link targeting the tag list page" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "クリップボードにコピー", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copied": { + "message": "コピーしました", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copy": { + "message": "コピー", + "description": "The copy button label on code blocks" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "サイドバーを展開", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "サイドバーを展開", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "ドキュメントページのナビゲーション", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "前のページ", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "次のページ", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "サイドバーを折りたたむ", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "サイドバーを折りたたむ", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.responsiveCloseButtonLabel": { + "message": "メニューを閉じる", + "description": "The ARIA label for close button of mobile doc sidebar" + }, + "theme.docs.sidebar.responsiveOpenButtonLabel": { + "message": "メニューを開く", + "description": "The ARIA label for open button of mobile doc sidebar" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "これは{siteTitle} {versionLabel}の将来のバージョンのドキュメントです。", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "これは{siteTitle}の{versionLabel}バージョンのドキュメントで、現在はサポートされていません。", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "最新のドキュメントは{latestVersionLink}({versionLabel})にあります。", + "description": "The label userd to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "最新バージョン", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "このページを編集", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "この見出しへの直接リンク", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "最終更新{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.common.skipToMainContent": { + "message": "メインコンテンツにスキップ", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + } +} diff --git a/i18n/ja/docusaurus-plugin-content-docs/community/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/community/index.mdx new file mode 100644 index 0000000000..713ae1b412 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/community/index.mdx @@ -0,0 +1,40 @@ +--- +hide_table_of_contents: true +--- + +# 💫 コミュニティ + +

+コミュニティリソースと追加資料 +

+ +## メイン {#main} + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { StarOutlined, SearchOutlined, TeamOutlined, VerifiedOutlined } from "@ant-design/icons"; + + + + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/community/team.mdx b/i18n/ja/docusaurus-plugin-content-docs/community/team.mdx new file mode 100644 index 0000000000..718318bd8c --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/community/team.mdx @@ -0,0 +1,18 @@ +--- +sidebar_class_name: sidebar-item--wip +sidebar_position: 2 +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# チーム + + + +## コアチーム + +### チャンピオンズ {#champions} + +## コントリビューター {#contributors} + +## 会社 {#companies} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current.json b/i18n/ja/docusaurus-plugin-content-docs/current.json new file mode 100644 index 0000000000..d991f18054 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,54 @@ +{ + "version.label": { + "message": "v2.0.0 🍰", + "description": "現在のバージョンのラベル" + }, + "sidebar.getstartedSidebar.category.🚀 Get Started": { + "message": "🚀 はじめに", + "description": "サイドバーの「はじめに」カテゴリのラベル" + }, + "sidebar.guidesSidebar.category.🎯 Guides": { + "message": "🎯 ガイド", + "description": "サイドバーの「ガイド」カテゴリのラベル" + }, + "sidebar.referenceSidebar.category.📚 Reference": { + "message": "📚 参考書", + "description": "サイドバーの「参考書」カテゴリのラベル" + }, + "sidebar.aboutSidebar.category.🍰 About": { + "message": "🍰 メソッドについて", + "description": "サイドバーの「メソッドについて」カテゴリのラベル" + }, + "sidebar.aboutSidebar.category.Understanding": { + "message": "理解", + "description": "サイドバーの「理解」カテゴリのラベル" + }, + "sidebar.aboutSidebar.category.Promote": { + "message": "推進", + "description": "サイドバーの「推進」カテゴリのラベル" + }, + "sidebar.guidesSidebar.category.Examples": { + "message": "実装例", + "description": "サイドバーの「例」カテゴリのラベル" + }, + "sidebar.guidesSidebar.category.Migration": { + "message": "移行", + "description": "サイドバーの「移行」カテゴリのラベル" + }, + "sidebar.guidesSidebar.category.Tech": { + "message": "技術", + "description": "サイドバーの「技術」カテゴリのラベル" + }, + "sidebar.referenceSidebar.category.Units": { + "message": "ユニット", + "description": "サイドバーの「ユニット」カテゴリのラベル" + }, + "sidebar.referenceSidebar.category.Isolation": { + "message": "分離", + "description": "サイドバーの「分離」カテゴリのラベル" + }, + "sidebar.referenceSidebar.category.Layer": { + "message": "レイヤー", + "description": "サイドバーの「レイヤー」カテゴリのラベル" + } +} diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/alternatives.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/alternatives.mdx new file mode 100644 index 0000000000..4074abbdf7 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/alternatives.mdx @@ -0,0 +1,103 @@ +--- +sidebar_class_name: sidebar-item--wip +sidebar_position: 3 +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# 代替案 + + + +## ビッグボールオブマッド + + + +- [(記事) DDD - Big Ball of mud](https://thedomaindrivendesign.io/big-ball-of-mud/) + + +## スマート&ダムコンポーネント + + + +- [(記事) Dan Abramov - Presentational and Container Components (TLDR: 非推奨)](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) + + +## デザイン原則 + + + +## DDD + + + +## 参照 {#see-also} + +- [(記事) DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together](https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/) + +## クリーンアーキテクチャ + + + +- [(記事) DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together](https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/) + +## フレームワーク + + + +- [(記事) FSDの作成理由 (フレームワークに関する断片)](/docs/about/motivation) + + +## Atomic Design + +### これは何か? + +アトミックデザインでは、責任の範囲が標準化された層に分かれています。 + +アトミックデザインは**5つの層**に分かれます(上から下へ)。 + +1. `pages` - FSDの`pages`層と同様の目的を持つ。 +2. `templates` - コンテンツに依存しないページの構造を定義するコンポーネント。 +3. `organisms` - ビジネスロジックを持つ分子から構成されるモジュール。 +4. `molecules` - 通常、ビジネスロジックを持たないより複雑なコンポーネント。 +5. `atoms` - ビジネスロジックを持たないUIコンポーネント。 + +同じ層のモジュールは、FSDのように下の層のモジュールとだけ相互作用しています。 +つまり、分子(molecule)は原子(atom)から構築され、生命体(organism)は分子から、テンプレート(template)は生命体から、ページ(page)はテンプレートから構築されます。 +また、アトミックデザインはモジュール内での**公開API**の使用を前提としています。 + +### フロントエンドでの適用性 +アトミックデザインはプロジェクトで比較的よく見られます。アトミックデザインは、開発者の間というより、ウェブデザイナーの間で人気です。ウェブデザイナーは、スケーラブルでメンテナンスしやすいデザインを作成するためにアトミックデザインをよく使用しています。 +開発では、アトミックデザインは他のアーキテクチャ設計方法論と混合されることがよくあります。 + +しかし、アトミックデザインはUIコンポーネントとその構成に焦点を当てているため、 +アーキテクチャ内でビジネスロジックを実装する問題が発生してしまいます。 + +問題は、アトミックデザインがビジネスロジックのための明確な責任レベルを提供していないため、 +ビジネスロジックがさまざまなコンポーネントやレベルに分散され、メンテナンスやテストが複雑になることです。 +ビジネスロジックは曖昧になり、責任の明確な分離が困難になり、コードがモジュール化されず再利用可能でなくなります。 + +### FSDとの統合 +FSDの文脈では、アトミックデザインのいくつかの要素を使用して柔軟でスケーラブルなUIコンポーネントを作成することができます。 `atoms`と`molecules`の層は、FSDの`shared/ui`に実装でき、基本的なUI要素の再利用とメンテナンスを簡素化しています。 + +```sh +├── shared +│   ├── ui  +│   │   ├── atoms +│   │   ├── molecules +│   ... +``` + +FSDとアトミックデザインの比較は、両方の設計方法論がモジュール性と再利用性を目指していることを示していますが、 +異なる側面に焦点を当てています。アトミックデザインは視覚的コンポーネントとその構成に焦点を当てています。 +FSDはアプリケーションの機能を独立したモジュールに分割し、それらの相互関係に焦点を当てています。 + +- [Atomic Design](https://atomicdesign.bradfrost.com/table-of-contents/) +- [(動画) Atomic Design: What is it and why is it important?](https://youtu.be/Yi-A20x2dcA) + +## Feature Driven + + + +- [(講演) Feature Driven Architecture - Oleg Isonen](https://youtu.be/BWAeYuWFHhs) +- [Feature Driven-Short specification (from the point of view of FSD)](https://github.com/feature-sliced/documentation/tree/rc/feature-driven) diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/index.mdx new file mode 100644 index 0000000000..3b573e934b --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/index.mdx @@ -0,0 +1,44 @@ +--- +hide_table_of_contents: true +pagination_prev: reference/index +--- + +# 🍰 FSDについて + +背景指向 + +

+FSD設計方法論、チーム、コミュニティ、そして発展の歴史に関する一般情報 +

+ +## 主な内容 {#main} + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { StarOutlined, TrophyOutlined, BulbOutlined, TeamOutlined } from "@ant-design/icons"; + + + + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/mission.md b/i18n/ja/docusaurus-plugin-content-docs/current/about/mission.md new file mode 100644 index 0000000000..b99c74375c --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/mission.md @@ -0,0 +1,50 @@ +--- +sidebar_position: 1 +--- + +# ミッション + +ここでは、私たちがFSD方法論を開発する際に従う方法論適用の制限と目標について説明します。 + +- 私たちは、目標をイデオロギーとシンプルさのバランスとして考えている +- 私たちは、すべての人に適した銀の弾丸を作ることはできない + +**それでも、FSD方法論が広範な開発者にとって近く、アクセス可能であることを望んでいます。** + +## 目標 {#goals} + +### 幅広い開発者に対する直感的な明確さ {#intuitive-clarity-for-a-wide-range-of-developers} + +FSD方法論は、プロジェクトチームの大部分にとってアクセス可能であるべきです。 + +*なぜなら、将来のすべてのツールがあっても、FSD方法論を理解できるのは経験豊富なシニアやリーダーだけでは不十分だからである* + +### 日常的な問題の解決 {#solving-everyday-problems} + +FSD方法論には、プロジェクト開発における日常的な問題の理由と解決策が示されるべきです。 + +また、開発者が*コミュニティーの経験に基づいた*アプローチを使用できるようにし、長年のアーキテクチャや開発の問題を回避できるようにするには、**FSD方法論はこれに関連するツール(CLI、リンター)を提供することも必要です。** + + +> *@sergeysova: 想像してみてください。開発者が方法論に基づいてコードを書いているとき、開発者の直面している問題は10倍少なく発生しています。それは他の人々が多くの問題の解決策を考え出したから、可能になったのです。* + +## 制限 {#limitations} + +私たちは*自分たちの見解を押し付けたくありません*が、同時に*多くの開発者の習慣が日々の開発の妨げになっていることを理解しています。* + +すべての開発者にはシステム設計と開発経験レベルが異なるため、**次のことを理解することが重要です。** + +- FSD方法論は、すべての開発者にとって、同時に非常にシンプルで、非常に明確にするのは不可能 + > *@sergeysova: 一部の概念は、問題に直面し、解決に数年を費やさない限り、直感的に理解することはできない。* + > + > - *数学の例 — グラフ理論。* + > - *物理の例 — 量子力学。* + > - *プログラミングの例 — アプリケーションのアーキテクチャ。* + > +- シンプルさ、拡張性は、実現可能であって望ましい + +## 参照 {#see-also} + +- [アーキテクチャの問題][refs-architecture--problems] + +[refs-architecture--problems]: /docs/about/understanding/architecture#problems diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/motivation.md b/i18n/ja/docusaurus-plugin-content-docs/current/about/motivation.md new file mode 100644 index 0000000000..7394004603 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/motivation.md @@ -0,0 +1,133 @@ +--- +sidebar_position: 2 +--- + +# モチベーション + +**Feature-Sliced Design**の主なアイデアは、さまざまな開発者の経験を議論し、研究結果を統合することに基づいて、複雑で発展するプロジェクトの開発を容易にし、開発コストを削減することです。 + +明らかに、これは銀の弾丸ではなく、当然ながら、FSDには独自の[適用範囲の限界][refs-mission]があります。 + +## 既存の解決策が不足している理由 {#intuitive-clarity-for-a-wide-range-of-developers} + +> 通常、次のような議論があります。 +> +> - *「SOLID」、「KISS」、「YAGNI」、「DDD」、「GRASP」、「DRY」など、すでに確立された設計原則があるのに、なぜ新しい方法論が必要なのか?」* +> - *「プロジェクトのすべての問題は、良いドキュメント、テスト、確立されたプロセスで解決できる」* +> - *「すべての問題は、すべての開発者が上記のすべてに従えば解決される」* +> - *「すでにすべてが考案されているから、あなたはそれを利用できないだけだ」* +> - *\{FRAMEWORK_NAME\}を使えば、すべてが解決される」* + +### 原則だけでは不十分 {#principles-alone-are-not-enough} + +**良いアーキテクチャを設計するためには、原則の存在だけでは不十分です。** + +すべての人が原則を完全に理解しているわけではありません。正しく原則を理解し、適用できる人はさらに少ないです。 + +*設計原則はあまりにも一般的であり、「スケーラブルで柔軟なアプリケーションの構造とアーキテクチャをどのように設計するか?」という具体的な質問に対する答えを提供していません。* + +### プロセスは常に機能するわけではない {#processes-dont-always-work} + +*ドキュメント/テスト/プロセス*を使用するのは、確かに良いことですが、残念ながら、それに多くのコストをかけても、**アーキテクチャの問題や新しい人をプロジェクトに導入する問題を解決することは常にできるわけではありません。** + +- ドキュメントは、しばしば膨大で古くなってしまうので、各開発者のプロジェクトへの参加時間はあまり短縮されない。 +- 誰もが同じようにアーキテクチャを理解しているかを常に監視することは、膨大なリソースを必要とする。 +- bus-factorも忘れないようにしましょう。 + +### 既存のフレームワークはどこでも適用できるわけではない {#existing-frameworks-cannot-be-applied-everywhere} + +- 既存の解決策は通常、高い参入障壁があるため、新しい開発者を見つけるのが難しい。 +- ほとんどの場合、技術の選択はプロジェクトの深刻な問題が発生する前に決定されているため、**技術に依存せずに**、すでにあるもので作業をすることができなければならない。 + +> Q: *「私のプロジェクトでは`React/Vue/Redux/Effector/Mobx/{YOUR_TECH}`を使っていますが、エンティティの構造とそれらの間の関係をどのように構築すればよいでしょうか?」* + +### 結果として {#as-a-result} + +「雪の結晶」のようにユニークなプロジェクトが得られ、それぞれが従業員の長期的な関与を必要とし、他のプロジェクトではほとんど適用できない知識を必要とします。 + +> @sergeysova: *これは、現在のフロントエンド開発の状況そのものであり、各リーダーがさまざまなアーキテクチャやプロジェクトの構造を考案しているが、これらの構造が時間の試練に耐えるかどうかは不明であり、最終的にはリーダー以外の人がプロジェクトを発展させることができるのは最大で2人であり、新しい開発者を再び入れる必要がある。* + +## 開発者にとっての方法論の必要性 {#why-do-developers-need-the-methodology} + +### アーキテクチャの問題ではなくビジネス機能に集中するため {#focus-on-business-features-not-on-architecture-problems} + +FSDは、スケーラブルで柔軟なアーキテクチャの設計にかかるリソースを節約し、開発者の注意を主要な機能開発に向けることを可能にしています。同時に、プロジェクトごとにアーキテクチャの解決策も標準化されます。 + +*別の問題は、FSDがコミュニティの信頼を得る必要があることです。そうすれば、開発者は自分のプロジェクトの問題を解決する際に、与えられた時間内にFSDを理解し、信頼することができます。* + +### 経験に基づく解決策 {#an-experience-proven-solution} + +FSDは、*複雑なビジネスロジックの設計における経験に基づく解決策を目指す開発者*を対象としています。 + +*ただし、FSDは、全体としてベストプラクティスのセット、または特定の問題やケースに関する記事一覧です。したがって、開発や設計の問題に直面する他の開発者にも役立てます。* + +### プロジェクトの健康 {#project-health} + +FSDは、*プロジェクトの問題を事前に解決し、追跡することを可能にし、膨大なリソースを必要としません。* + +**技術的負債は通常、時間とともに蓄積され、その解決の責任はリーダーとチームの両方にあります。** + +FSDは、*スケーリングやプロジェクトの発展における潜在的な問題を事前に警告することを可能にしています。* + +## ビジネスにとってのFSD方法論の必要性 {#why-does-a-business-need-a-methodology} + +### 迅速なオンボーディング {#fast-onboarding} + +FSDを使用すると、**すでにこのアプローチに慣れている人をプロジェクトに雇うことができ、再教育する必要がありません。** + +*人々はより早くプロジェクトに慣れ、貢献し始め、次のプロジェクトのイテレーションで人を見つけるための追加の保証が得られます。* + +### 経験に基づく解決策 {#an-experience-proven-solution-1} + +ビジネスは、プロジェクトの発展における大部分の問題を解決するフレームワーク/解決策を得たいと考えています。FSDにより、ビジネスは*システムの開発中に発生するほとんどの問題に対する解決策を得ることができます。* + +### プロジェクトのさまざまな段階への適用性 {#applicability-for-different-stages-of-the-project} + +FSDは、*プロジェクトのサポートと発展の段階でも、MVPの段階でもプロジェクトに利益をもたらすことができます。* + +はい、MVPでは通常、機能が重要であり、将来のアーキテクチャは重要ではありません。しかし、限られた時間の中で、方法論のベストプラクティスを知っていることで、少ないコストで済むことができ、MVPバージョンのシステムを設計する際に合理的な妥協を見つけることができます(無計画に機能を追加するよりも)。 + +*テストについても同じことが言えます。* + +## 私たちの方法論が必要ない場合 {#when-is-our-methodology-not-needed} + +- プロジェクトが短期間しか存続しない場合 +- プロジェクトがサポートされるアーキテクチャを必要としない場合 +- ビジネスがコードベースと機能の提供速度の関連性を認識しない場合 +- ビジネスができるだけ早く注文を完了することを重視し、さらなるサポートを求めない場合 + +### ビジネスの規模 {#business-size} + +- **小規模ビジネス** - 通常、迅速で即効性のある解決策を必要とします。ビジネスは、成長する(少なくとも中規模に達する)と、顧客が継続的にサービスなどを利用するためには、開発される解決策の品質と安定性に時間をかける必要があることを理解し始めます。 +- **中規模ビジネス** - 通常、開発のすべての問題を理解しており、たとえ機能をできるだけ早くリリースしたい場合でも、品質の改善、リファクタリング、テスト(そしてもちろん、拡張可能なアーキテクチャ)に時間をかけます。 +- **大規模ビジネス** - 通常、すでに広範なオーディエンスを持ち、従業員の数も多く、独自のプラクティスのセットを持っているため、他のアプローチを採用するアイデアはあまり浮かびません。 + +## 目標 {#plans} + +主要な目標の大部分は[ここに記載されています][refs-mission--goals]が、今後のFSD方法論に対する私たちの期待についても話しておく必要があります。 + +### 経験の統合 {#combining-experience} + +現在、私たちは`core-team`のさまざまな経験を統合し、実践に基づいた方法論を得ることを目指しています。 + +もちろん、最終的にはAngular 3.0のようなものを得るかもしれませんが、ここで最も重要なのは、**複雑なシステムのアーキテクチャ設計の問題を探求することです。** + +*そして、現在のFSD方法論のバージョンに対して不満があることは確かですが、私たちはコミュニティの経験も考慮しながら、共通の努力で統一的かつ最適な解決策に到達したいと考えています。* + +### 仕様外の生活 {#life-outside-the-specification} + +すべてがうまくいけば、FSDは仕様やツールキットに限定されることはありません。 + +- 講演や記事があるかもしれない。 +- FSD方法論に従って書かれたプロジェクトの他の技術への移行のための`CODE_MODEs`があるかもしれない。 +- 最終的には、大規模な技術的解決策のメンテイナーに到達できるかもしれない。 + - *特にReactに関しては、他のフレームワークと比較して、これは主な問題である。なぜなら、特定の問題を解決する方法を示さないからである。* + +## 参照 {#see-also} + +- [方法論の使命について:目標と制限][refs-mission] +- [プロジェクトにおける知識の種類][refs-knowledge] + +[refs-mission]: /docs/about/mission +[refs-mission--goals]: /docs/about/mission#goals +[refs-knowledge]: /docs/about/understanding/knowledge-types \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/_category_.yaml b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/_category_.yaml new file mode 100644 index 0000000000..abce1d4fe5 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/_category_.yaml @@ -0,0 +1,3 @@ +label: プロモート +position: 11 +collapsed: true diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-company.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-company.mdx new file mode 100644 index 0000000000..b8efbc68ca --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-company.mdx @@ -0,0 +1,10 @@ +--- +sidebar_position: 4 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# 会社での推進 + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-team.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-team.mdx new file mode 100644 index 0000000000..c484972621 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/for-team.mdx @@ -0,0 +1,10 @@ +--- +sidebar_position: 3 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# チームでの推進 + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/integration.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/integration.mdx new file mode 100644 index 0000000000..b12c4006cf --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/integration.mdx @@ -0,0 +1,16 @@ +--- +sidebar_position: 1 +--- + +# 統合の側面 + +**利点**: +- [概要](/docs/get-started/overview#advantages) +- コードレビュー +- オンボーディング + +**欠点**: +- メンタル的な複雑さ +- 高い参入障壁 +- 「レイヤー地獄」 +- 機能ベースのアプローチにおける典型的な問題 \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/partial-application.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/partial-application.mdx new file mode 100644 index 0000000000..a4fc1d8221 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/promote/partial-application.mdx @@ -0,0 +1,10 @@ +--- +sidebar_position: 2 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# 部分的な適用 + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/_category_.yaml b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/_category_.yaml new file mode 100644 index 0000000000..5690b49cfd --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/_category_.yaml @@ -0,0 +1,2 @@ +label: 理解 +position: 3 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/abstractions.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/abstractions.mdx new file mode 100644 index 0000000000..5e7de6f46b --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/abstractions.mdx @@ -0,0 +1,18 @@ +--- +sidebar_position: 6 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# 抽象化 + + + +## 漏れのある抽象化の法則 {#the-law-of-leaky-abstractions} + +## なぜこんなに多くの抽象化があるのか {#why-are-there-so-many-abstractions} + +> 抽象化はプロジェクトの複雑さに対処するのに役立ちます。問題は、これらの抽象化がこのプロジェクトに特有のものになるのか、それともフロントエンドの特性に基づいて一般的な抽象化を導き出そうとするのかということです。 + +> アーキテクチャとアプリケーション全体は元々複雑であり、問題はその複雑さをどのように分配し、記述するかだけです。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/architecture.md b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/architecture.md new file mode 100644 index 0000000000..2153d05788 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/architecture.md @@ -0,0 +1,94 @@ +--- +sidebar_position: 1 +--- + +# アーキテクチャ + +## 問題 {#problems} + +通常、アーキテクチャについての議論は、プロジェクトの開発が何らかの問題で停滞しているときに持ち上がります。 + +### バスファクターとオンボーディング + +プロジェクトとそのアーキテクチャを理解しているのは限られた人々だけです。 + +**例:** + +- *「新しい人を開発に加えるのが難しい」* +- *「問題があるたびに、各自が異なる回避策を持っている」* +- *「この大きなモノリスの中で何が起こっているのか理解できない」* + +### 暗黙的かつ制御されていない結果 {#implicit-and-uncontrolled-consequences} + +開発やリファクタリングにおいて多くの暗黙的な副作用が発生してしまいます(「すべてがすべてに依存している」)。 + +**例:** + +- *「フィーチャーが他のフィーチャーをインポートしている」* +- *「あるページのストアを更新したら、別のページのフィーチャーが壊れた」* +- *「ロジックがアプリ全体に散らばっていて、どこが始まりでどこが終わりかわからない」* + +### 制御されていないロジックの再利用 {#uncontrolled-reuse-of-logic} + +既存のロジックを再利用したり修正したりするのが難しいです。 + +通常、2つの極端なケースがあります。 + +- 各モジュールごとにロジックを完全にゼロから書く(既存のコードベースに重複が生じる可能性がある) +- すべてのモジュールを`shared`フォルダーに移動し、大きなモジュールの「ごみ屋敷」を作る(ほとんどが一箇所でしか使用されない) + +**例:** + +- *「プロジェクトに同じビジネスロジックの複数の実装があって、毎日その影響を受けている」* +- *「プロジェクトには6つの異なるボタン/ポップアップコンポーネントがある」* +- *「ヘルパー関数の「ごみ屋敷」」* + +## 要件 {#requirements} + +したがって、理想的なアーキテクチャに対する要求を提示するのは、理にかなっています。 + +:::note + +「簡単」と言われるところでは、「広範な開発者にとって相対的に簡単である」という意味です。なぜなら、[すべての人にとって完璧な解決策を作ることはできないからです](/docs/about/mission#limitations)。 + +::: + +### 明示性 + +- チームがプロジェクトとそのアーキテクチャを**簡単に習得し、説明できる**ようにする必要がある +- 構造はプロジェクトの**ビジネス価値**を反映するべきである +- **副作用と抽象化間の関係**が明示されるべきである +- ユニークな実装を妨げず、**ロジックの重複を簡単に発見できる**ようにする必要がある +- プロジェクト全体に**ロジックが散らばってはいけない** +- 良好なアーキテクチャのために**あまりにも多くの異なる抽象化やルールが存在してはならない** + +### 制御 + +- 良好なアーキテクチャは**課題の解決や機能の導入を加速する**べきである +- プロジェクトの開発を**制御**できる必要がある +- コードを**拡張、修正、削除するのが簡単である**べきである +- 機能の**分解と孤立性**が守られるべきである +- システムの各コンポーネントは**簡単に交換可能で削除可能**であるべきである + - *未来を予測することはできないから、[変更に最適化する必要はない][ext-kof-not-modification]* + - *既存のコンテキストに基づいて、[削除に最適化する方が良い][ext-kof-but-removing]* + +### 適応性 + +- 良好なアーキテクチャは、ほとんどのプロジェクトに適用可能であるべきである + - *既存のインフラソリューションと共に* + - *どの発展段階でも* +- フレームワークやプラットフォームに依存してはいけない +- プロジェクトとチームを簡単にスケールアップでき、開発の並行処理が可能である必要がある +- 変化する要件や状況に適応するのが簡単であるべきである + +## 関連情報 {#see-also} + +- [(React Berlin Talk) Oleg Isonen - Feature Driven Architecture][ext-kof] +- [(記事) プロジェクトのモジュール化について][ext-medium] +- [(記事) 関心の分離と機能に基づく構造について][ext-ryanlanciaux] + +[ext-kof-not-modification]: https://youtu.be/BWAeYuWFHhs?t=1631 +[ext-kof-but-removing]: https://youtu.be/BWAeYuWFHhs?t=1666 +[ext-kof]: https://youtu.be/BWAeYuWFHhs +[ext-medium]: https://alexmngn.medium.com/why-react-developers-should-modularize-their-applications-d26d381854c1 +[ext-ryanlanciaux]: https://ryanlanciaux.com/blog/2017/08/20/a-feature-based-approach-to-react-development/ diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/knowledge-types.md b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/knowledge-types.md new file mode 100644 index 0000000000..74e5b2dff9 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/knowledge-types.md @@ -0,0 +1,23 @@ +--- +sidebar_position: 3 +sidebar_label: 知識の種類 +--- + +# プロジェクトにおける知識の種類 + +どのプロジェクトにも以下の「知識の種類」が存在します。 + +* **基礎知識** + 時間とともにあまり変わらない知識。例えばアルゴリズム、コンピュータサイエンス、プログラミング言語やそのAPIの動作メカニズムなど。 + +* **技術スタック** + プロジェクトで使用される技術的解決策のセットに関する知識。プログラミング言語、フレームワーク、ライブラリを含む。 + +* **プロジェクト知識** + 現在のプロジェクトに特有であり、他のプロジェクトでは役に立たない知識。この知識は新しいチームメンバーが効果的にプロジェクトに貢献するために必要である。 + +:::note + +**Feature-Sliced Design**は「プロジェクト知識」への依存を減らし、より多くの責任を引き受け、新しいチームメンバーのオンボーディングを容易にすることを目指している。 + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/naming.md b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/naming.md new file mode 100644 index 0000000000..dcb4e36686 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/naming.md @@ -0,0 +1,36 @@ +--- +sidebar_position: 4 +--- + +# ネーミング + +異なる開発者は異なる経験と背景を持っているため、同じエンティティが異なる名前で呼ばれることによって、チーム内で誤解が生じる可能性があります。例えば + +- 表示用のコンポーネントは「ui」、「components」、「ui-kit」、「views」などと呼ばれることがある。 +- アプリケーション全体で再利用されるコードは「core」、「shared」、「app」などと呼ばれることがある。 +- ビジネスロジックのコードは「store」、「model」、「state」などと呼ばれることがある。 + +## Feature-Sliced Designにおけるネーミング {#naming-in-fsd} + +FSD設計方法論では、以下のような特定の用語が使用されます。 + +- 「app」、「process」、「page」、「feature」、「entity」、「shared」といった層の名前、 +- 「ui」、「model」、「lib」、「api」、「config」といったセグメントの名前。 + +これらの用語を遵守することは、チームメンバーやプロジェクトに新しく参加する開発者の混乱を防ぐために非常に重要です。標準的な名称を使用することは、コミュニティに助けを求める際にも役立ちます。 + +## 名前衝突 {#when-can-naming-interfere} + +名前衝突は、FSD設計方法論で使用される用語がビジネスで使用される用語と重なっている場合に発生する可能性があります。例えば + +- `FSD#process`と、アプリケーション内でモデル化されたプロセス、 +- `FSD#page`と、マガジンのページ、 +- `FSD#model`と、自動車モデル。 + +開発者がコード内で「プロセス」という言葉を見た場合、どのプロセスが指されているのかを理解するのに余分な時間を費やすことになってしまいます。このような**衝突は開発プロセスを妨げる場合があります**。 + +プロジェクトの用語集にFSD特有の用語が含まれている場合、これらの用語をチームや技術的に関心のない関係者と議論する際には特に注意が必要です。 + +チームとの効果的なコミュニケーションのためには、用語の前に「FSD」という略語を付けることをお勧めします。例えば、プロセスについて話すときは、「このプロセスをFSDのフィーチャー層に置くことができる」と言うことができます。 + +逆に、技術的でない関係者とのコミュニケーションでは、FSDの用語の使用を制限し、コードベースの内部構造に言及しない方が良いでしょう。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/needs-driven.md b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/needs-driven.md new file mode 100644 index 0000000000..c8f60760ed --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/needs-driven.md @@ -0,0 +1,153 @@ +--- +sidebar_position: 2 +--- + +# ニーズの理解と課題の定義について + +:::note TL;DR + +— _新しい機能が解決する目標を明確にできませんか?それとも、問題はタスク自体が明確にされていないことにありますか?**FSDは、問題の定義や目標を引き出す手助けをすることも目的にしています。**_ + +— _プロジェクトは静的に存在するわけではなく、要件や機能は常に変化しています。プロジェクトは最初の要望のスナップショットのみに基づいて設計されているため、時間が経つにつれて、コードは混沌としてしまいます。**良いアーキテクチャの課題の一つは、変化する開発条件に対応できるようにすることです。**_ + +::: + + + + +## なぜ? {#why} + +エンティティの明確な名前を選び、その構成要素を理解するためには、**コードが解決する課題を明確に理解する必要があります。** + +> _@sergeysova: 開発中、私たちは各エンティティや機能に、その意図や意味を明確に反映する名前を付けようとしている。_ + +_課題を理解しなければ、重要なケースをカバーする正しいテストを書くことも、ユーザーに適切な場所でエラーを表示することもできず、単純にユーザーのフローを中断することにもなってしまいます。_ + +## どのような課題についての話? {#what-tasks-are-we-talking-about} + +フロントエンドは、エンドユーザーのためのアプリケーションやインターフェースを開発しているため、私たち開発者はその消費者の課題を解決しています。 + +私たちのもとに誰かが来るとき、**その人は自分の悩みを解決したり、ニーズを満たしたりしてほしいのです。** + +_マネージャーとアナリストの仕事はこのニーズを定義することです。開発者の仕事はウェブ開発の特性(接続の喪失、バックエンドのエラー、タイプミス、カーソルや指の操作ミス)を考慮して、そのニーズを実現することです。_ + +**ユーザーが持ってきた目的こそが、開発者の課題です。** + +> _小さな解決された課題が、Feature-Sliced Designの設計方法論におけるfeatureではあります。プロジェクト課題のスコープを小さな目標に分割する必要があります。_ + +## これが開発にどのように影響するのか? {#how-does-this-affect-development} + +### 課題(タスク)の分解 {#task-decomposition} + +開発者がタスクを実装し始めるとき、理解の簡素化とコードメンテナンスのために、**タスクを段階に分けます**。 + +- まずは、上位レベルのエンティティに分けて、それを実装する +- 次に、これらのエンティティをより小さく分ける +- そしてさらに続ける + +_エンティティを分解する過程で、開発者はそれに明確に意図を反映した名前を付ける必要があり、エンティティの一覧表を読む際にそのコードが解決する課題を理解するのに役立ちます。_ + +この際、ユーザーの悩みを軽減したり、ニーズを実現したりするユーザーへの手助けをすることを忘れないように心がけましょう。 + +### 課題の本質を理解する {#understanding-the-essence-of-the-task} + +エンティティに明確な名前を付けるためには、**開発者はその目的について十分に理解する必要があります。** + +- エンティティをどのように使用するつもりなのか +- エンティティがユーザーの課題のどの部分を実現するのか、他にどこでこのエンティティを使用できるのか +- などなど + +結論を出すのは難しくありません。**開発者がFSD枠内でのエンティティの名前を考えているとき、コードを書く前に不十分に定義された課題を見つけることができます。** + +> どのようにエンティティに名前を付けるのか、もしそのエンティティが解決できる課題をよく理解していない場合、そもそもどうやって課題をエンティティに分解できるのか? + +## どのように定義するのか? {#how-to-formulate-it} + +機能によって解決される課題を定義するためには、その課題自体を理解する必要があります。これはプロジェクトマネージャーやアナリストの責任範囲です。 + +_FSD設計方法論は、開発者に対して、プロダクトマネージャーが注目すべき課題を示唆することしかできません。_ + +> _@sergeysova: フロントエンドは、まず情報を表示するものである。どのコンポーネントも、まず何かを表示する。したがって、「ユーザーに何かを見せる」というタスクには実用的な価値がない。_ + +基本的なニーズや悩みを見つけたら、**あなたのプロダクトやサービスがどのようにユーザーの目標をサポートすることができるのかを考えます。** + +タスクトラッカーの新しいタスクは、ビジネスの課題を解決することを目的としており、ビジネスは同時にユーザーの課題を解決し、利益を上げようとしています。したがって、説明文に明記されていなくても、各タスクには特定の目標が含まれています。 + +開発者は、特定のタスクが追求する目的をはっきりと把握しておくべきです。しかし、すべての会社がプロセスを完璧に構築できるわけではありません。 + +## その利益は何か? {#and-what-is-the-benefit} + +では、プロセス全体を最初から最後まで見てみましょう。 + +### 1. ユーザーの課題を理解する {#1-understanding-user-tasks} + +開発者は、ユーザーの悩みとビジネスがその悩みをどのように解決するかを理解すると、ウェブ開発の特性によりビジネスには提供できない解決策を提案することができます。 + +> しかしもちろん、これは開発者が自分の行動や目的に無関心でない限り機能します。さもなければ、そもそもなぜFSDやアプローチが必要なのか?という疑問になってしまいます。 + +### 2. 構造化と整理 {#2-structuring-and-ordering} + +課題を理解することで、**頭とコードの中で明確な構造が得られます。** + +### 3. 機能とその構成要素を理解する {#3-understanding-the-feature-and-its-components} + +**1つの機能は、ユーザーにとって1つの有用な機能性です。** + +- 1つの機能に複数の機能性が実装されている場合、それは**境界の侵害**である。 +- 機能は分割不可能で成長可能になる場合があるが、**それは悪くない。** +- **悪い**のは、機能が「ユーザーにとってのビジネス価値は何か?」という質問に答えられないことである。 + - 「オフィスの地図」という機能は存在できない。 + - しかし、「地図上の会議室の予約」、「従業員の検索」、「作業場所の変更」は**存在可能である。** + +> _@sergeysova: 機能には、直接的にその機能を実現するコードだけが含まれるべきであり、余計な詳細や内部の解決策は含まれないべきである(理想的には)。_ + +> *機能のコードを開くと、**そのタスクに関連するものだけが見える**。それ以上は必要ない。* + +### 4. Profit {#4-profit} + +ビジネスはその方針を極めて稀にしか根本的に変えないため、**ビジネスのタスクをフロントエンドアプリケーションのコードに反映することは非常に大きな利点になれます。** + +_そうすれば、チームの新しいメンバーにそのコードが何をするのか、なぜ追加されたのかを説明する必要がなくなります。**すべては、すでにコードに反映されているビジネスのタスクを通じて説明されているからです。**_ + +> [Domain Driven Developmentにおける「ビジネス言語」][ext-ubiq-lang] + +--- + +## 現実に戻りましょう {#back-to-reality} + +ビジネスプロセスが明確な意味を持ち、設計段階で良い名前が付けられている場合、_その理解と論理をコードに移すことはそれほど問題ではありません。_ + +しかし実際には、タスクや機能性は通常「過度に」反復的に進化し、(または)デザインを考える時間がありません。 + +**その結果、今日、機能は意味を持っていますが、1か月後にその機能を拡張する際には、プロジェクト全体を再構築する必要があるかもしれません。** + +> *開発者は未来の要望を考慮しながら2〜3ステップ先を考えようとしますが、自分の経験に行き詰まってしまいます。* + +> _経験豊富なエンジニアは通常、すぐに10ステップ先を見て、どの機能を分割するか、どの機能を他の機能と統合するかを理解しています。_ + +> _しかし、経験上遭遇したことのないタスクが来ることもあり、その場合、どのように機能を適切に分解し、将来的に悲惨な結果を最小限に抑えるかを理解する手段がありません。_ + +## FSDの役割 {#the-role-of-methodology} + +**FSDは、開発者の問題を解決する手助けをし、ユーザーの問題を解決するのを容易にしています。** + +開発者のためだけに課題を解決することはありません。 + +しかし、開発者が自分の課題を解決するためには、**ユーザーの課題を理解する必要があります**。逆は成り立ちません。 + +### FSDに対する要件 {#methodology-requirements} + +明らかになるのは、**Feature-Sliced Design**のために少なくとも2つの要件を定義する必要があるということです。 + +1. FSD方法論は**フィーチャー、プロセス、エンティティを作成する方法**を説明する必要がある。 + - つまり、それらの間でコードをどのように分割するかを明確に説明する必要がある。これによりこれらのエンティティの命名も仕様に組み込まれるべきである。 +2. FSD方法論は、アーキテクチャがプロジェクトの変わりゆく要件にスムーズに対応できるようにするべきである。 + +## 関連情報 {#see-also} + +- [(記事) "How to better organize your applications"][ext-medium] + +[refs-arch--adaptability]: architecture#adaptability + +[ext-medium]: https://alexmngn.medium.com/how-to-better-organize-your-react-applications-2fd3ea1920f1 +[ext-ubiq-lang]: https://thedomaindrivendesign.io/developing-the-ubiquitous-language \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/signals.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/signals.mdx new file mode 100644 index 0000000000..c1757ce6be --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/about/understanding/signals.mdx @@ -0,0 +1,10 @@ +--- +sidebar_position: 5 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# アーキテクチャのシグナル + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/branding.md b/i18n/ja/docusaurus-plugin-content-docs/current/branding.md new file mode 100644 index 0000000000..4b722d43e7 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/branding.md @@ -0,0 +1,80 @@ +# ブランドガイドライン + +FSDのビジュアルアイデンティティは、そのコアコンセプトである `Layered`、`Sliced self-contained parts`、`Parts & Compose`、`Segmented` に基づいています。しかし、私たちはFSDの哲学を反映し、簡単に認識できる美しいアイデンティティを目指しています。 + +**FSDのアイデンティティを「そのまま」変更せずに、私たちのアセットを使って快適にご利用ください。** このブランドガイドは、FSDのアイデンティティを正しく使用する手助けをします。 + +:::caution 互換性 + +FSDは以前、[別のレガシーアイデンティティ](https://drive.google.com/drive/folders/11Y-3qZ_C9jOFoW2UbSp11YasOhw4yBdl?usp=sharing)を持っていました。古いデザインは、FSDの主要なコンセプトを反映していませんでした。また、これは粗いドラフトとして作成され、更新されるべきものでした。 + +ブランドの互換性と長期的な使用のために、私たちは2021年から2022年にかけて慎重にリブランディングに取り組みました。**FSDのアイデンティティを使用する際に自信を持てるように🍰** + +*古いアイデンティティではなく、最新のアイデンティティを使用してください!* + +::: + +## 名前 {#title} + +- ✅ **正しい:** `Feature-Sliced Design`、`FSD` +- ❌ **間違っている:** `Feature-Sliced`、`Feature Sliced`、`FeatureSliced`、`feature-sliced`、`feature sliced`、`FS` + +## 絵文字 {#emojii} + +ケーキのイメージ 🍰 はFSDの主要なコンセプトをよく反映しているため、私たちのブランド絵文字として選ばれました。 + +> 例: *"🍰 フロントエンド用ののアーキテクチャデザイン設計方法論"* + +## ロゴとカラーパレット {#logo--palettte} + +FSDには異なるコンテキスト用のいくつかのロゴバリエーションがありますが、**primary**の使用が推奨されます。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
テーマロゴ (Ctrl/Cmd + Clickでダウンロード)使用法
primary
(#29BEDC, #517AED)
logo-primaryほとんどの場合に推奨されます
flat
(#3193FF)
logo-flat単色コンテキスト用
monochrome
(#FFF)
logo-monocrhome白黒コンテキスト用
square
(#3193FF)
logo-square正方形サイズ用
+ +## バナーとスキーム {#banners--schemes} + +
banner-primary +banner-monochrome + +## ソーシャルプレビュー + +作業中... + +## プレゼンテーションテンプレート {#presentation-template} + +作業中... + +## 参照 {#see-also} + +- [ディスカッション (github)](https://github.com/feature-sliced/documentation/discussions/399) +- [リブランディングの歴史と参考資料 (figma)](https://www.figma.com/file/RPphccpoeasVB0lMpZwPVR/FSD-Brand?node-id=0%3A1) +- [リブランディングデモ](https://rebrand-sliced.netlify.app/en/) diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/cheatsheet.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/cheatsheet.mdx new file mode 100644 index 0000000000..d5d502f9b4 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/cheatsheet.mdx @@ -0,0 +1,28 @@ +--- +# sidebar_position: 3 +unlisted: true +--- + +# 分解のチートシート + +インターフェースをレイヤーに分割する際の参考書として使用してください。以下にPDFバージョンもあり、印刷して枕の下に置いておくことができます。 + +## レイヤーの選択 {#choosing-a-layer} + +[PDFをダウンロード](/files/choosing-a-layer-en.pdf) + +![レイヤーの定義と自己チェックの質問](/img/choosing-a-layer-en.jpg) + +## 例 {#examples} + +### ツイート + +![分解されたツイート](/img/decompose-twitter.png) + +### GitHub + +![分解されたGitHub](/img/decompose-github.jpg) + +## 参照 {#see-also} + +- [(記事) ロジックの分解におけるさまざまなアプローチ](https://www.pluralsight.com/resources/blog/guides/how-to-organize-your-react--redux-codebase) diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md new file mode 100644 index 0000000000..062f018fed --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md @@ -0,0 +1,68 @@ +--- +sidebar_position: 20 +pagination_next: guides/index +--- + +# FAQ + +:::info + +質問は、[Discordコミュニティ][discord]、[GitHub Discussions][github-discussions]、および[Telegramチャット][telegram]で聞くことができます。 + +::: + +### ツールキットやリンターはありますか? {#is-there-a-toolkit-or-a-linter} + +公式のESLintコンフィグ — [@feature-sliced/eslint-config][eslint-config-official]、およびコミュニティメンバーのアレクサンドル・ベロウスによって作成されたESLintプラグイン — [@conarti/eslint-plugin-feature-sliced][eslint-plugin-conarti]があります。これらのプロジェクトへの貢献や独自のツールの作成を歓迎します! + +### ページのレイアウト/テンプレートはどこに保存すればよいですか? {#where-to-store-the-layouttemplate-of-pages} + +シンプルなレイアウトテンプレートが必要な場合は、`shared/ui`に保存できます。より上層のレイヤーを使用する必要がある場合、いくつかのオプションがあります。 + +- レイアウトが本当に必要ですか?レイアウトが数行で構成されている場合、各ページにコードを重複させる方が合理的です。 +- レイアウトが必要な場合は、個別のウィジェットやページとして保存し、App層のルーター設定にそれらを組み合わせることができます。ネストされたルーティングも一つのオプションです。 + +### フィーチャーとエンティティの違いは何ですか? {#what-is-the-difference-between-feature-and-entity} + +エンティティはアプリケーションが扱う現実世界の概念です。フィーチャーはユーザーに実際の価値を提供するインタラクションであり、ユーザーがエンティティで行いたいことです。 + +詳細および例については、参考書セクションの[スライスについてのページ][reference-entities]を参照してください。 + +### ページ/フィーチャー/エンティティを相互に埋め込むことはできますか? {#can-i-embed-pagesfeaturesentities-into-each-other} + +はい、しかし、この埋め込みはより上層のレイヤーで行う必要があります。例えば、ウィジェット内で両方のフィーチャーをインポートし、プロップス/子要素として一方のフィーチャーを他方に挿入することができます。 + +一方のフィーチャーを他方のフィーチャーからインポートすることはできません。これは[**レイヤーのインポートルール**][import-rule-layers]で禁止されています。 + +### Atomic Designはどうですか? {#what-about-atomic-design} + +現在、アトミックデザインをFeature-Sliced Designと一緒に使用することを義務付けていませんが、禁止もしていません。 + +アトミックデザインは、モジュールの`ui`セグメントにうまく適用できます。 + +### FSDに関する有用なリソース/記事などはありますか? {#are-there-any-useful-resourcesarticlesetc-about-fsd} + +はい! https://github.com/feature-sliced/awesome + +### なぜFeature-Sliced Designが必要なのですか? {#why-do-i-need-feature-sliced-design} + +FSDは、プロジェクトの主要な価値を提供するコンポーネントの観点から、あなたとあなたのチームが迅速にプロジェクトを把握するのに役立ちます。標準化されたアーキテクチャは、オンボーディングを迅速化し、コード構造に関する議論を解決するのに役立ちます。FSDが作成された理由については、[モチベーション][motivation]のページを参照してください。 + +### 初心者の開発者にFSDのアーキテクチャ/設計方法論は必要ですか? {#does-a-novice-developer-need-an-architecturemethodology} + +おそらく必要です。 + +*通常、一人でプロジェクトを設計・開発する場合、すべてが順調に進みます。しかし、開発に中断が生じたり、新しい開発者がチームに加わると問題が発生します。* + +### 認証コンテキストをどのように扱えばよいですか? {#how-do-i-work-with-the-authorization-context} + +[こちら](/docs/guides/examples/auth)で回答しています。 + +[import-rule-layers]: /docs/reference/layers#import-rule-on-layers +[reference-entities]: /docs/reference/layers#entities +[eslint-config-official]: https://github.com/feature-sliced/eslint-config +[eslint-plugin-conarti]: https://github.com/conarti/eslint-plugin-feature-sliced +[motivation]: /docs/about/motivation +[telegram]: https://t.me/feature_sliced +[discord]: https://discord.gg/S8MzWTUsmp +[github-discussions]: https://github.com/feature-sliced/documentation/discussions diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/index.mdx new file mode 100644 index 0000000000..75b532c1b0 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/index.mdx @@ -0,0 +1,38 @@ +--- +hide_table_of_contents: true +pagination_prev: intro +--- + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { RocketOutlined, PlaySquareOutlined, QuestionCircleOutlined } from "@ant-design/icons"; + +# 🚀 クイックスタート + +

+ようこそ!このセクションでは、Feature-Sliced Designの適用方法とその基礎知識が簡単に紹介されます。また、FSDの主な利点とその作成理由についての内容も記載されています。 +

+ + + + +{/* */} diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/overview.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/overview.mdx new file mode 100644 index 0000000000..3f47649650 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/overview.mdx @@ -0,0 +1,137 @@ +--- +sidebar_position: 1 +--- + +# 概要 + +**Feature-Sliced Design** (FSD) とは、フロントエンドアプリケーションの設計方法論です。簡単に言えば、コードを整理するためのルールと規約の集大成です。FSDの主な目的は、ビジネス要件が絶えず変化する中で、プロジェクトをより理解しやすく、構造化されたものにすることです。 + +ルールのセットに加えて、FSDはツールチェーンでもあります。プロジェクトのアーキテクチャをチェックするための[リンター][ext-steiger]、CLIやIDEを通じた[フォルダージェネレーター][ext-tools]、および豊富な[実装例のコレクション][examples]があります。 + +## FSDは私のプロジェクトに適しているのか? {#is-it-right-for-me} + +FSDは、あらゆる規模のプロジェクトやチームに導入できます。以下の場合、あなたのプロジェクトに適しています。 + +- **フロントエンド**開発での使用(ウェブサイト、モバイル/デスクトップアプリケーションのインターフェース作成など) +- **アプリケーション**開発での使用(ライブラリ開発ではない) + +これだけです!使用するプログラミング言語、フレームワーク、状態管理ライブラリには制限がありません。尚、FSDを段階的に導入したり、モノレポで使用したり、アプリケーションをパッケージに分割し、それぞれにFSDを個別に導入することもできます! + +既存のアーキテクチャからFSDに移行することを検討している場合は、現在のアーキテクチャがチームに**支障をきたしている**かどうかを確認してください。例えば、プロジェクトが大きくなりすぎて新機能の開発が効率的に行えない場合や、多くの新しいメンバーがチームに加わることが予想される場合です。現在のアーキテクチャが正常に機能している場合、変更する必要はないかもしれません。しかし、移行を決定した場合は、[移行セクション][migration]の推奨事項を確認してください。 + +## 基本的な例 {#basic-example} + +以下は、FSDを実装したシンプルなプロジェクトです。 + +- `📁 app` +- `📁 pages` +- `📁 shared` + +これらのトップレベルのフォルダーは*レイヤー*と呼ばれます。詳しく見てみましょう。 + +- `📂 app` + - `📁 routes` + - `📁 analytics` +- `📂 pages` + - `📁 home` + - `📂 article-reader` + - `📁 ui` + - `📁 api` + - `📁 settings` +- `📂 shared` + - `📁 ui` + - `📁 api` + +`📂 pages`内のフォルダーは*スライス*と呼ばれます。スライスはドメイン(この場合はページ)ごとにレイヤーを分割します。 + +`📂 app`、`📂 shared`、および`📂 pages/article-reader`内のフォルダーは*セグメント*と呼ばれ、スライス(またはレイヤー)を技術的な目的に応じて分割します。 + +## 概念 {#concepts} + +レイヤー、スライス、セグメントは、以下の図に示されるように階層を形成します。 + +
+ ![FSDの概念の階層、以下に説明](/img/visual_schema.jpg) + +
+

上の図には、左から右に「レイヤー」、「スライス」、「セグメント」とラベル付けされた3つの列があります。

+

「レイヤー」列には、上から下に「app」、「processes」、「pages」、「widgets」、「features」、「entities」、「shared」とラベル付けされた7つの区分があります。「processes」区分は取り消し線が引かれています。「entities」区分は2番目の列「スライス」と接続されていて、2番目の列が「entities」の内容であることを示しています。

+

「スライス」列には、上から下に「user」、「post」、「comment」とラベル付けされた3つの区分があります。「post」区分は「セグメント」列と同様に接続されていて、「post」の内容であることを示しています。

+

「セグメント」列には、上から下に「ui」、「model」、「api」とラベル付けされた3つの区分があります。

+
+
+ +### レイヤー {#layers} + +レイヤーはすべてのFSDプロジェクトで標準化されています。すべてのレイヤーを使用する必要はありませんが、ネーミングは重要です。現在、7つのレイヤーが存在しています(上から下へ)。 + +1. App*(アップ) — アプリケーションの起動に必要なすべてのもの(ルーティング、エントリーポイント、グローバルスタイル、プロバイダーなど) +2. Processes(プロセス、非推奨) — 複雑なページ間のシナリオ +3. Pages(ページ) — ページ全体、またはネストされたルーティングの場合、ページの大部分 +4. Widgets(ウィジェット) — 大きな自己完結型の機能部分、またはインターフェースの大部分。通常はユーザーシナリオ全体を実装する +5. Features(フィーチャー) — プロダクト機能の再利用可能な実装、つまりユーザーにビジネス価値をもたらすアクション +6. Entities(エンティティ) — プロジェクトが扱うビジネスエンティティ、例えば`user`や`product` +7. Shared*(シェアード) — 再利用可能なコード。特にプロジェクト/ビジネスの詳細から切り離されたもの + +_* — App層とShared層のレイヤーは他のレイヤーとは異なり、スライスを持たず、直接セグメントで構成されています。_ + +レイヤーの特徴は、レイヤーのモジュールは、下層のレイヤーモジュールのみを知ることができ、その結果、レイヤーが下層のレイヤーからのみモジュールをインポートできることです。 + +### スライス {#slices} + +次にスライスがあり、レイヤーをドメインごとに分割します。スライスの名前は自由に付けることができ、いくつでも作成できます。スライスは、意味的に関連するコードをグループ化することで、プロジェクト内のナビゲーションをしやすくします。 + +スライスは同じレイヤーの他のスライスを使用できないため、スライス内のコードの強い結合とスライス間の弱い結合が保証されます。 + +### セグメント {#segments} + +スライス、およびApp層とShared層のレイヤーはセグメントで構成され、セグメントはその目的に応じてコードをグループ化します。セグメントの名前は標準で固定されていませんが、最も一般的な目的のためにいくつかの共通の名前があります。 + +- `ui` — 表示に関連するすべて: UIコンポーネント、日付フォーマッター、スタイルなど +- `api` — バックエンドとのやり取り: リクエスト関数、データ型、マッパー +- `model` — データモデル: バリデーションスキーマ、インターフェース、ストレージ、ビジネスロジック +- `lib` — 他のモジュールが必要とするライブラリコード +- `config` — 設定ファイルとフィーチャーフラグ + +通常、これらのセグメントはほとんどのレイヤーに十分であるため、独自のセグメントはShared層やApp層でのみ作成されることが多いです。しかし、これは厳格なルールではありません。 + +## 利点 {#advantages} + +- **一貫性** + 構造が標準化されているため、プロジェクトがより一貫性を持ち、新しいメンバーのチームへの参加が容易になります。 + +- **変更とリファクタリングへの耐性** + レイヤーのモジュールは、同じレイヤーや上層レイヤーの他のモジュールを使用できないため、アプリケーションの他の部分に予期しない影響を与えることなく、分離された変更を加えることができます。 + +- **ロジックの再利用制御** + レベルに応じて、コードを非常に再利用可能にすることも、非常にローカルにすることもできます。 + これにより、**DRY**原則と実用性のバランスが保たれます。 + +- **ビジネスとユーザーのニーズに焦点を当てる** + アプリケーションはビジネスドメインに分割され、命名にはビジネス用語の使用が奨励されるため、プロジェクトの他の無関係な部分に完全に精通することなく、プロダクトで有用な作業を行うことができます。 + +## 段階的な導入 {#incremental-adoption} + +既存のコードベースをFSDに移行したい場合は、以下の戦略をお勧めします。私たち自身の移行経験から、この方法は非常に効果的であることが分かりました。 + +1. App層とShared層のレイヤーを徐々に形成し、基盤を作る。 + +2. 既存のすべてのインターフェースコードをウィジェットとページに分散させる。FSDのルールに違反する依存関係があっても良い。 + +3. インポートのルール違反を徐々に修正しながら、エンティティやフィーチャーを抽出する。 + +リファクタリング中に新しい大きななエンティティを追加することや、部分的なリファクタリングは避けることをお勧めします。 + +## 次のステップ {#next-steps} + +- **FSDの考え方を理解したい?** [チュートリアル][tutorial]を読んでください。 +- **例を見て学びたい?** [実装例セクション][examples]にたくさんあります。 +- **質問がある?** [Discordチャンネル][ext-discord]にアクセスして、コミュニティに質問してください。 + +[tutorial]: /docs/get-started/tutorial +[examples]: /examples +[migration]: /docs/guides/migration/from-custom +[ext-steiger]: https://github.com/feature-sliced/steiger +[ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools +[ext-discord]: https://discord.com/invite/S8MzWTUsmp + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md new file mode 100644 index 0000000000..46ef4b4e92 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -0,0 +1,2264 @@ +--- +sidebar_position: 2 +--- + +# チュートリアル + +## 第1章 紙の上で + +このガイドでは、Real World Appとしても知られるアプリケーションを見ていきます。Conduitは、[Medium](https://medium.com/)の簡略版であり、ブログ記事を読み書きし、他の人の記事にコメントすることができます。 + +![Conduitのホームページ](/img/tutorial/realworld-feed-anonymous.jpg) + +これはかなり小さなアプリケーションなので、過度に分解することなく開発を進めます。おそらく、アプリケーション全体は3つの層に収まります: **App層**、**Pages層**、**Shared層**。もしそうでなければ、進行に応じて追加の層を導入しましょう。準備はいいですか? + +### ページの列挙から始める + +上のスクリーンショットを見てみると、少なくとも次のページがあると推測できます。 + +- ホーム(記事のフィード) +- ログインと登録 +- 記事の閲覧 +- 記事の編集 +- ユーザープロフィールの閲覧 +- プロフィールの編集(設定) + +これらの各ページは、*Pages*層の個別*スライス*になります。概要のセクションから思い出してください。スライスは単に層内のフォルダーであり、層は事前に定義された名前のフォルダーだけです。例えば、`pages`のようです。 + +したがって、私たちのPagesフォルダーは次のようになります。 + +``` +📂 pages/ + 📁 feed/ (フィード) + 📁 sign-in/ (ログイン/登録) + 📁 article-read/ (記事の閲覧) + 📁 article-edit/ (記事の編集) + 📁 profile/ (プロフィール) + 📁 settings/ (設定) +``` + +Feature-Sliced Designの特徴は、ページが互いに依存できないことです。つまり、1つのページが他のページのコードをインポートすることはできません。これは**層のインポートルール**によって禁じられています。 + +*スライス内のモジュールは、下層にあるスライスのみをインポートできる。* + +この場合、ページはスライスであるため、そのページ内のモジュール(ファイル)は、他のページではなく、下層からのみコードをインポートできます。 + +### フィードを詳しく見てみると + +
+ ![匿名訪問者の視点](/img/tutorial/realworld-feed-anonymous.jpg) +
+ _匿名訪問者の視点_ +
+
+ +
+ ![認証されたユーザーの視点](/img/tutorial/realworld-feed-authenticated.jpg) +
+ _認証されたユーザーの視点_ +
+
+ +フィードページには3つの動的領域があります。 + +1. 認証状態を示すログインリンク +2. フィードをフィルタリングするタグ一覧 +3. 1つ、または2つのフィード記事。各記事にはいいねボタンがある + +ログインリンクは、すべてのページで共通のヘッダーの一部であるため、一旦保留にしましょう。 + +#### タグ一覧 + +タグ一覧を作成するには、すべての利用可能なタグを取得し、各タグをチップ([chip](https://m3.material.io/components/chips/overview))として表示し、選択されたタグをクライアント側のストレージに保存する必要があります。これらの操作は、「APIとのインタラクション」、「ユーザーインターフェース」、「データストレージ」のカテゴリに関連しています。Feature-Sliced Designでは、コードは目的に応じて*セグメント*に分けられます。セグメントはスライス内のフォルダーであり、目的を説明する任意の名前を持つことができます。いくつかの目的は非常に一般的であるため、いくつかの一般的な名前があります。 + +- 📂 `api/` バックエンドとのインタラクション +- 📂 `ui/` 表示と外観を担当するコード +- 📂 `model/` データとビジネスロジックのストレージ +- 📂 `config/` フィーチャーフラグ、環境変数、その他の設定形式 + +タグを取得するコードは`api`に、タグコンポーネントは`ui`に、ストレージとのインタラクションは`model`に配置します。 + +#### 記事 + +同じ論理に従って、記事のフィードを同じ3つのセグメントに分けることができます。 + +- 📂 `api/`: ページごとの記事一覧を取得したり、いいねを残したりする +- 📂 `ui/`: + - タグを選択したときに追加のタブを表示できるタブ一覧 + - 個別の記事 + - ページネーション +- 📂 `model/`: クライアントのストレージに保存された読み込まれた投稿と現在のページ(必要に応じて) + +### 共通コードの再利用 + +アプリケーションのページは通常、目的によって非常に異なりますが、全体で共通するものもあります。例えば、デザイン言語に対応するUIキットや、すべてが特定の認証メソッドを介してREST APIを通じて行われるというバックエンドにおける取り決めです。スライスは隔離されている必要があるため、コードの再利用は下層の**Shared層**を介して行われます。 + +Shared層は他の層とは異なり、スライスではなくセグメントを含むため、Shared層はレイヤーとスライスのハイブリッドです。 + +通常、Shared層内のコードは事前に作成されず、開発の過程で抽出されます。なぜなら、どの部分のコードが実際に再利用されるかが開発中に明らかになるからです。それでも、Shared層にどんなコードを保持するかを念頭に置いておくことは重要です。 + +- 📂 `ui/` — ビジネスロジックなしのUIキット。例えば、ボタン、ダイアログ、フォームフィールド。 +- 📂 `api/` — バックエンドへのリクエスト用の便利なラッパー(例えば、ウェブの場合は、`fetch()`のラッパー) +- 📂 `config/` — 環境変数の処理 +- 📂 `i18n/` — 多言語対応の設定 +- 📂 `router/` — ルーティングのプリミティブと定数 + +これらはShared層内のセグメントの例に過ぎません。これらのいずれかを省略したり、自分自身のセグメントを作成したりできます。新しいセグメントを作成する際に覚えておくべき唯一のことは、セグメントの名前は内容の本質(何)ではなく、目的(なぜ)を説明するものでなければなりません。`components`、`hooks`、`modals`のような名前は使用しない方が良いです。なぜなら、これらはファイルが本質的に何を含んでいるかを説明するものであり、コードが書かれた目的を説明するものではないからです。このようなネーミングの結果、チームは必要なものを見つけるためにフォルダーを掘り下げなければならず、さらに無関係なコードが隣接しているため、リファクタリング時にアプリケーションの大部分に影響を与え、レビューやテストが難しくなってしまいます。 + +### 公開APIを定義する + +Feature-Sliced Designの文脈において、*公開API*という用語は、スライス、またはセグメントが、プロジェクト内の他のモジュールがインポートできるものを宣言することを意味します。例えば、JavaScriptでは、他のファイルからオブジェクトを再エクスポートする`index.js`ファイルがこれに該当します。これにより、外部との契約(つまり、公開API)が変更されない限り、スライス内でのリファクタリングを自由にできます。 + +Shared層にはスライスがないため、通常、セグメントレベルで公開API(インデックス)を定義する方が便利です。そうすることで、Shared層からのインポートは自然に目的に応じて整理されます。他のレイヤーにはスライスがあるため、通常は1つのインデックスをスライスに定義し、スライス自身が内部のセグメントのセットを制御する方が実用的です。なぜなら、他のレイヤーは通常、エクスポートがはるかに少なく、リファクタリングが頻繁に行われるからです。 + +私たちのスライス/セグメントは次のようになるでしょう。 + +``` +📂 pages/ + 📂 feed/ + 📄 index + 📂 sign-in/ + 📄 index + 📂 article-read/ + 📄 index + 📁 … +📂 shared/ + 📂 ui/ + 📄 index + 📂 api/ + 📄 index + 📁 … +``` + +`pages/feed`や`shared/ui`のようなフォルダー内にあるものは、これらのフォルダーにのみ知られており、これらのフォルダーの内容に関する保証はありません。 + +### 大きな再利用可能なUIブロック + +以前、再利用可能なアプリケーションのヘッダーのところに戻りますが、各ページでヘッダーを再構築するのは非効率的なので、再利用します。再利用するコードには、すでにShared層がありますが、Shared層内の大きなUIブロックには注意が必要です。Shared層は上層のレイヤーについて何も知らないべきです。 + +Shared層とPages層の間には、Entities層、Features層、Widgets層の3つの他のレイヤーがあります。他のプロジェクトでは、これらのレイヤーに大きな再利用可能なブロックで使用したいものがあるかもしれません。その場合、そのブロックをShared層に置くことはできません。なぜなら、上層からインポートしなければならず、それは禁止されているからです。ここでWidgets層が役立ちます。これはShared層、Entities層、Features層の上に位置しているため、すべてを使用できます。 + +私たちの場合、ヘッダーは非常にシンプルです。静的なロゴと上部ナビゲーションしかありません。ナビゲーションはAPIに現在のユーザーが認証されているかどうかを尋ねる必要がありますが、これは`api`セグメントからの単純なインポートで解決できます。したがって、ヘッダーはShared層に残します。 + +### フォームページに着目 + +記事を読むだけでなく、編集することもできるページも見てみましょう。例えば、記事編集者のページです。 + +![Conduitの記事編集者](/img/tutorial/realworld-editor-authenticated.jpg) + +見た目は単純ですが、私たちがまだ調べていないアプリケーション開発のいくつかの側面を含んでいます。フォームのバリデーション、エラー状態、データの永続的な保存のようなものです。 + +このページを作成するには、Shared層からいくつかのフィールドとボタンを取り、それらをこのページの`ui`セグメントにあるフォームにまとめます。次に、`api`セグメントで、バックエンドに記事を作成するための変更リクエストを定義します。 + +リクエストを送信する前にリクエストをバリデーションするために、バリデーションスキーマが必要です。バリデーションスキーマはデータモデルであるため、`model`セグメントに入れるのがちょうど良いです。そこでエラーメッセージを生成し、`ui`セグメントの別のコンポーネントを使用してエラーメッセージを表示します。 + +UXを向上させるために、ブラウザを閉じたときに偶発的なデータ損失を防ぐために、入力データを永続的に保存することもできます。これも`model`セグメントに適しています。 + +### まとめ + +いくつかのページに着目し、アプリケーションの基本的な構造を決めることができました。 + +1. Shared層 + 1. `ui` には再利用可能なUIキットが含まれる + 2. `api` にはバックエンドとのインタラクションのためのプリミティブが含まれる + 3. 残りはコードを書く過程で整理する +2. Pages層 — 各ページに対して個別のスライスを作成 + 1. `ui` にはページ自体とその構成要素が含まれる + 2. `api` には`shared/api`を使用するデータ取得のためのより専用的な関数が含まれる + 3. `model` には表示するデータのクライアントストレージなどが含まれる + +これでこのアプリケーションを作りましょう! + +## 第2章 コードの中で + +計画ができたので、実現していきましょう。Reactと[Remix](https://remix.run/)を使用します。 + +このプロジェクトにはすでにテンプレートが用意されているので、GitHubからクローンして作成を始めてください。 + +[https://github.com/feature-sliced/tutorial-conduit/tree/clean](https://github.com/feature-sliced/tutorial-conduit/tree/clean) + +依存関係を`npm install`でインストールし、`npm run dev`でサーバーを起動します。[http://localhost:3000](http://localhost:3000/)を開くと、空のアプリケーションが表示されます。 + +### ページごとに整理する + +すべてのページのために空のコンポーネントを作成することから始めましょう。ターミナルで次のコマンドを実行します。 + +```bash +npx fsd pages feed sign-in article-read article-edit profile settings --segments ui +``` + +これにより、`pages/feed/ui/`のようなフォルダーと、各ページのインデックスファイル`pages/feed/index.ts`が作成されます。 + +### フィードページを接続する + +アプリケーションのルート(`/`)をフィードページに接続しましょう。`pages/feed/ui`に`FeedPage.tsx`コンポーネントを作成し、次の内容を入れます。 + +```tsx title="pages/feed/ui/FeedPage.tsx" +export function FeedPage() { + return ( +
+
+
+

conduit

+

知識を共有する場

+
+
+
+ ); +} +``` + +次に、このコンポーネントをフィードページの公開APIに再エクスポートします。 + +```tsx title="pages/feed/index.ts" +export { FeedPage } from "./ui/FeedPage"; +``` + +次に、ルートに接続します。Remixでは、ルーティングはファイルに基づいていて、ルートファイルは`app/routes`フォルダーにあります。これはFeature-Sliced Designとよく組み合っています。 + +`app/routes/_index.tsx`で`FeedPage`コンポーネントを使用します。 + +```tsx title="app/routes/_index.tsx" +import type { MetaFunction } from "@remix-run/node"; +import { FeedPage } from "pages/feed"; + +export const meta: MetaFunction = () => { + return [{ title: "Conduit" }]; +}; + +export default FeedPage; +``` + +これで、devサーバーを起動し、アプリケーションを開くと、Conduitのバナーが表示されるはずです! + +![Conduitのバナー](/img/tutorial/conduit-banner.jpg) + +### APIクライアント + +RealWorldのバックエンドと通信するために、Shared層内に便利なAPIクライアントを作成しましょう。クライアント用の`api`セグメントと、バックエンドの基本URLなどの変数用の`config`セグメントを作成します。 + +```bash +npx fsd shared --segments api config +``` + +次に、`shared/config/backend.ts`を作成します。 + +```tsx title="shared/config/backend.ts" +export const backendBaseUrl = "https://api.realworld.io/api"; +``` + +```tsx title="shared/config/index.ts" +export { backendBaseUrl } from "./backend"; +``` + +RealWorldプロジェクトは[OpenAPI仕様](https://github.com/gothinkster/realworld/blob/main/api/openapi.yml)を提供しているため、APIクライアントの型を自動的に生成できます。私たちは[`openapi-fetch`パッケージ](https://openapi-ts.pages.dev/openapi-fetch/)を使用します。このパッケージにはTypeScriptの型を自動生成するツールも含まれています。 + +次のコマンドを実行して、APIの最新の型を生成しましょう。 + +```bash +npm run generate-api-types +``` + +その結果、`shared/api/v1.d.ts`ファイルが作成されます。このファイルを使用して、`shared/api/client.ts`で型付きAPIクライアントを作成します。 + +```tsx title="shared/api/client.ts" +import createClient from "openapi-fetch"; + +import { backendBaseUrl } from "shared/config"; +import type { paths } from "./v1"; + +export const { GET, POST, PUT, DELETE } = createClient({ baseUrl: backendBaseUrl }); +``` + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; +``` + +### フィード内の実データ + +これで、バックエンドから記事を取得し、フィードに追加できます。まず、記事プレビューコンポーネントを実装しましょう。 + +`pages/feed/ui/ArticlePreview.tsx`を作成し、次の内容を記述します。 + +```tsx title="pages/feed/ui/ArticlePreview.tsx" +export function ArticlePreview({ article }) { /* TODO */ } +``` + +私たちはTypeScriptを使っているので、型付きのArticleオブジェクトを持つと良いでしょう。生成された`v1.d.ts`を調べると、Articleオブジェクトは`components["schemas"]["Article"]`を介して利用可能であることがわかります。これでShared層内にデータモデルを持つファイルを作成し、モデルをエクスポートしましょう。 + +```tsx title="shared/api/models.ts" +import type { components } from "./v1"; + +export type Article = components["schemas"]["Article"]; +``` + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; + +export type { Article } from "./models"; +``` + +これで、記事プレビューコンポーネントに戻って、データでマークアップを埋めることができます。次の内容をコンポーネントに追加します。 + +```tsx title="pages/feed/ui/ArticlePreview.tsx" +import { Link } from "@remix-run/react"; +import type { Article } from "shared/api"; + +interface ArticlePreviewProps { + article: Article; +} + +export function ArticlePreview({ article }: ArticlePreviewProps) { + return ( +
+
+ + + +
+ + {article.author.username} + + + {new Date(article.createdAt).toLocaleDateString(undefined, { + dateStyle: "long", + })} + +
+ +
+ +

{article.title}

+

{article.description}

+ 続きを読む... +
    + {article.tagList.map((tag) => ( +
  • + {tag} +
  • + ))} +
+ +
+ ); +} +``` + +「いいね」ボタンはまだ機能していません。それは記事の読み取りページに移動して、「いいね」機能を実装するときに修正します。 + +これで、記事を取得して、たくさんのプレビューカードを表示できます。Remixでは、データの取得は*ローダー*を使用して行われます。ローダーは、ページに必要なデータを収集するサーバー関数です。ローダーはページの代わりにAPIとやり取りをするため、`api`セグメントに配置します。 + +```tsx title="pages/feed/api/loader.ts" +import { json } from "@remix-run/node"; + +import { GET } from "shared/api"; + +export const loader = async () => { + const { data: articles, error, response } = await GET("/articles"); + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return json({ articles }); +}; +``` + +これをページに接続するには、ルートファイルから`loader`としてエクスポートする必要があります。 + +```tsx title="pages/feed/index.ts" +export { FeedPage } from "./ui/FeedPage"; +export { loader } from "./api/loader"; +``` + +```tsx title="app/routes/_index.tsx" +import type { MetaFunction } from "@remix-run/node"; +import { FeedPage } from "pages/feed"; + +export { loader } from "pages/feed"; + +export const meta: MetaFunction = () => { + return [{ title: "Conduit" }]; +}; + +export default FeedPage; +``` + +最後のステップは、これらのカードをフィードに表示することです。`FeedPage`を次のコードで更新します。 + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; + +export function FeedPage() { + const { articles } = useLoaderData(); + + return ( +
+
+
+

conduit

+

知識を共有する場

+
+
+ +
+
+
+ {articles.articles.map((article) => ( + + ))} +
+
+
+
+ ); +} +``` + +### タグによるフィルタリング + +タグに関しては、バックエンドから取得し、ユーザーが選択したタグを記憶する必要があります。私たちはバックエンドからの取得方法はすでに知っています。これはローダー関数からの別のリクエストです。すでにインストールされている`remix-utils`パッケージの便利な`promiseHash`関数を使用します。 + +`pages/feed/api/loader.ts`のローダーを次のコードで更新します。 + +```tsx title="pages/feed/api/loader.ts" +import { json } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async () => { + return json( + await promiseHash({ + articles: throwAnyErrors(GET("/articles")), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + +エラー処理を共通の`throwAnyErrors`関数に移したことに気付いたでしょうか。それはかなり使えそうに見えるので、後で再利用するかもしれません。 + +タグ一覧をインタラクティブにする必要があります。タグをクリックすると、そのタグが選択されるようにします。Remixの伝統に従い、選択されたタグのストレージとしてURLのクエリパラメータを使用します。ブラウザにストレージを任せ、私たちはより重要なことに集中しましょう。 + +`pages/feed/ui/FeedPage.tsx`を次のコードで更新します。 + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { Form, useLoaderData } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import type { loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; + +export function FeedPage() { + const { articles, tags } = useLoaderData(); + + return ( +
+
+
+

conduit

+

知識を共有する場

+
+
+ +
+
+
+ {articles.articles.map((article) => ( + + ))} +
+ +
+
+

人気のタグ

+ +
+ +
+ {tags.tags.map((tag) => ( + + ))} +
+ +
+
+
+
+
+ ); +} +``` + +次に、タグの検索パラメータをローダーで使用する必要があります。`pages/feed/api/loader.ts`の`loader`関数を次のように変更します。 + +```tsx title="pages/feed/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const url = new URL(request.url); + const selectedTag = url.searchParams.get("tag") ?? undefined; + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles", { params: { query: { tag: selectedTag } } }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + +以上です。最終的に`model`セグメントは必要ありませんでした。Remixはすごいですよね。 + +### ページネーション + +同様に、ページネーションを実装できます。自分で実装してみても、以下のコードをコピーしても良いです。 + +```tsx title="pages/feed/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +/** 1ページあたりの記事の数。 */ +export const LIMIT = 20; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const url = new URL(request.url); + const selectedTag = url.searchParams.get("tag") ?? undefined; + const page = parseInt(url.searchParams.get("page") ?? "", 10); + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles", { + params: { + query: { + tag: selectedTag, + limit: LIMIT, + offset: !Number.isNaN(page) ? page * LIMIT : undefined, + }, + }, + }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { Form, useLoaderData, useSearchParams } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import { LIMIT, type loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; + +export function FeedPage() { + const [searchParams] = useSearchParams(); + const { articles, tags } = useLoaderData(); + const pageAmount = Math.ceil(articles.articlesCount / LIMIT); + const currentPage = parseInt(searchParams.get("page") ?? "1", 10); + + return ( +
+
+
+

conduit

+

知識を共有する場

+
+
+ +
+
+
+ {articles.articles.map((article) => ( + + ))} + +
+ +
    + {Array(pageAmount) + .fill(null) + .map((_, index) => + index + 1 === currentPage ? ( +
  • + {index + 1} +
  • + ) : ( +
  • + +
  • + ), + )} +
+ +
+ +
+
+

人気のタグ

+ +
+ +
+ {tags.tags.map((tag) => ( + + ))} +
+ +
+
+
+
+
+ ); +} +``` + +よし、これも実現しました。タグ一覧も同様に実装できますが、認証を実装するまで待ちましょう。ところで、認証についてですが! + +### 認証 + +認証には、ログイン用のページと登録用のページの2つがあります。これらは主に非常に似ているため、必要に応じてコードを再利用できるように、1つの`sign-in`セグメントに保持するのが理にかなっています。 + +`pages/sign-in`の`ui`セグメントに`RegisterPage.tsx`を作成し、次の内容を配置します。 + +```tsx title="pages/sign-in/ui/RegisterPage.tsx" +import { Form, Link, useActionData } from "@remix-run/react"; + +import type { register } from "../api/register"; + +export function RegisterPage() { + const registerData = useActionData(); + + return ( +
+
+
+
+

登録

+

+ アカウントをお持ちですか? +

+ + {registerData?.error && ( +
    + {registerData.error.errors.body.map((error) => ( +
  • {error}
  • + ))} +
+ )} + +
+
+ +
+
+ +
+
+ +
+ +
+
+
+
+
+ ); +} +``` + +これからは壊れたインポートを修正する必要があります。インポートが新しいセグメントにアクセスしているため、次のコマンドでそのセグメントを作成しましょう。 + +```bash +npx fsd pages sign-in -s api +``` + +ただし、登録のバックエンド部分を実装する前に、Remixのセッション処理のためのインフラコードが必要です。これは他のページでも必要になる可能性があるため、Shared層に配置します。 + +次のコードを`shared/api/auth.server.ts`に配置しましょう。このコードはRemixに特有のものであり、すべてが理解できなくても心配しないでください。単にコピーして貼り付けてください。 + +```tsx title="shared/api/auth.server.ts" +import { createCookieSessionStorage, redirect } from "@remix-run/node"; +import invariant from "tiny-invariant"; + +import type { User } from "./models"; + +invariant( + process.env.SESSION_SECRET, + "SESSION_SECRET must be set for authentication to work", +); + +const sessionStorage = createCookieSessionStorage<{ + user: User; +}>({ + cookie: { + name: "__session", + httpOnly: true, + path: "/", + sameSite: "lax", + secrets: [process.env.SESSION_SECRET], + secure: process.env.NODE_ENV === "production", + }, +}); + +export async function createUserSession({ + request, + user, + redirectTo, +}: { + request: Request; + user: User; + redirectTo: string; +}) { + const cookie = request.headers.get("Cookie"); + const session = await sessionStorage.getSession(cookie); + + session.set("user", user); + + return redirect(redirectTo, { + headers: { + "Set-Cookie": await sessionStorage.commitSession(session, { + maxAge: 60 * 60 * 24 * 7, // 7日間 + }), + }, + }); +} + +export async function getUserFromSession(request: Request) { + const cookie = request.headers.get("Cookie"); + const session = await sessionStorage.getSession(cookie); + + return session.get("user") ?? null; +} + +export async function requireUser(request: Request) { + const user = await getUserFromSession(request); + + if (user === null) { + throw redirect("/login"); + } + + return user; +} +``` + +また、`models.ts`ファイルから`User`モデルをエクスポートしてください。 + +```tsx title="shared/api/models.ts" +import type { components } from "./v1"; + +export type Article = components["schemas"]["Article"]; +export type User = components["schemas"]["User"]; +``` + +このコードが動作する前に、`SESSION_SECRET`環境変数を設定する必要があります。プロジェクトのルートに`.env`ファイルを作成し、`SESSION_SECRET=`を記述してから、適当にランダムな文字列を記入します。次のようになります。 + +```bash title=".env" +SESSION_SECRET=これをコピーしないでください +``` + +最後に、公開APIにいくつかのエクスポートを追加します。 + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; + +export type { Article } from "./models"; + +export { createUserSession, getUserFromSession, requireUser } from "./auth.server"; +``` + +これで、RealWorldのバックエンドと通信するコードを書くことができます。これを`pages/sign-in/api`に保存します。`register.ts`ファイルを作成して、中に次のコードを配置しましょう。 + +```tsx title="pages/sign-in/api/register.ts" +import { json, type ActionFunctionArgs } from "@remix-run/node"; + +import { POST, createUserSession } from "shared/api"; + +export const register = async ({ request }: ActionFunctionArgs) => { + const formData = await request.formData(); + const username = formData.get("username")?.toString() ?? ""; + const email = formData.get("email")?.toString() ?? ""; + const password = formData.get("password")?.toString() ?? ""; + + const { data, error } = await POST("/users", { + body: { user: { email, password, username } }, + }); + + if (error) { + return json({ error }, { status: 400 }); + } else { + return createUserSession({ + request: request, + user: data.user, + redirectTo: "/", + }); + } +}; +``` + +```tsx title="pages/sign-in/index.ts" +export { RegisterPage } from './ui/RegisterPage'; +export { register } from './api/register'; +``` + +ほぼ完成です!残りの部分は、`/register`ルートにアクションとページを接続することだけです。`app/routes`で`register.tsx`を作成します。 + +```tsx title="app/routes/register.tsx" +import { RegisterPage, register } from "pages/sign-in"; + +export { register as action }; + +export default RegisterPage; +``` + +これで、[http://localhost:3000/register](http://localhost:3000/register)にアクセスすると、ユーザーを作成できます!アプリケーションの残りの部分は、まだ反応しませんが、近々対処します。 + +同様に、ログインページを実装することもできます。自分で実装してみるか、下記のコードをコピペするか、次に進みましょう。 + +```tsx title="pages/sign-in/api/sign-in.ts" +import { json, type ActionFunctionArgs } from "@remix-run/node"; + +import { POST, createUserSession } from "shared/api"; + +export const signIn = async ({ request }: ActionFunctionArgs) => { + const formData = await request.formData(); + const email = formData.get("email")?.toString() ?? ""; + const password = formData.get("password")?.toString() ?? ""; + + const { data, error } = await POST("/users/login", { + body: { user: { email, password } }, + }); + + if (error) { + return json({ error }, { status: 400 }); + } else { + return createUserSession({ + request: request, + user: data.user, + redirectTo: "/", + }); + } +}; +``` + +```tsx title="pages/sign-in/ui/SignInPage.tsx" +import { Form, Link, useActionData } from "@remix-run/react"; + +import type { signIn } from "../api/sign-in"; + +export function SignInPage() { + const signInData = useActionData(); + + return ( +
+
+
+
+

サインイン

+

+ アカウントが必要ですか? +

+ + {signInData?.error && ( +
    + {signInData.error.errors.body.map((error) => ( +
  • {error}
  • + ))} +
+ )} + +
+
+ +
+
+ +
+ +
+
+
+
+
+ ); +} +``` + +```tsx title="pages/sign-in/index.ts" +export { RegisterPage } from './ui/RegisterPage'; +export { register } from './api/register'; +export { SignInPage } from './ui/SignInPage'; +export { signIn } from './api/sign-in'; +``` + +```tsx title="app/routes/login.tsx" +import { SignInPage, signIn } from "pages/sign-in"; + +export { signIn as action }; + +export default SignInPage; +``` + +これで、ユーザーがこれらのページにアクセスできるようになりました。 + +### ヘッダー + +前章で説明されたように、アプリケーションのヘッダーは通常Widgets層、またはShared層に配置されます。ヘッダーは非常にシンプルで、すべてのビジネスロジックを外部に保持できるので、Shared層に配置しましょう。ヘッダー用のフォルダーを作成します。 + +```bash +npx fsd shared ui +``` + +次に、`shared/ui/Header.tsx`を作成し、次の内容を配置します。 + +```tsx title="shared/ui/Header.tsx" +import { useContext } from "react"; +import { Link, useLocation } from "@remix-run/react"; + +import { CurrentUser } from "../api/currentUser"; + +export function Header() { + const currentUser = useContext(CurrentUser); + const { pathname } = useLocation(); + + return ( + + ); +} +``` + +このコンポーネントを`shared/ui`からエクスポートします。 + +```tsx title="shared/ui/index.ts" +export { Header } from "./Header"; +``` + +ヘッダーで`shared/api`にあるコンテキストを使っているので、それを作成しましょう。 + +```tsx title="shared/api/currentUser.ts" +import { createContext } from "react"; + +import type { User } from "./models"; + +export const CurrentUser = createContext(null); +``` + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; + +export type { Article } from "./models"; + +export { createUserSession, getUserFromSession, requireUser } from "./auth.server"; +export { CurrentUser } from "./currentUser"; +``` + +これで、ヘッダーをページに追加できます。すべてのページに表示されるように、ルートに追加し、アウトレット(ページがレンダリングされる場所)を`CurrentUser`のコンテキストプロバイダーで包みます。これにより、ヘッダーを含むアプリ全体が現在のユーザーオブジェクトにアクセスできるようになります。また、クッキーから現在のユーザーオブジェクトを取得するためのローダーも追加します。次のコードを`app/root.tsx`に追加しましょう。 + +```tsx title="app/root.tsx" +import { cssBundleHref } from "@remix-run/css-bundle"; +import type { LinksFunction, LoaderFunctionArgs } from "@remix-run/node"; +import { + Links, + LiveReload, + Meta, + Outlet, + Scripts, + ScrollRestoration, + useLoaderData, +} from "@remix-run/react"; + +import { Header } from "shared/ui"; +import { getUserFromSession, CurrentUser } from "shared/api"; + +export const links: LinksFunction = () => [ + ...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []), +]; + +export const loader = ({ request }: LoaderFunctionArgs) => + getUserFromSession(request); + +export default function App() { + const user = useLoaderData(); + + return ( + + + + + + + + + + + + + +
+ + + + + + + + ); +} +``` + +最終的に、ホームページは次のようになります。 + +
+ ![ヘッダー、フィード、タグがあるConduitのフィードページ。タブはまだありません。](/img/tutorial/realworld-feed-without-tabs.jpg) + +
ヘッダー、フィード、タグがあるConduitのフィードページ。タブはまだない。
+
+ +### タブ + +これで認証状態を判断できるようになったので、タブと「いいね」ボタンをフィードページに実装しましょう。新しいフォームを作る必要がありますが、このページファイルはすでに大きすぎるので、これらのフォームを隣接するファイルに移動しましょう。`Tabs.tsx`、`PopularTags.tsx`、`Pagination.tsx`を作成し、次の内容を配置します。 + +```tsx title="pages/feed/ui/Tabs.tsx" +import { useContext } from "react"; +import { Form, useSearchParams } from "@remix-run/react"; + +import { CurrentUser } from "shared/api"; + +export function Tabs() { + const [searchParams] = useSearchParams(); + const currentUser = useContext(CurrentUser); + + return ( +
+
+
    + {currentUser !== null && ( +
  • + +
  • + )} +
  • + +
  • + {searchParams.has("tag") && ( +
  • + + {searchParams.get("tag")} + +
  • + )} +
+
+
+ ); +} +``` + +```tsx title="pages/feed/ui/PopularTags.tsx" +import { Form, useLoaderData } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import type { loader } from "../api/loader"; + +export function PopularTags() { + const { tags } = useLoaderData(); + + return ( +
+

人気のタグ

+ +
+ +
+ {tags.tags.map((tag) => ( + + ))} +
+ +
+ ); +} +``` + +```tsx title="pages/feed/ui/Pagination.tsx" +import { Form, useLoaderData, useSearchParams } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import { LIMIT, type loader } from "../api/loader"; + +export function Pagination() { + const [searchParams] = useSearchParams(); + const { articles } = useLoaderData(); + const pageAmount = Math.ceil(articles.articlesCount / LIMIT); + const currentPage = parseInt(searchParams.get("page") ?? "1", 10); + + return ( +
+ +
    + {Array(pageAmount) + .fill(null) + .map((_, index) => + index + 1 === currentPage ? ( +
  • + {index + 1} +
  • + ) : ( +
  • + +
  • + ), + )} +
+ + ); +} +``` + +これで、フィードページを大幅に簡素化できます。 + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; +import { Tabs } from "./Tabs"; +import { PopularTags } from "./PopularTags"; +import { Pagination } from "./Pagination"; + +export function FeedPage() { + const { articles } = useLoaderData(); + + return ( +
+
+
+

conduit

+

知識を共有する場

+
+
+ +
+
+
+ + + {articles.articles.map((article) => ( + + ))} + + +
+ +
+ +
+
+
+
+ ); +} +``` + +ローダー関数にも新しいタブを考慮する必要があります。 + +```tsx title="pages/feed/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET, requireUser } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + /* そのまま */ +} + +/** 1ページあたりの記事数。 */ +export const LIMIT = 20; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const url = new URL(request.url); + const selectedTag = url.searchParams.get("tag") ?? undefined; + const page = parseInt(url.searchParams.get("page") ?? "", 10); + + if (url.searchParams.get("source") === "my-feed") { + const userSession = await requireUser(request); + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles/feed", { + params: { + query: { + limit: LIMIT, + offset: !Number.isNaN(page) ? page * LIMIT : undefined, + }, + }, + headers: { Authorization: `Token ${userSession.token}` }, + }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); + } + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles", { + params: { + query: { + tag: selectedTag, + limit: LIMIT, + offset: !Number.isNaN(page) ? page * LIMIT : undefined, + }, + }, + }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + +フィードページを一旦置いておく前に、投稿へのいいねを処理するコードを追加しましょう。`ArticlePreview.tsx`を次のように変更します。 + + +```tsx title="pages/feed/ui/ArticlePreview.tsx" +import { Form, Link } from "@remix-run/react"; +import type { Article } from "shared/api"; + +interface ArticlePreviewProps { + article: Article; +} + +export function ArticlePreview({ article }: ArticlePreviewProps) { + return ( +
+
+ + + +
+ + {article.author.username} + + + {new Date(article.createdAt).toLocaleDateString(undefined, { + dateStyle: "long", + })} + +
+
+ +
+
+ +

{article.title}

+

{article.description}

+ もっと読む... +
    + {article.tagList.map((tag) => ( +
  • + {tag} +
  • + ))} +
+ +
+ ); +} +``` + +このコードは、`/article/:slug`にPOSTリクエストを送信し、`_action=favorite`を使用して記事をお気に入りにします。今は機能していませんが、記事リーダーの作成を始めると、これも実装します。 + +これで、フィードの作成が完了しました!やったね! + +### 記事リーダー + +まず、データが必要です。ローダーを作成しましょう。 + +```bash +npx fsd pages article-read -s api +``` + +```tsx title="pages/article-read/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import invariant from "tiny-invariant"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET, getUserFromSession } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async ({ request, params }: LoaderFunctionArgs) => { + invariant(params.slug, "スラッグパラメータが必要です"); + const currentUser = await getUserFromSession(request); + const authorization = currentUser + ? { Authorization: `Token ${currentUser.token}` } + : undefined; + + return json( + await promiseHash({ + article: throwAnyErrors( + GET("/articles/{slug}", { + params: { + path: { slug: params.slug }, + }, + headers: authorization, + }), + ), + comments: throwAnyErrors( + GET("/articles/{slug}/comments", { + params: { + path: { slug: params.slug }, + }, + headers: authorization, + }), + ), + }), + ); +}; +``` + +```tsx title="pages/article-read/index.ts" +export { loader } from "./api/loader"; +``` + +これで、`/article/:slug`ルートに接続できます。`article.$slug.tsx`というルートファイルを作成します。 + +```tsx title="app/routes/article.$slug.tsx" +export { loader } from "pages/article-read"; +``` + +ページ自体は、記事のタイトルとアクション、記事の本文、コメントセクションの3つの主要なブロックで構成されています。下記はページのマークアップで、特に興味深いものはありません。 + +```tsx title="pages/article-read/ui/ArticleReadPage.tsx" +import { useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { ArticleMeta } from "./ArticleMeta"; +import { Comments } from "./Comments"; + +export function ArticleReadPage() { + const { article } = useLoaderData(); + + return ( +
+
+
+

{article.article.title}

+ + +
+
+ +
+
+
+

{article.article.body}

+
    + {article.article.tagList.map((tag) => ( +
  • + {tag} +
  • + ))} +
+
+
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +} +``` + +興味深いのは`ArticleMeta`と`Comments`です。これらは、記事を「いいね」したり、コメントを残したりするための操作を含んでいます。これらが機能するためには、まずバックエンド部分を実装する必要があります。このページの`api`セグメントに`action.ts`ファイルを作成します。 + +```tsx title="pages/article-read/api/action.ts" +import { redirect, type ActionFunctionArgs } from "@remix-run/node"; +import { namedAction } from "remix-utils/named-action"; +import { redirectBack } from "remix-utils/redirect-back"; +import invariant from "tiny-invariant"; + +import { DELETE, POST, requireUser } from "shared/api"; + +export const action = async ({ request, params }: ActionFunctionArgs) => { + const currentUser = await requireUser(request); + + const authorization = { Authorization: `Token ${currentUser.token}` }; + + const formData = await request.formData(); + + return namedAction(formData, { + async delete() { + invariant(params.slug, "スラッグパラメータが必要です"); + await DELETE("/articles/{slug}", { + params: { path: { slug: params.slug } }, + headers: authorization, + }); + return redirect("/"); + }, + async favorite() { + invariant(params.slug, "スラッグパラメータが必要です"); + await POST("/articles/{slug}/favorite", { + params: { path: { slug: params.slug } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async unfavorite() { + invariant(params.slug, "スラッグパラメータが必要です"); + await DELETE("/articles/{slug}/favorite", { + params: { path: { slug: params.slug } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async createComment() { + invariant(params.slug, "スラッグパラメータが必要です"); + const comment = formData.get("comment"); + invariant(typeof comment === "string", "コメントパラメータが必要です"); + await POST("/articles/{slug}/comments", { + params: { path: { slug: params.slug } }, + headers: { ...authorization, "Content-Type": "application/json" }, + body: { comment: { body: comment } }, + }); + return redirectBack(request, { fallback: "/" }); + }, + async deleteComment() { + invariant(params.slug, "スラッグパラメータが必要です"); + const commentId = formData.get("id"); + invariant(typeof commentId === "string", "idパラメータが必要です"); + const commentIdNumeric = parseInt(commentId, 10); + invariant( + !Number.isNaN(commentIdNumeric), + "数値のidパラメータが必要です", + ); + await DELETE("/articles/{slug}/comments/{id}", { + params: { path: { slug: params.slug, id: commentIdNumeric } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async followAuthor() { + const authorUsername = formData.get("username"); + invariant( + typeof authorUsername === "string", + "ユーザーネームパラメータが必要です", + ); + await POST("/profiles/{username}/follow", { + params: { path: { username: authorUsername } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async unfollowAuthor() { + const authorUsername = formData.get("username"); + invariant( + typeof authorUsername === "string", + "ユーザーネームパラメータが必要です", + ); + await DELETE("/profiles/{username}/follow", { + params: { path: { username: authorUsername } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + }); +}; +``` + +これをスライスから再エクスポートし、ルートから再エクスポートします。ここにいる間に、ページ自体も接続しましょう。 + +```tsx title="pages/article-read/index.ts" +export { ArticleReadPage } from "./ui/ArticleReadPage"; +export { loader } from "./api/loader"; +export { action } from "./api/action"; +``` + +```tsx title="app/routes/article.$slug.tsx" +import { ArticleReadPage } from "pages/article-read"; + +export { loader, action } from "pages/article-read"; + +export default ArticleReadPage; +``` + +これで、記事リーダーの「いいね」ボタンはまだ実装されていないにも関わらず、フィードの「いいね」ボタンは機能し始めます!それは、フィードの「いいね」ボタンもそのルートにリクエストを送っているからです。何かを「いいね」してみてください! + +`ArticleMeta`と`Comments`は、単なるフォームです。以前にこれを行ったので、コードをコピペして先に進みましょう。 + +```tsx title="pages/article-read/ui/ArticleMeta.tsx" +import { Form, Link, useLoaderData } from "@remix-run/react"; +import { useContext } from "react"; + +import { CurrentUser } from "shared/api"; +import type { loader } from "../api/loader"; + +export function ArticleMeta() { + const currentUser = useContext(CurrentUser); + const { article } = useLoaderData(); + + return ( +
+
+ + + + +
+ + {article.article.author.username} + + {article.article.createdAt} +
+ + {article.article.author.username == currentUser?.username ? ( + <> + + 記事を編集 + +    + + + ) : ( + <> + + +    + + + )} +
+
+ ); +} +``` + +```tsx title="pages/article-read/ui/Comments.tsx" +import { useContext } from "react"; +import { Form, Link, useLoaderData } from "@remix-run/react"; + +import { CurrentUser } from "shared/api"; +import type { loader } from "../api/loader"; + +export function Comments() { + const { comments } = useLoaderData(); + const currentUser = useContext(CurrentUser); + + return ( +
+ {currentUser !== null ? ( +
+
+ +
+
+ + +
+
+ ) : ( +
+
+

+ サインイン +   または   + 登録 +   して記事にコメントを追加しましょう! +

+
+
+ )} + + {comments.comments.map((comment) => ( +
+
+

{comment.body}

+
+ +
+ + + +   + + {comment.author.username} + + {comment.createdAt} + {comment.author.username === currentUser?.username && ( + +
+ + +
+
+ )} +
+
+ ))} +
+ ); +} +``` + +これで、記事リーダーが完成しました!「著者をフォローする」ボタン、「いいね」ボタン、「コメントを残す」ボタンがすべて正常に機能するはずです。 + +
+ ![記事リーダーの画像](/img/tutorial/realworld-article-reader.jpg) + +
記事リーダーの画像
+
+ +### 記事編集 + +これは、このガイドで最後に取り上げるページです。ここで最も興味深い部分は、フォームデータを検証する方法です。 + +`article-edit/ui/ArticleEditPage.tsx`ページ自体は、非常にシンプルで、追加のロジックは他の2つのコンポーネントに含まれます。 + +```tsx title="pages/article-edit/ui/ArticleEditPage.tsx" +import { Form, useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { TagsInput } from "./TagsInput"; +import { FormErrors } from "./FormErrors"; + +export function ArticleEditPage() { + const article = useLoaderData(); + + return ( +
+
+
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+
+
+
+ ); +} +``` + +このページは、存在する記事を取得し(新しい記事を作成する場合を除く)、対応するフォームフィールドを埋めます。これは以前に見たものです。着目すべき部分は`FormErrors`で、これは検証結果を取得し、ユーザーに表示します。 + +```tsx title="pages/article-edit/ui/FormErrors.tsx" +import { useActionData } from "@remix-run/react"; +import type { action } from "../api/action"; + +export function FormErrors() { + const actionData = useActionData(); + + return actionData?.errors != null ? ( +
    + {actionData.errors.map((error) => ( +
  • {error}
  • + ))} +
+ ) : null; +} +``` + +アクションが`errors`フィールドを返し、人間に理解できるエラーメッセージの配列を表示することを想定しています。アクションには後で移ります。 + +もう1つのコンポーネントはタグ入力フィールドです。これは、選択されたタグのプレビューできる通常の入力フィールドです。特に注目すべき点はありません。 + +```tsx title="pages/article-edit/ui/TagsInput.tsx" +import { useEffect, useRef, useState } from "react"; + +export function TagsInput({ + name, + defaultValue, +}: { + name: string; + defaultValue?: Array; +}) { + const [tagListState, setTagListState] = useState(defaultValue ?? []); + + function removeTag(tag: string): void { + const newTagList = tagListState.filter((t) => t !== tag); + setTagListState(newTagList); + } + + const tagsInput = useRef(null); + useEffect(() => { + tagsInput.current && (tagsInput.current.value = tagListState.join(",")); + }, [tagListState]); + + return ( + <> + + setTagListState(e.target.value.split(",").filter(Boolean)) + } + /> +
+ {tagListState.map((tag) => ( + + + [" ", "Enter"].includes(e.key) && removeTag(tag) + } + onClick={() => removeTag(tag)} + >{" "} + {tag} + + ))} +
+ + ); +} +``` + +次に、API部分に移ります。ローダーはURLを確認し、記事へのリンクがある場合、既存の記事を編集していることを意味し、そのデータをロードする必要があります。そうでない場合は、何も返しません。このローダーを作成しましょう。 + +```tsx title="pages/article-edit/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; + +import { GET, requireUser } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async ({ params, request }: LoaderFunctionArgs) => { + const currentUser = await requireUser(request); + + if (!params.slug) { + return { article: null }; + } + + return throwAnyErrors( + GET("/articles/{slug}", { + params: { path: { slug: params.slug } }, + headers: { Authorization: `Token ${currentUser.token}` }, + }), + ); +}; +``` + +アクションは新しいフィールドの値を受け取り、それらをデータスキーマに通し、すべてが正しければ、既存の記事を更新するか、新しい記事を作成することによって、バックエンドに変更を保存します。 + +```tsx title="pages/article-edit/api/action.ts" +import { json, redirect, type ActionFunctionArgs } from "@remix-run/node"; + +import { POST, PUT, requireUser } from "shared/api"; +import { parseAsArticle } from "../model/parseAsArticle"; + +export const action = async ({ request, params }: ActionFunctionArgs) => { + try { + const { body, description, title, tags } = parseAsArticle( + await request.formData(), + ); + const tagList = tags?.split(",") ?? []; + + const currentUser = await requireUser(request); + const payload = { + body: { + article: { + title, + description, + body, + tagList, + }, + }, + headers: { Authorization: `Token ${currentUser.token}` }, + }; + + const { data, error } = await (params.slug + ? PUT("/articles/{slug}", { + params: { path: { slug: params.slug } }, + ...payload, + }) + : POST("/articles", payload)); + + if (error) { + return json({ errors: error }, { status: 422 }); + } + + return redirect(`/article/${data.article.slug ?? ""}`); + } catch (errors) { + return json({ errors }, { status: 400 }); + } +}; +``` + +私たちのデータスキーマは、`FormData`を解析するので、最終的に処理するエラーメッセージを投げたりするのに役立ちます。この解析関数は次のようになります。 + +```tsx title="pages/article-edit/model/parseAsArticle.ts" +export function parseAsArticle(data: FormData) { + const errors = []; + + const title = data.get("title"); + if (typeof title !== "string" || title === "") { + errors.push("記事にタイトルを付けてください"); + } + + const description = data.get("description"); + if (typeof description !== "string" || description === "") { + errors.push("この記事が何についてか説明してください"); + } + + const body = data.get("body"); + if (typeof body !== "string" || body === "") { + errors.push("記事そのものを書いてください"); + } + + const tags = data.get("tags"); + if (typeof tags !== "string") { + errors.push("タグは文字列である必要があります"); + } + + if (errors.length > 0) { + throw errors; + } + + return { title, description, body, tags: data.get("tags") ?? "" } as { + title: string; + description: string; + body: string; + tags: string; + }; +} +``` + +少し長く繰り返しが多いように見えるかもしれませんが、これはエラーメッセージを人間に理解しやすくするための代償です。Zodのようなスキーマを使用することもできますが、その場合、フロントエンドでエラーメッセージを表示する必要があります。このフォームはそのような複雑さには値しません。 + +最後のステップは、ページ、ローダー、アクションをルートに接続することです。私たちは作成と編集の両方をきれいにサポートしているので、`editor._index.tsx`と`editor.$slug.tsx`の両方から同じアクションをエクスポートできます。 + +```tsx title="pages/article-edit/index.ts" +export { ArticleEditPage } from "./ui/ArticleEditPage"; +export { loader } from "./api/loader"; +export { action } from "./api/action"; +``` + +```tsx title="app/routes/editor._index.tsx, app/routes/editor.$slug.tsx (同じ内容)" +import { ArticleEditPage } from "pages/article-edit"; + +export { loader, action } from "pages/article-edit"; + +export default ArticleEditPage; +``` + +これで完成です!ログインして新しい記事を作成してみてください。あるいは、フィールドに何も記入せず進み、バリデーションがどのように機能するかを検証してみてください。 + +
+ ![記事編集者の画像](/img/tutorial/realworld-article-editor.jpg) + +
記事編集画像
+
+ +プロフィールページや設定ページは、記事の読み取りや編集ページに非常に似ていて、読者のための宿題として残されています。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/_category_.yaml b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/_category_.yaml new file mode 100644 index 0000000000..685e78df8d --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/_category_.yaml @@ -0,0 +1,2 @@ +label: 例 +position: 1 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md new file mode 100644 index 0000000000..264a970c26 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md @@ -0,0 +1,229 @@ +--- +sidebar_position: 1 +--- + +# 認証 + +一般的に、認証は以下のステップで構成されます。 + +1. ユーザーから資格情報を取得する +2. それをバックエンドに送信する +3. 認証されたリクエストを送信するためのトークンを保存する + +## ユーザーの資格情報を取得する方法 + +OAuthを通じて認証を行う場合は、OAuthプロバイダーのページへのリンクを持つログインページを作成し、[ステップ3](#how-to-store-the-token-for-authenticated-requests)に進むことができます。 + +### ログイン用の別ページ + +通常、ウェブサイトにはユーザー名とパスワードを入力するためのログイン専用ページがあります。これらのページは非常にシンプルであるため、分解する必要はありません。さらに、ログインフォームと登録フォームは外見が非常に似ているため、同じページにグループ化することもできます。ログイン/登録ページ用のスライスをPages層に作成します。 + +- 📂 pages + - 📂 login + - 📂 ui + - 📄 LoginPage.tsx + - 📄 RegisterPage.tsx + - 📄 index.ts + - その他のページ… + +ここでは、2つのコンポーネントを作成し、インデックスで両方をエクスポートしました。これらのコンポーネントは、ユーザーが資格情報を入力するためのわかりやすい要素を含むフォームを持ちます。 + +### ログイン用のダイアログボックス + +アプリケーションにどのページでも使用できるログイン用のダイアログボックスがある場合は、そのダイアログボックス用のウィジェットを作成できます。これにより、フォーム自体をあまり分解せずに、どのページでもこのダイアログボックスを再利用できます。 + +- 📂 widgets + - 📂 login-dialog + - 📂 ui + - 📄 LoginDialog.tsx + - 📄 index.ts + - その他のウィジェット… + +このガイドの残りの部分は、ログインが別ページで行われる最初のアプローチに基づいていますが、同じ原則がダイアログボックス用のウィジェットにも適用されます。 + +### クライアントバリデーション + +たまには、特に登録時に、クライアント側で検証を行い、ユーザーにエラーを迅速に通知することがあります。この場合、検証は、ログインページの`model`セグメントで行うことができます。スキーマ検証ライブラリ、例えば[Zod][ext-zod]をJS/TS用に使用し、このスキーマを`ui`セグメントに提供します。 + + +```ts title="pages/login/model/registration-schema.ts" +import { z } from "zod"; + +export const registrationData = z.object({ + email: z.string().email(), + password: z.string().min(6), + confirmPassword: z.string(), +}).refine((data) => data.password === data.confirmPassword, { + message: "パスワードが一致しません", + path: ["confirmPassword"], +}); +``` + +次に、`ui`セグメントでこのスキーマを使用してユーザー入力を検証できます。 + +```tsx title="pages/login/ui/RegisterPage.tsx" +import { registrationData } from "../model/registration-schema"; + +function validate(formData: FormData) { + const data = Object.fromEntries(formData.entries()); + try { + registrationData.parse(data); + } catch (error) { + // TODO: ユーザーにエラーメッセージを表示 + } +} + +export function RegisterPage() { + return ( +
validate(new FormData(e.target))}> + + + + + + + + +
+ ) +} +``` + +## 資格情報をバックエンドに送信する方法 + +バックエンドのログインエンドポイントにリクエストを送信する関数を作成しましょう。この関数は、コンポーネントのコード内でミューテーションライブラリ(例えば、TanStack Query)を通じて直接呼び出すことも、状態管理ライブラリの副作用として呼び出すこともできます。 + +### リクエスト関数をどこに置くか + +この関数を置く場所は2つあります: `shared/api`またはページの`api`セグメントです。 + +#### `shared/api`に + +このアプローチは、すべてのリクエスト関数を`shared/api`に配置し、エンドポイントごとにグループ化するのに適しています。この場合、ファイル構造は次のようになります。 + +- 📂 shared + - 📂 api + - 📂 endpoints + - 📄 login.ts + - その他のリクエスト関数… + - 📄 client.ts + - 📄 index.ts + +`📄 client.ts`ファイルには、リクエストを実行するためのプリミティブのラッパーが含まれています(例えば、`fetch()`)。このラッパーは、バックエンドのベースURLを知っており、必要なヘッダーを設定し、データをシリアライズします。 + +```ts title="shared/api/endpoints/login.ts" +import { POST } from "../client"; + +export function login({ email, password }: { email: string, password: string }) { + return POST("/login", { email, password }); +} +``` + +```ts title="shared/api/index.ts" +export { login } from "./endpoints/login"; +``` + +#### ページの`api`セグメントに + +すべてのリクエストを1か所に保存していない場合は、ログインページの`api`セグメントにこのリクエスト関数を配置するのが適しているかもしれません。 + +- 📂 pages + - 📂 login + - 📂 api + - 📄 login.ts + - 📂 ui + - 📄 LoginPage.tsx + - 📄 index.ts + - その他のページ… + + +```ts title="pages/login/api/login.ts" +import { POST } from "shared/api"; + +export function login({ email, password }: { email: string, password: string }) { + return POST("/login", { email, password }); +} +``` + + +この関数は、ページのインデックスから再エクスポートする必要はありません。なぜなら、恐らくこのページ内でのみ使用されるからです。 + +### 2要素認証 + +アプリケーションが2要素認証(2FA)をサポートしている場合、ユーザーを一時的なパスワードを入力するための別のページにリダイレクトする必要があるかもしれません。通常、`POST /login`リクエストは、ユーザーに2FAが有効であることを示すフラグを持つユーザーオブジェクトを返します。このフラグが設定されている場合、ユーザーを2FAページにリダイレクトします。 + +このページはログインと非常に関連しているため、Pages層の同じ`login`スライスに配置することもできます。 + +また、上で作成した`login()`に似た別のリクエスト関数が必要になります。それらをShared層にまとめるか、ログインページの`api`セグメントに配置してください。 + +## 認証されたリクエスト用のトークンを保存する方法 {#how-to-store-the-token-for-authenticated-requests} + +使用する認証スキームに関係なく、単純なログインとパスワード、OAuth、または2要素認証であっても、最終的にはトークンを取得します。以降のリクエストで自分を識別できるように、このトークンは保存する必要があります。 + +ウェブアプリケーションにおけるトークンの理想的な保存場所は**クッキー**です。クッキーはトークンの手動保存や処理を必要としません。したがって、クッキーの保存はフロントエンドアーキテクチャにほとんど労力を必要としません。フロントエンドフレームワークにサーバーサイドがある場合(例えば、[Remix][ext-remix])、クッキーのサーバーインフラは`shared/api`に保存する必要があります。[「認証」チュートリアルセクション][tutorial-authentication]には、Remixでの実装例があります。 + +ただし、時にはトークンをクッキーに保存することができない場合もあります。この場合、トークンを自分で保存しなければなりません。その際、トークンの有効期限が切れたときに更新するロジックを書く手間がかかるかもしれません。FSDの枠組み内には、トークンを保存できるいくつかの場所と、そのトークンをアプリケーションの他の部分で利用できるようにするいくつかの方法があります。 + +### Shared層に保存する + +このアプローチは、APIクライアントが`shared/api`に定義されている場合にうまく機能します。なぜなら、APIクライアントがトークンに自由にアクセスできるからです。クライアントが状態を持つようにするには、リアクティブストアを使用するか、単にモジュールレベルの変数を使用することができます。その後、`login()`/`logout()`関数内でこの状態を更新できます。 + +トークンの自動更新は、APIクライアント内のミドルウェアとして実装できます。これは、リクエストを行うたびに実行されます。例えば、次のようにすることができます。 + +- 認証し、アクセストークンとリフレッシュトークンを保存する +- 認証を必要とするリクエストを行う +- リクエストがアクセストークンの有効期限切れを示すステータスコードで失敗した場合、ストレージにリフレッシュトークンがあれば、更新リクエストを行い、新しいアクセストークンとリフレッシュトークンを保存し、元のリクエストを再試行する + +このアプローチの欠点の1つは、トークンの保存と更新ロジックが専用の場所を持たないことです。これは、特定のアプリケーションやチームには適しているかもしれませんが、トークン管理のロジックがより複雑な場合、リクエスト送信とトークン管理の責任を分けたいと思うかもしれません。この場合、リクエストとAPIクライアントを`shared/api`に置き、トークンストレージと更新ロジックを`shared/auth`に配置します。 + +このアプローチのもう1つの欠点は、サーバーがトークンとともに現在のユーザーに関する情報を返す場合、その情報を保存する場所がなく、特別なエンドポイント(例えば`/me`や`/users/current`)から再度取得する必要があることです。 + +### Entities層に保存する + +FSDプロジェクトには、ユーザーエンティティや現在のユーザーエンティティが存在することがよくあります。これらは同じエンティティである場合もあります。 + +:::note + +**現在のユーザー**は時には「viewer」や「me」とも呼ばれます。これは、権限とプライベート情報を持つ認証されたユーザーと、公開情報を持つ他のすべてのユーザーを区別するために行われます。 + +::: + +ユーザーエンティティにトークンを保存するには、`model`セグメントにリアクティブストアを作成します。このストアには、トークンとユーザー情報のオブジェクトの両方を含めることができます。 + +APIクライアントは通常、`shared/api`に配置されるか、エンティティ間で分散されるため、このアプローチの主な問題は、他のリクエストがトークンにアクセスできるようにしつつ、[レイヤーのインポートルール][import-rule-on-layers]を破らないことです。 + +> スライス内のモジュールは、下層にあるスライスのみをインポートできる。 + +この問題にはいくつかの解決策があります。 + +1. **リクエストを行うたびにトークンを手動で渡す** + これは最も簡単な解決策ですが、すぐに不便になり、厳密な型付けがない場合は忘れやすくなります。この解決策は、Shared層のAPIクライアントのミドルウェアパターンとも互換性がありません。 + +2. **コンテキストや`localStorage`のようなグローバルストレージを介してアプリ全体にトークンへのアクセスを提供する** + トークンを取得するためのキーは`shared/api`に保存され、APIクライアントがそれを使用できるようにします。トークンのリアクティブストアはユーザーエンティティからエクスポートされ、必要に応じてコンテキストプロバイダーがApp層で設定されます。これにより、APIクライアントの設計に対する自由度が増しますが、このアプローチは暗黙の依存関係を生み出してしまいます。 + +3. **トークンが変更されるたびにAPIクライアントにトークンを挿入する** + リアクティブなストアであれば、変更を監視し、ユーザーエンティティのストアが変更されるたびにAPIクライアントのトークンを更新できます。この解決策は、前の解決策と同様に暗黙の依存関係を生み出してしまいますが、より命令的(「プッシュ」)であり、前のものはより宣言的(「プル」)です。 + +ユーザーエンティティのモデルに保存されたトークンの可用性の問題を解決したら、トークン管理に関連する追加のビジネスロジックを記述できます。例えば、`model`セグメントには、トークンを一定期間後に無効にするロジックや、期限切れのトークンを更新するロジックを含めることができます。これらのタスクを実行するために、ユーザーエンティティの`api`セグメント、または`shared/api`を使用します。 + +### Pages層/Widgets層に保存する(非推奨) + +アクセストークンのようなアプリ全体に関連する状態をページやウィジェットに保存することは推奨されません。ログインページの`model`セグメントにトークンストレージを配置しないでください。代わりに、最初の2つの解決策(Shared層配置かEntities層配置)のいずれかを選択してください。 + +## ログアウトとトークンの無効化 + +通常、アプリケーションではログアウト専用のページを作成しませんが、ログアウト機能は非常に重要です。この機能には、バックエンドへの認証リクエストとトークンストレージの更新が含まれます。 + +すべてのリクエストを`shared/api`に保存している場合は、ログイン関数の近くにログアウトリクエストの関数を配置してください。そうでない場合は、ログアウトを呼び出すボタンの近くに配置してください。例えば、すべてのページに存在し、ログアウトリンクを含むヘッダーウィジェットがある場合、そのリクエストをこのウィジェットの`api`セグメントに配置します。 + +トークンストレージの更新も、ログアウトボタンの場所からトリガーされる必要があります。リクエストとストレージの更新をこのウィジェットの`model`セグメントで統合できます。 + +### 自動ログアウト + +ログアウトリクエストやトークン更新リクエストの失敗を考慮することを忘れないでください。いずれの場合も、トークンストレージをリセットする必要があります。トークンをEntities層に保存している場合、このコードは`model`セグメントに配置できます。トークンをShared層に保存している場合、このロジックを`shared/api`に配置すると、セグメントが膨らみ、その目的が曖昧になってしまいます。`api`セグメントに無関係な2つのものが含まれていることに気づいた場合、トークン管理ロジックを別のセグメント、例えば`shared/auth`に分離することを検討してみてください。 + +[tutorial-authentication]: /docs/get-started/tutorial#authentication +[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers +[ext-remix]: https://remix.run +[ext-zod]: https://zod.dev \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/autocompleted.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/autocompleted.mdx new file mode 100644 index 0000000000..98102f4f7f --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/autocompleted.mdx @@ -0,0 +1,13 @@ +--- +sidebar_position: 5 +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# 自動補完 + + + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/browser-api.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/browser-api.mdx new file mode 100644 index 0000000000..e5a3c130a8 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/browser-api.mdx @@ -0,0 +1,10 @@ +--- +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# ブラウザAPI + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/cms.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/cms.mdx new file mode 100644 index 0000000000..e53b6cc5ff --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/cms.mdx @@ -0,0 +1,10 @@ +--- +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# CMS + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/feedback.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/feedback.mdx new file mode 100644 index 0000000000..2f620c67cb --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/feedback.mdx @@ -0,0 +1,10 @@ +--- +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# フィードバック + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/i18n.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/i18n.mdx new file mode 100644 index 0000000000..e736c4fe37 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/i18n.mdx @@ -0,0 +1,11 @@ +--- +sidebar_position: 6 +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# i18n + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/index.mdx new file mode 100644 index 0000000000..9452069ba4 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/index.mdx @@ -0,0 +1,36 @@ +--- +hide_table_of_contents: true +--- + +# 例 + +

+小さな実践的な例を通じて、FSDの適用方法を示します。 +

+ +## 主要 {#main} + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { UserSwitchOutlined, LayoutOutlined, FontSizeOutlined } from "@ant-design/icons"; + + + + \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/metric.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/metric.mdx new file mode 100644 index 0000000000..fe2dcfcac3 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/metric.mdx @@ -0,0 +1,10 @@ +--- +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# メトリクス + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/monorepo.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/monorepo.mdx new file mode 100644 index 0000000000..42cb3c59a9 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/monorepo.mdx @@ -0,0 +1,11 @@ +--- +sidebar_position: 9 +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# モノレポ + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md new file mode 100644 index 0000000000..baa8ef1a9f --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md @@ -0,0 +1,104 @@ +--- +sidebar_position: 3 +--- + +# ページレイアウト + +このガイドでは、複数のページが同じ構造を持ち、主な内容だけが異なる場合のページレイアウトの抽象化について説明します。 + +:::info + +あなたの質問がこのガイドにない場合は、この記事にフィードバックを残して質問を投稿してください(右側の青いボタン)、私たちはこのガイドを拡張する可能性を検討します! + +::: + +## シンプルなレイアウト + +最もシンプルなレイアウトは、このページで直接見ることができます。これは、サイトのナビゲーションを含むヘッダー、2つのサイドバー、外部リンクを含むフッターを持っています。ここには複雑なビジネスロジックはなく、唯一の動的部分はサイドバーとヘッダーの右側にあるトグルスイッチです。このレイアウトは、`shared/ui`または`app/layouts`に全体を配置でき、サイドバーのコンテンツはプロパティを通じて埋め込むことができます。 + +```tsx title="shared/ui/layout/Layout.tsx" +import { Link, Outlet } from "react-router-dom"; +import { useThemeSwitcher } from "./useThemeSwitcher"; + +export function Layout({ siblingPages, headings }) { + const [theme, toggleTheme] = useThemeSwitcher(); + + return ( +
+
+ + +
+
+ + {/* ここにページの主な内容が表示されます */} + +
+
+
    +
  • GitHub
  • +
  • X
  • +
+
+
+ ); +} +``` + +```ts title="shared/ui/layout/useThemeSwitcher.ts" +export function useThemeSwitcher() { + const [theme, setTheme] = useState("light"); + + function toggleTheme() { + setTheme(theme === "light" ? "dark" : "light"); + } + + useEffect(() => { + document.body.classList.remove("light", "dark"); + document.body.classList.add(theme); + }, [theme]); + + return [theme, toggleTheme] as const; +} +``` + + +サイドバーのコードは読者に課題として残されています! + +## レイアウトでのウィジェットの使用 + +時には、特定のビジネスロジックをレイアウトに組み込む必要があります。特に、[React Router][ext-react-router]のような深くネストされたルートを使用している場合、Shared層やWidgets層にレイアウトを保存することはできません。これは[レイヤーのインポートルール][import-rule-on-layers]に違反しています。 + +> スライス内のモジュールは、下層にあるスライスのみをインポートできる。 + +解決策を議論する前に、これが実際に問題かどうかを確認する必要があります。このレイアウトは本当に必要なのか?もしそうなら、ウィジェットとして実装することが最適なのかも再考する必要があるでしょう。もしビジネスロジックのブロックが2〜3ページで使用され、レイアウトがそのウィジェットの小さなラッパーに過ぎない場合、次の2つのオプションを検討してください。 + +1. **レイアウトをApp層のルーターで直接作成する** + これは、ネストをサポートするルーターに最適です。特定のルートをグループ化し、必要なレイアウトをそれらにのみ適用できます。 + +2. **単にコピーする** + コードを抽象化する欲求はしばしば過大評価されます。特にレイアウトに関しては、変更がほとんどないためです。ある時点で、これらのページの1つが変更を必要とする場合、他のページに影響を与えずに変更を加えることができます。他のページを更新することを忘れるかもしれないと心配している場合は、ページ間の関係を説明するコメントを残すことができます。 + +上記のいずれのオプションも適用できない場合、ウィジェットをレイアウトに組み込むための2つの解決策があります。 + +1. **レンダープロップまたはスロットを使用する** + ほとんどのフレームワークは、UIの一部を外部から渡すことを許可しています。Reactではこれを[レンダープロップ][ext-render-props]と呼び、Vueでは[スロット][ext-vue-slots]と呼びます。 + +2. **レイアウトをApp層に移動する** + レイアウトをApp層に保存し、必要なウィジェットを組み合わせることもできます。 + +## 追加資料 + +- ReactとRemixを使用した認証付きレイアウトの作成例は[チュートリアル][tutorial]で見つけることができます(React Routerに類似する)。 + +[tutorial]: /docs/get-started/tutorial +[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers +[ext-react-router]: https://reactrouter.com/ +[ext-render-props]: https://www.patterns.dev/react/render-props-pattern/ +[ext-vue-slots]: https://jp.vuejs.org/guide/components/slots \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/platforms.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/platforms.mdx new file mode 100644 index 0000000000..79f3389bb6 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/platforms.mdx @@ -0,0 +1,10 @@ +--- +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# デスクトップ/タッチプラットフォーム + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/ssr.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/ssr.mdx new file mode 100644 index 0000000000..51fdbba8de --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/ssr.mdx @@ -0,0 +1,10 @@ +--- +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# SSR + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/theme.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/theme.mdx new file mode 100644 index 0000000000..9de66e03b0 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/theme.mdx @@ -0,0 +1,11 @@ +--- +sidebar_position: 4 +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# テーマ化 + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md new file mode 100644 index 0000000000..d0111f68b1 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md @@ -0,0 +1,436 @@ +--- +sidebar_position: 2 +--- + +# 型 + +このガイドでは、TypeScriptのような型付き言語のデータの型と、それがFSDにどのように適合するかについて説明します。 + +:::info + +あなたの質問がこのガイドにない場合は、この記事にフィードバックを残して質問を投稿してください(右側の青いボタン)、私たちはこのガイドを拡張する可能性を検討します! + +::: + +## ユーティリティ型 + +ユーティリティ型は、特に意味を持たず、通常は他の型と一緒に使用される型です。例えば + +
+ + +```ts +type ArrayValues = T[number]; +``` + + +
+ 出典: https://github.com/sindresorhus/type-fest/blob/main/source/array-values.d.ts +
+ +
+ +ユーティリティ型をプロジェクトに追加するには、[`type-fest`][ext-type-fest]のようなライブラリをインストールするか、`shared/lib`に独自のライブラリを作成します。必ず、新しい型をこのライブラリに追加できるか、できないかを明確に示してください。例えば、`shared/lib/utility-types`と名付け、その中にユーティリティ型があなたのチームの理解において何であるかを説明するREADMEファイルを追加してください。 + +ユーティリティ型の再利用の可能性を過大評価しないでください。再利用可能であるからといって、必ずしも再利用されるわけではなく、したがってすべてのユーティリティ型がShared層に存在する必要はありません。一部のユーティリティ型は、使用される場所の近くに置くべきです。 + +- 📂 pages + - 📂 home + - 📂 api + - 📄 ArrayValues.ts (ユーティリティ型) + - 📄 getMemoryUsageMetrics.ts (このユーティリティを使用するコード) + +:::warning + +`shared/types`フォルダーを作成したり、スライスに`types`セグメントを追加する誘惑に負けないでください。「型」というカテゴリは「コンポーネント」や「フック」と同様に、内容を説明するものであり、目的を示すものではありません。セグメントはコードの目的を説明するべきであり、その本質を説明するべきではありません。 + +::: + +## ビジネスエンティティと相互参照 + +アプリケーションで最も重要な型の一つは、ビジネスエンティティの型、つまりアプリケーションが扱う実際のオブジェクトです。例えば、オンライン音楽サービスのアプリケーションでは、ビジネスエンティティとして「曲」(song)や「アルバム」(album)などがあります。 + +ビジネスエンティティは、しばしばバックエンドから提供されるため、最初のステップはバックエンドのレスポンスを型付けすることです。各エンドポイントに対してリクエスト関数を持ち、その関数の呼び出し結果を型付けするのが便利です。型の安全性を高めるために、Zodのようなスキーマ検証ライブラリを通じて結果を通過させることができます。 + +例えば、すべてのリクエストをShared層に保存している場合、次のようにできます。 + +```ts title="shared/api/songs.ts" +import type { Artist } from "./artists"; + +interface Song { + id: number; + title: string; + artists: Array; +} + +export function listSongs() { + return fetch('/api/songs').then((res) => res.json() as Promise>); +} +``` + + +`Song`型が他の`Artist`エンティティを参照していることに気付くかもしれません。これはリクエストをShared層に保存する利点です。実際の型が相互に参照されることが多いです。この関数を`entities/song/api`に置いた場合、`entities/artist`から`Artist`を単純にインポートすることはできません。なぜなら、FSDはスライス間のクロスインポートを[レイヤーのインポートルール][import-rule-on-layers]によって制限しているからです。 + +> スライス内のモジュールは、下層にあるスライスのみをインポートできる。 + +この問題を解決する方法は2つあります。 + +1. **型をパラメーター化する** + 型が他のエンティティと接続するためのスロットとして型引数を受け取るようにすることができます。さらに、これらのスロットに制約を課すこともできます。例えば + + ```ts title="entities/song/model/song.ts" + interface Song { + id: number; + title: string; + artists: Array; + } + ``` + + これはいくつかの型に対してはうまく機能しますが、機能しないケースもあります。`Cart = { items: Array }`のような単純な型は、任意のプロダクト型で簡単に機能させることができます。しかし、`Country`と`City`のようなより関連性の高い型は、分離するのが難しいかもしれません。 + +2. **クロスインポートする(正しく)** + FSD内でエンティティ間のクロスインポートを行うには、各スライス専用の特別の公開APIを使用することができます。例えば、`song`(曲)、`artist`(アーティスト)、`playlist`(プレイリスト)のエンティティがあり、後者の2つが`song`を参照する必要がある場合、`@x`ノーテーションを通じて`song`エンティティ内に2つの特別な公開APIを作成できます。 + + - 📂 entities + - 📂 song + - 📂 @x + - 📄 artist.ts (公開API、`artist`エンティティをインポートする) + - 📄 playlist.ts (公開API、`playlist`エンティティをインポートする) + - 📄 index.ts (通常の公開API) + + `📄 entities/song/@x/artist.ts`ファイルの内容は、`📄 entities/song/index.ts`と似ています。 + + ```ts title="entities/song/@x/artist.ts" + export type { Song } from "../model/song.ts"; + ``` + + その後、`📄 entities/artist/model/artist.ts`は次のように`Song`をインポートできます。 + + ```ts title="entities/artist/model/artist.ts" + import type { Song } from "entities/song/@x/artist"; + + export interface Artist { + name: string; + songs: Array; + } + ``` + + エンティティ間の明示的な関係を持つことで、依存関係を正確に制御し、ドメインの分離を十分に保つことができます。 + +## データ転送オブジェクト(DTO)とマッパー {#data-transfer-objects-and-mappers} + +データ転送オブジェクト、またはDTO(Data Transfer Object)は、バックエンドから送信されるデータの形式を説明する用語です。時にはDTOをそのまま使用できますが、時にはその形式がフロントエンドにとって不便な場合があります。ここでマッパーが役立ちます。マッパーは、DTOをより使いやすい形式に変換する関数です。 + +### DTOをどこに置くか + +バックエンドの型が別のパッケージにある場合(例えば、フロントエンドとバックエンド間でコードを共有している場合)、そこからDTOをインポートするだけで済みます。バックエンドとフロントエンド間でコードを共有していない場合、DTOをフロントエンドコードのどこかに保存する必要があります。この場合については以下で説明します。 + +リクエスト関数を`shared/api`に保存している場合、その関数で使用するDTOも、ちょうどその関数の近くに配置するべきです。 + + +```ts title="shared/api/songs.ts" +import type { ArtistDTO } from "./artists"; + +interface SongDTO { + id: number; + title: string; + artist_ids: Array; +} + +export function listSongs() { + return fetch('/api/songs').then((res) => res.json() as Promise>); +} +``` + +前のセクションで述べたように、リクエストとDTOをShared層に保存する利点は、他のDTOを参照できることです。 + +### マッパーをどこに置くか + +マッパーは、DTOを変換するための関数であり、したがってDTOの定義の近くに置くべきです。実際には、リクエストとDTOが`shared/api`に定義されている場合、マッパーもそこに置くべきです。 + +```ts title="shared/api/songs.ts" +import type { ArtistDTO } from "./artists"; + +interface SongDTO { + id: number; + title: string; + disc_no: number; + artist_ids: Array; +} + +interface Song { + id: string; + title: string; + /** 曲の完全なタイトル、ディスク番号を含む。 */ + fullTitle: string; + artistIds: Array; +} + +function adaptSongDTO(dto: SongDTO): Song { + return { + id: String(dto.id), + title: dto.title, + fullTitle: `${dto.disc_no} / ${dto.title}`, + artistIds: dto.artist_ids.map(String), + }; +} + +export function listSongs() { + return fetch('/api/songs').then(async (res) => (await res.json()).map(adaptSongDTO)); +} +``` + +リクエストとストレージがエンティティスライスに定義されている場合、このすべてのコードはそこに置くべきであり、エンティティ間のクロスインポートの制限を考慮する必要があります。 + +```ts title="entities/song/api/dto.ts" +import type { ArtistDTO } from "entities/artist/@x/song"; + +export interface SongDTO { + id: number; + title: string; + disc_no: number; + artist_ids: Array; +} +``` + +```ts title="entities/song/api/mapper.ts" +import type { SongDTO } from "./dto"; + +export interface Song { + id: string; + title: string; + /** 曲の完全なタイトル、ディスク番号を含む。 */ + fullTitle: string; + artistIds: Array; +} + +export function adaptSongDTO(dto: SongDTO): Song { + return { + id: String(dto.id), + title: dto.title, + fullTitle: `${dto.disc_no} / ${dto.title}`, + artistIds: dto.artist_ids.map(String), + }; +} +``` + +```ts title="entities/song/api/listSongs.ts" +import { adaptSongDTO } from "./mapper"; + +export function listSongs() { + return fetch('/api/songs').then(async (res) => (await res.json()).map(adaptSongDTO)); +} +``` + +```ts title="entities/song/model/songs.ts" +import { createSlice, createEntityAdapter } from "@reduxjs/toolkit"; + +import { listSongs } from "../api/listSongs"; + +export const fetchSongs = createAsyncThunk('songs/fetchSongs', listSongs); + +const songAdapter = createEntityAdapter(); +const songsSlice = createSlice({ + name: "songs", + initialState: songAdapter.getInitialState(), + reducers: {}, + extraReducers: (builder) => { + builder.addCase(fetchSongs.fulfilled, (state, action) => { + songAdapter.upsertMany(state, action.payload); + }) + }, +}); +``` + +### ネストされたDTOをどう扱うか + +最も問題となるのは、バックエンドからのレスポンスが複数のエンティティを含む場合です。例えば、曲がアーティストのIDだけでなく、アーティストのデータオブジェクト全体を含む場合です。この場合、エンティティは互いに知らないわけにはいきません(データを捨てたり、バックエンドチームと真剣に話し合いたくない場合を除いて)。スライス間の暗黙的な関係の解決策を考えるのではなく、`@x`ノーテーションを通じて明示的なクロスインポートを選ぶべきです。Redux Toolkitを使用してこれを実装する方法は次のとおりです。 + +```ts title="entities/song/model/songs.ts" +import { + createSlice, + createEntityAdapter, + createAsyncThunk, + createSelector, +} from '@reduxjs/toolkit' +import { normalize, schema } from 'normalizr' + +import { getSong } from "../api/getSong"; + +// normalizrでエンティティのスキーマを宣言 +export const artistEntity = new schema.Entity('artists') +export const songEntity = new schema.Entity('songs', { + artists: [artistEntity], +}) + +const songAdapter = createEntityAdapter() + +export const fetchSong = createAsyncThunk( + 'songs/fetchSong', + async (id: string) => { + const data = await getSong(id) + // データを正規化して、リデューサーが予測可能なオブジェクトをロードできるようにします。例えば + // `action.payload = { songs: {}, artists: {} }` + const normalized = normalize(data, songEntity) + return normalized.entities + } +) + +export const slice = createSlice({ + name: 'songs', + initialState: songAdapter.getInitialState(), + reducers: {}, + extraReducers: (builder) => { + builder.addCase(fetchSong.fulfilled, (state, action) => { + songAdapter.upsertMany(state, action.payload.songs) + }) + }, +}) + +const reducer = slice.reducer +export default reducer +``` + +```ts title="entities/song/@x/artist.ts" +export { fetchSong } from "../model/songs"; +``` + +```ts title="entities/artist/model/artists.ts" +import { createSlice, createEntityAdapter } from '@reduxjs/toolkit' + +import { fetchSong } from 'entities/song/@x/artist' + +const artistAdapter = createEntityAdapter() + +export const slice = createSlice({ + name: 'users', + initialState: artistAdapter.getInitialState(), + reducers: {}, + extraReducers: (builder) => { + builder.addCase(fetchSong.fulfilled, (state, action) => { + // ここでバックエンドからの同じレスポンスを処理し、ユーザーを追加します + usersAdapter.upsertMany(state, action.payload.users) + }) + }, +}) + +const reducer = slice.reducer +export default reducer +``` + +これはスライスの分離の利点を少し制限しますが、私たちが制御できないこれらの2つのエンティティ間の関係を明確に示します。これらのエンティティがリファクタリングされる場合、同時にリファクタリングする必要があります。 + +## グローバルの型とRedux + +グローバルの型とは、アプリケーション全体で使用される型のことです。グローバルの型には、必要な情報に応じて2種類があります。 +1. アプリケーションに特有の情報を持たないユニバーサル型 +2. アプリケーション全体について知る必要がある型 + +最初のケースは簡単に解決できます。型をShared層の適切なセグメントに置くだけです。例えば、分析用のグローバル変数のインターフェースがある場合、それを`shared/analytics`に置くことができます。 + +:::warning + +`shared/types`フォルダーを作成することは避けてください。これは「型である」という特性に基づいて無関係なものをグループ化するだけであり、この特性はプロジェクト内でコードを検索する際には通常無意味です。 + +::: + +2番目のケースは、RTKなしでReduxを使用しているプロジェクトでよく見られます。最終的なストアの型は、すべてのリデューサーを結合した後にのみ利用可能ですが、このストアの型はアプリケーションで使用されるセレクターに必要です。例えば、以下はReduxでのストアの典型的な定義です。 + +```ts title="app/store/index.ts" +import { combineReducers, rootReducer } from "redux"; + +import { songReducer } from "entities/song"; +import { artistReducer } from "entities/artist"; + +const rootReducer = combineReducers(songReducer, artistReducer); + +const store = createStore(rootReducer); + +type RootState = ReturnType; +type AppDispatch = typeof store.dispatch; +``` + +`shared/store`に型付けされた`useAppDispatch`と`useAppSelector`のフックを持つことは良いアイデアですが、[レイヤーのインポートルール][import-rule-on-layers]のために、App層から`RootState`と`AppDispatch`をインポートすることはできません。 + +> スライス内のモジュールは、下層にあるスライスのみをインポートできる。 + +この場合の推奨解決策は、Shared層とApp層の間に暗黙の依存関係を作成することです。これらの2つの型、`RootState`と`AppDispatch`は、変更される可能性が低く、Reduxの開発者には馴染みのあるものであるため、暗黙の関係は問題にならないでしょう。 + +TypeScriptでは、これらの型をグローバルとして宣言することで実現できます。例えば + +```ts title="app/store/index.ts" +/* 上記のコードブロックと同じ内容… */ + +declare type RootState = ReturnType; +declare type AppDispatch = typeof store.dispatch; +``` + +```ts title="shared/store/index.ts" +import { useDispatch, useSelector, type TypedUseSelectorHook } from "react-redux"; + +export const useAppDispatch = useDispatch.withTypes() +export const useAppSelector: TypedUseSelectorHook = useSelector; +``` + +## 型のバリデーションスキーマとZod + +データが特定の形式や制約に従っていることを確認したい場合、バリデーションスキーマを作成できます。TypeScriptでこの目的に人気のあるライブラリは[Zod][ext-zod]です。バリデーションスキーマは、可能な限りそれを使用するコードの近くに配置する必要があります。 + +バリデーションスキーマは、データ転送オブジェクト(DTO)と似ており([DTOとマッパー](#data-transfer-objects-and-mappers)のセクションで説明)、DTOを受け取り、それを解析し、解析に失敗した場合はエラーを返します。 + +バリデーションの最も一般的なケースの一つは、バックエンドからのデータです。通常、データがスキーマに従わない場合、リクエストを失敗としてマークしたいので、リクエスト関数と同じ場所にスキーマを置くのが良いでしょう。通常、これは`api`セグメントになります。 + +ユーザー入力を介してデータが送信される場合、例えばフォームを通じて、バリデーションはデータ入力時に行わなければなりません。この場合、スキーマを`ui`セグメントに配置し、フォームコンポーネントの近くに置くか、`ui`セグメントが過負荷である場合は`model`セグメントに配置できます。 + +## コンポーネントのプロップスとコンテキストの型付け + +一般的に、プロップスやコンテキストのインターフェースは、それを使用するコンポーネントやコンテキストと同じファイルに保存するのが最良です。VueやSvelteのように、単一ファイルコンポーネントを持つフレームワークの場合、インターフェースを同じファイルに定義できない場合や、複数のコンポーネント間でこのインターフェースを再利用したい場合は、通常は`ui`セグメント内の同じフォルダーに別のファイルを作成します。 + +以下はJSX(ReactまたはSolid)の例です。 + +```ts title="pages/home/ui/RecentActions.tsx" +interface RecentActionsProps { + actions: Array<{ id: string; text: string }>; +} + +export function RecentActions({ actions }: RecentActionsProps) { + /* … */ +} +``` + +以下は、Vueのために別のファイルにインターフェースを保存する例です。 + +```ts title="pages/home/ui/RecentActionsProps.ts" +export interface RecentActionsProps { + actions: Array<{ id: string; text: string }>; +} +``` + +```html title="pages/home/ui/RecentActions.vue" + +``` + +## 環境宣言ファイル(`*.d.ts`) + +一部のパッケージ、例えば[Vite][ext-vite]や[ts-reset][ext-ts-reset]は、アプリケーションで動作するために環境宣言ファイルを必要とします。通常、これらは小さくて簡単なので、特にアーキテクチャを必要とせず、単に`src/`に置くことができます。`src`をより整理されたものにするために、App層の`app/ambient/`に保存することもできます。 + +他のパッケージは単に型を持たず、その型を未定義として宣言する必要があるか、あるいは自分で型を作成する必要があるかもしれません。これらの型の良い場所は`shared/lib`で、`shared/lib/untyped-packages`のようなフォルダーです。そこに`%LIBRARY_NAME%.d.ts`というファイルを作成し、必要な型を宣言します。 + +```ts title="shared/lib/untyped-packages/use-react-screenshot.d.ts" +// このライブラリには型がなく、自分で型を書くのは億劫です。 +declare module "use-react-screenshot"; +``` + +## 型の自動生成 + +外部ソースから型を生成することは、しばしば便利です。例えば、OpenAPIスキーマからバックエンドの型を生成することができます。この場合、これらの型のためにコード内に特別な場所を作成します。例えば、`shared/api/openapi`のようにします。これらのファイルが何であるか、どのように再生成されるかを説明するREADMEをこのフォルダーに含めておくと理想的です。 + +[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers +[ext-type-fest]: https://github.com/sindresorhus/type-fest +[ext-zod]: https://zod.dev +[ext-vite]: https://vitejs.dev +[ext-ts-reset]: https://www.totaltypescript.com/ts-reset \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/white-labels.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/white-labels.mdx new file mode 100644 index 0000000000..b536ecddbc --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/white-labels.mdx @@ -0,0 +1,11 @@ +--- +sidebar_position: 8 +sidebar_class_name: sidebar-item--wip +unlisted: true +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# ホワイトラベル + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/index.mdx new file mode 100644 index 0000000000..f6b7376683 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/index.mdx @@ -0,0 +1,46 @@ +--- +hide_table_of_contents: true +pagination_prev: get-started/index +--- + +# 🎯 ガイド + +実践指向 + +

+Feature-Sliced Designの適用に関する実践的なガイドと例です。このセクションでは、移行ガイドや悪習のハンドブックも説明されています。具体的な何かを実現しようとしているときや、FSDを「実戦」で見たいときに最も役立ちます。 +

+ +## 主な内容 {#main} + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { ToolOutlined, ImportOutlined, BugOutlined, FunctionOutlined } from "@ant-design/icons"; + + + + + + \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/_category_.yaml b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/_category_.yaml new file mode 100644 index 0000000000..8d2bd9c676 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/_category_.yaml @@ -0,0 +1,2 @@ +label: コードの臭いと問題 +position: 4 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/cross-imports.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/cross-imports.mdx new file mode 100644 index 0000000000..92183efece --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/cross-imports.mdx @@ -0,0 +1,13 @@ +--- +sidebar_position: 4 +sidebar_class_name: sidebar-item--wip +pagination_next: reference/index +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# クロスインポート + + + +> クロスインポートは、レイヤーや抽象化が本来の責任以上に多くの責任を持ち始めると発生する。そのため、FSDは新しいレイヤーを設けて、これらのクロスインポートを分離することを可能にしている。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/desegmented.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/desegmented.mdx new file mode 100644 index 0000000000..28f3bddc42 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/desegmented.mdx @@ -0,0 +1,96 @@ +--- +sidebar_position: 2 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# デセグメンテーション + + + +## 状況 {#situation} + +プロジェクトでは、特定のドメインに関連するモジュールが過度にデセグメント化され、プロジェクト全体に散らばっていることがよくあります。 + +```sh +├── components/ +| ├── DeliveryCard +| ├── DeliveryChoice +| ├── RegionSelect +| ├── UserAvatar +├── actions/ +| ├── delivery.js +| ├── region.js +| ├── user.js +├── epics/ +| ├── delivery.js +| ├── region.js +| ├── user.js +├── constants/ +| ├── delivery.js +| ├── region.js +| ├── user.js +├── helpers/ +| ├── delivery.js +| ├── region.js +| ├── user.js +├── entities/ +| ├── delivery/ +| | ├── getters.js +| | ├── selectors.js +| ├── region/ +| ├── user/ +``` + + +## 問題 {#problem} + +問題は、**高い凝集性**の原則の違反と、**変更の軸**の過度な拡張として現れます。 + +## 無視する場合 {#if-you-ignore-it} + +- 例えば、配達に関するロジックに触れる必要がある場合、このロジックが複数の箇所に分散していることを考慮しなければならず、コード内で複数の箇所に触れる必要がある。これにより、**変更の軸**が過度に引き伸ばされる +- ユーザーに関するロジックを調べる必要がある場合、**actions、epics、constants、entities、components**の詳細を調べるためにプロジェクト全体を巡回しなければならない +- 暗黙関係と拡大するドメインの制御不能 + - このアプローチでは、視野が狭くなり、「定数のための定数」を作成し、プロジェクトの該当ディレクトリをごちゃごちゃさせてしまうことに気づかないことがよくある + +## 解決策 {#solution} + +特定のドメイン/ユースケースに関連するすべてのモジュールを近くに配置することです。 + +これは特定のモジュールを調べる際に、そのすべての構成要素がプロジェクト全体に散らばらず、近くに配置されるためです。 + +> これにより、コードベースとモジュール間の関係の発見しやすさと明確さが向上します。 + +```diff +- ├── components/ +- | ├── DeliveryCard +- | ├── DeliveryChoice +- | ├── RegionSelect +- | ├── UserAvatar +- ├── actions/ +- | ├── delivery.js +- | ├── region.js +- | ├── user.js +- ├── epics/{...} +- ├── constants/{...} +- ├── helpers/{...} + ├── entities/ + | ├── delivery/ ++ | | ├── ui/ # ~ components/ ++ | | | ├── card.js ++ | | | ├── choice.js ++ | | ├── model/ ++ | | | ├── actions.js ++ | | | ├── constants.js ++ | | | ├── epics.js ++ | | | ├── getters.js ++ | | | ├── selectors.js ++ | | ├── lib/ # ~ helpers + | ├── region/ + | ├── user/ +``` + +## 参照 {#see-also} +* [(記事) Cohesion and Coupling: the difference](https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/) diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/routes.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/routes.mdx new file mode 100644 index 0000000000..10dc329e10 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/issues/routes.mdx @@ -0,0 +1,42 @@ +--- +sidebar_position: 3 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# ルーティング + + + +## 状況 {#situation} + +ページへのURLが、pages層より下の層にハードコーディングされています。 + +```tsx title="entities/post/card" + + + + ... + +``` + + +## 問題 {#problem} + +URLがページ層に集中しておらず、責任範囲において適切な場所に配置されていません。 + +## 無視する場合 {#if-you-ignore-it} + +URLを変更する際に、URL(およびURL/リダイレクトのロジック)がpages層以外のすべての層に存在する可能性があることを考慮しなければなりません。 + +また、これは単純な商品カードでさえ、ページからの一部の責任を引き受けることを意味し、プロジェクト全体にロジックが分散してしまいます。 + +## 解決策 {#solution} + +URLやリダイレクトの処理をページ層およびそれ以上の層で定義することです。 + +URLを下層の層には、コンポジション/プロパティ/ファクトリーを通じて渡すことができます。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/_category_.yaml b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/_category_.yaml new file mode 100644 index 0000000000..32b7491cea --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/_category_.yaml @@ -0,0 +1,2 @@ +label: 移行 +position: 2 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md new file mode 100644 index 0000000000..94b6a2e3bb --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md @@ -0,0 +1,306 @@ +--- +sidebar_position: 3 +sidebar_label: カスタムアーキテクチャからの移行 +--- + +# カスタムアーキテクチャからの移行 + +このガイドは、カスタムのアーキテクチャからFeature-Sliced Designへの移行に役立つアプローチを説明します。 + +以下は、典型的なカスタムアーキテクチャのフォルダ構造です。このガイドでは、これを例として使用します。フォルダの内容が見えるように、フォルダの横にある青い矢印をクリックすることができます。 + +
+ 📁 src +
    +
  • +
    + 📁 actions +
      +
    • 📁 product
    • +
    • 📁 order
    • +
    +
    +
  • +
  • 📁 api
  • +
  • 📁 components
  • +
  • 📁 containers
  • +
  • 📁 constants
  • +
  • 📁 i18n
  • +
  • 📁 modules
  • +
  • 📁 helpers
  • +
  • +
    + 📁 routes +
      +
    • 📁 products.jsx
    • +
    • 📄 products.[id].jsx
    • +
    +
    +
  • +
  • 📁 utils
  • +
  • 📁 reducers
  • +
  • 📁 selectors
  • +
  • 📁 styles
  • +
  • 📄 App.jsx
  • +
  • 📄 index.js
  • +
+
+ +## 開始前に {#before-you-start} + +Feature-Sliced Designへの移行を検討する際に、チームに最も重要な質問は「本当に必要か?」です。私たちはFeature-Sliced Designが好きですが、いくつかのプロジェクトはそれなしでうまくいけることを認めています。 + +移行を検討すべき理由はいくつかあります。 + +1. 新しいチームメンバーが生産的なレベルに達するのが難しいと不満を言う。 +2. コードの一部を変更すると、**しばしば**他の無関係な部分が壊れる。 +3. 巨大なコードベースのため、新しい機能を追加するのが難しい。 + +**同僚の意に反してFSDに移行することは避けてください**。たとえあなたがチームリーダーであっても、まずは同僚を説得し、移行の利点がコストを上回ることを理解させる必要があります。 + +また、アーキテクチャの変更は、瞬時には経営陣には見えないことを覚えておいてください。始める前に、経営陣が移行を支持していることを確認し、この移行がプロジェクトにどのように役立つかを説明してください。 + +:::tip + +プロジェクトマネージャーをFSDの有用性に納得させるためのアイデアをいくつか紹介します。 + +1. FSDへの移行は段階的に行えるため、新機能の開発を止めることはありません。 +2. 良いアーキテクチャは、新しい開発者が生産性を達成するのにかかる時間を大幅に短縮できます。 +3. FSDは文書化されたアーキテクチャであるため、チームは独自の文書を維持するために常に時間を費やす必要がありません。 + +::: + +--- + +もし移行を始める決断をした場合、最初に行うべきことは`📁 src`のエイリアスを設定することです。これは、後で上位フォルダを参照するのに便利です。以降のテキストでは、`@`を`./src`のエイリアスとして扱います。 + +## ステップ1。コードをページごとに分割する {#divide-code-by-pages} + +ほとんどのカスタムアーキテクチャは、ロジックのサイズに関係なく、すでにページごとに分割されています。もし`📁 pages`がすでに存在する場合は、このステップをスキップできます。 + +もし`📁 routes`しかない場合は、`📁 pages`を作成し、できるだけ多くのコンポーネントコードを`📁 routes`から移動させてみてください。理想的には、小さなルートファイルと大きなページファイルがあることです。コードを移動させる際には、各ページのためのフォルダを作成し、その中にインデックスファイルを追加します。 + +:::note + +現時点では、ページ同士が互いにインポートすることは問題ありません。後でこれらの依存関係を解消するための別のステップがあります。今はページごとの明確な分割を確立することに集中します。 + +::: + +ルートファイル + +```js title="src/routes/products.[id].js" +export { ProductPage as default } from "@/pages/product" +``` + +ページのインデックスファイル + +```js title="src/pages/product/index.js" +export { ProductPage } from "./ProductPage.jsx" +``` + +ページコンポーネントファイル + +```jsx title="src/pages/product/ProductPage.jsx" +export function ProductPage(props) { + return
; +} +``` + +## ステップ2。 ページ以外のすべてを分離する {#separate-everything-else-from-pages} + +`📁 src/shared`フォルダを作成し、`📁 pages`や`📁 routes`からインポートされないすべてをそこに移動します。`📁 src/app`フォルダを作成し、ページやルートをインポートするすべてをそこに移動します。 + +Shared層にはスライスがないことを覚えておいてください。したがって、セグメントは互いにインポートできます。 + +最終的には、次のようなファイル構造になるはずです。 + +
+ 📁 src +
    +
  • +
    + 📁 app +
      +
    • +
      + 📁 routes +
        +
      • 📄 products.jsx
      • +
      • 📄 products.[id].jsx
      • +
      +
      +
    • +
    • 📄 App.jsx
    • +
    • 📄 index.js
    • +
    +
    +
  • +
  • +
    + 📁 pages +
      +
    • +
      + 📁 product +
        +
      • +
        + 📁 ui +
          +
        • 📄 ProductPage.jsx
        • +
        +
        +
      • +
      • 📄 index.js
      • +
      +
      +
    • +
    • 📁 catalog
    • +
    +
    +
  • +
  • +
    + 📁 shared +
      +
    • 📁 actions
    • +
    • 📁 api
    • +
    • 📁 components
    • +
    • 📁 containers
    • +
    • 📁 constants
    • +
    • 📁 i18n
    • +
    • 📁 modules
    • +
    • 📁 helpers
    • +
    • 📁 utils
    • +
    • 📁 reducers
    • +
    • 📁 selectors
    • +
    • 📁 styles
    • +
    +
    +
  • +
+
+ +## ステップ3。 ページ間のクロスインポートを解消する {#tackle-cross-imports-between-pages} + +あるページが他のページから何かをインポートしているすべての箇所を見つけ、次のいずれかを行います。 + +1. インポートされているコードを依存するページにコピーして、依存関係を取り除く。 +2. コードをShared層の適切なセグメントに移動する + - UIキットの一部であれば、`📁 shared/ui`に移動。 + - 設定の定数であれば、`📁 shared/config`に移動。 + - バックエンドとのやり取りであれば、`📁 shared/api`に移動。 + +:::note + +**コピー自体はアーキテクチャの問題ではありません**。実際、時には新しい再利用可能なモジュールに何かを抽象化するよりも、何かを複製する方が正しい場合もあります。ページの共通部分が異なってくることがあるため、その場合、依存関係が妨げにならないようにする必要があります。 + +ただし、DRY("don't repeat yourself" — "繰り返さない")の原則には意味があるため、ビジネスロジックをコピーしないようにしてください。そうしないと、バグを複数の箇所で修正することになることを頭に入れておく必要があります。 + +::: + +## ステップ4。 Shared層を分解する {#unpack-shared-layer} + +この段階では、Shared層に多くのものが入っているかもしれませんが、一般的にはそのような状況を避けるべきです。理由は、Shared層に依存している他の層にあるコードが存在している可能性があるため、そこに変更を加えることは予期しない結果を引き起こす可能性が高くなります。 + +特定のページでのみ使用されるすべてのオブジェクトを見つけ、それらをそのページのスライスに移動します。そして、_これにはアクション、リデューサー、セレクターも含まれます_。すべてのアクションを一緒にグループ化することには意味がありませんが、関連するアクションをその使用場所の近くに置くことには意味があります。 + +最終的には、次のようなファイル構造になるはずです。 + +
+ 📁 src +
    +
  • 📁 app (変更なし)
  • +
  • +
    + 📁 pages +
      +
    • +
      + 📁 product +
        +
      • 📁 actions
      • +
      • 📁 reducers
      • +
      • 📁 selectors
      • +
      • +
        + 📁 ui +
          +
        • 📄 Component.jsx
        • +
        • 📄 Container.jsx
        • +
        • 📄 ProductPage.jsx
        • +
        +
        +
      • +
      • 📄 index.js
      • +
      +
      +
    • +
    • 📁 catalog
    • +
    +
    +
  • +
  • +
    + 📁 shared (再利用されるオブジェクトのみ) +
      +
    • 📁 actions
    • +
    • 📁 api
    • +
    • 📁 components
    • +
    • 📁 containers
    • +
    • 📁 constants
    • +
    • 📁 i18n
    • +
    • 📁 modules
    • +
    • 📁 helpers
    • +
    • 📁 utils
    • +
    • 📁 reducers
    • +
    • 📁 selectors
    • +
    • 📁 styles
    • +
    +
    +
  • +
+
+ +## ステップ5。 コードを技術的な目的に基づいて整理する {#organize-by-technical-purpose} + +FSDでは、技術的な目的に基づく分割がセグメントによって行われます。よく見られるセグメントはいくつかあります。 + +- `ui` — インターフェースの表示に関連するすべて: UIコンポーネント、日付のフォーマット、スタイルなど。 +- `api` — バックエンドとのやり取り: リクエスト関数、データ型、マッパーなど。 +- `model` — データモデル: スキーマ、インターフェース、ストレージ、ビジネスロジック。 +- `lib` — 他のモジュールに必要なライブラリコード。 +- `config` — 設定ファイルやフィーチャーフラグ。 + +必要に応じて独自のセグメントを作成できます。ただし、コードをその性質によってグループ化するセグメント(例: `components`、`actions`、`types`、`utils`)を作成しないようにしてください。代わりに、コードの目的に基づいてグループ化してください。 + +ページのコードをセグメントに再分配します。すでに`ui`セグメントがあるはずなので、今は他のセグメント(例えば、アクション、リデューサー、セレクターのための`model`や、サンクやミューテーションのための`api`)を作成するときです。 + +また、Shared層を再分配して、次のフォルダを削除します。 + +- `📁 components`、`📁 containers` — その内容のほとんどは`📁 shared/ui`になるべきです。 +- `📁 helpers`、`📁 utils` — 再利用可能なヘルパー関数が残っている場合は、目的に基づいてグループ化し、これらのグループを`📁 shared/lib`に移動します。 +- `📁 constants` — 同様に、目的に基づいてグループ化し、`📁 shared/config`に移動します。 + +## 任意のステップ {#optional-steps} + +### ステップ6。 複数のページで使用されるReduxスライスからエンティティ/フィーチャーを形成する {#form-entities-features-from-redux} + +通常、これらの再利用可能なReduxスライスは、ビジネスに関連する何かを説明します(例えば、プロダクトやユーザーなど)。したがって、それらをエンティティ層に移動できます。1つのエンティティにつき1つのフォルダです。Reduxスライスが、ユーザーがアプリケーションで実行したいアクションに関連している場合(例えば、コメントなど)、それをフィーチャー層に移動できます。 + +エンティティとフィーチャーは互いに独立している必要があります。ビジネス領域に組み込まれたエンティティ間の関係がある場合は、[ビジネスエンティティに関するガイド][business-entities-cross-relations]を参照して、これらの関係を整理する方法を確認してください。 + +これらのスライスに関連するAPI関数は、`📁 shared/api`に残すことができます。 + +### ステップ7。 モジュールをリファクタリングする {#refactor-your-modules} + +`📁 modules`フォルダは通常、ビジネスロジックに使用されるため、すでにFSDのフィーチャー層に似た性質を持っています。一部のモジュールは、アプリケーションの大きな部分(例えば、アプリのヘッダーなど)を説明することもあります。この場合、それらをウィジェット層に移動できます。 + +### ステップ8。 `shared/ui`にUI基盤を正しく形成する {#form-clean-ui-foundation} + +理想的には、`📁 shared/ui`にはビジネスロジックが含まれていないUI要素のセットが含まれるべきです。また、非常に再利用可能である必要があります。 + +以前`📁 components`や`📁 containers`にあったUIコンポーネントをリファクタリングして、ビジネスロジックを分離します。このビジネスロジックを上位層に移動します。あまり多くの場所で使用されていない場合は、コピーを検討することもできます。 + +[ext-steiger]: https://github.com/feature-sliced/steiger +[business-entities-cross-relations]: /docs/guides/examples/types#business-entities-and-their-cross-references diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md new file mode 100644 index 0000000000..4387ebba47 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md @@ -0,0 +1,154 @@ +--- +sidebar_position: 4 +--- + +# v1からの移行 + +## なぜv2なのか? {#why-v2} + +初期の**feature-slices**の概念は、2018年に提唱されました。 + +それ以来、FSD方法論は多くの変革を経てきましたが、基本的な原則は保持されています。 + +- *標準化された*フロントエンドプロジェクト構造の使用 +- アプリケーションを*ビジネスロジック*に基づいて分割 +- *孤立した機能*の使用により、暗黙の副作用や循環依存を防止 +- モジュールの「内部」にアクセスすることを禁止する*公開API*の使用 + +しかし、以前のバージョンのFSD方法論には依然として**弱点が残っていました**。 + +- ボイラープレートの発生 +- コードベースの過剰な複雑化と抽象化間の明確でないルール +- プロジェクトのメンテナンスや新しいメンバーのオンボーディングを妨げていた暗黙のアーキテクチャ的決定 + +新しいバージョンのFSD方法論([v2][ext-v2])は、**これらの欠点を解消しつつ、既存の利点を保持することを目的としています**。 + +2018年以降、[**feature-driven**][ext-fdd]という別の類似の方法論が[発展してきました][ext-fdd-issues]。それを最初に提唱したのは[Oleg Isonen][ext-kof]でした。 + +2つのアプローチの統合により、**既存のプラクティスが改善され、柔軟性、明確さ、効率が向上しました**。 + +> 結果として、方法論の名称も「feature-slice**d**」に変更されました。 + +## なぜプロジェクトをv2に移行する意味があるのか? {#why-does-it-make-sense-to-migrate-the-project-to-v2} + +> `WIP:` 現在の方法論のバージョンは開発中であり、一部の詳細は*変更される可能性があります*。 + +#### 🔍 より透明でシンプルなアーキテクチャ {#-more-transparent-and-simple-architecture} + +FSD(v2)は、**より直感的で、開発者の間で広く受け入れられている抽象化とロジックの分割方法を提供しています**。 + +これにより、新しいメンバーの参加やプロジェクトの現状理解、アプリケーションのビジネスロジック分配に非常に良い影響を与えます。 + +#### 📦 より柔軟で誠実なモジュール性 {#-more-flexible-and-honest-modularity} + +FSD(v2)は、**より柔軟な方法でロジックを分配することを可能にしています**。 + +- 孤立した部分をゼロからリファクタリングできる +- 同じ抽象化に依存しつつ、余計な依存関係の絡みを避けられる +- 新しいモジュールの配置をよりシンプルにできる *(layer → slice → segment)* + +#### 🚀 より多くの仕様、計画、コミュニティ {#-more-specifications-plans-community} + +`core-team`は最新の(v2)バージョンのFSD方法論に積極的に取り組んでいます。 + +したがって、以下のことが期待できます。 + +- より多くの記述されたケース/問題 +- より多くの適用ガイド +- より多くの実例 +- 新しいメンバーのオンボーディングや方法論概念の学習のための全体的な文書の増加 +- 方法論の概念とアーキテクチャに関するコンベンションを遵守するためのツールキットのさらなる発展 + +> もちろん、初版に対するユーザーサポートも行われますが、私たちにとっては最新のバージョンが最優先です。 + +> 将来的には、次のメジャーアップデートの際に、現在のバージョン(v2)へのアクセスが保持され、**チームやプロジェクトにリスクをもたらすことはありません**。 + +## Changelog + +### `BREAKING` Layers + +FSD方法論は上位レベルでの層の明示的な分離を前提としています。 + +- `/app` > `/processes` > **`/pages`** > **`/features`** > `/entities` > `/shared` +- *つまり、すべてがフィーチャーやページとして解釈されるわけではない* +- このアプローチにより、層のルールを明示的に設定することが可能になる + - モジュールの**層が高いほど**、より多くの**コンテキスト**を持つことができる + + *(言い換えれば、各層のモジュールは、下層のモジュールのみをインポートでき、上層のモジュールはインポートできない)* + - モジュールの**層が低いほど**、変更を加える際の**危険性と責任**が増す + + *(一般的に、再利用されるのは下層のモジュールらからである)* + +### `BREAKING` Shared層 + +以前はプロジェクトのsrcルートにあったインフラストラクチャの `/ui`, `/lib`, `/api` 抽象化は、現在 `/src/shared` という別のディレクトリに分離されています。 + +- `shared/ui` - アプリケーションの共通UIキット(オプション) + - *ここで`Atomic Design`を使用することは引き続き許可されている* +- `shared/lib` - ロジックを実装するための補助ライブラリセット + - *引き続き、ヘルパー関数の「ごみ屋敷」を作らずに* +- `shared/api` - APIへのアクセスのための共通エントリポイント + - *各フィーチャー/ページにローカルに記述することも可能だが、推奨されない* +- 以前と同様に、`shared`にはビジネスロジックへの明示的な依存関係があってはならない + - *必要に応じて、この依存関係は`entities`、またはそれ以上の層に移動する必要がある* + +### `新規` Entities層, Processes層 + +v2では、**ロジックの複雑さと強い結合の問題を解消するために、新しい抽象化が追加されました**。 + +- `/entities` - **ビジネスエンティティ**の層で、ビジネスモデルやフロントエンド専用の合成エンティティに関連するスライスを含む + - *例:`user`, `i18n`, `order`, `blog`* +- `/processes` - アプリケーション全体にわたる**ビジネスプロセス**の層 + - **この層はオプションであり、通常は*ロジックが拡大し、複数のページにまたがる場合に使用が推奨される*** + - *例:`payment`, `auth`, `quick-tour`* + +### `BREAKING` 抽象化と命名 + +具体的な抽象化とその命名に関する[明確なガイドライン][refs-adaptability]が定義されています。 + +#### Layers + +- `/app` — **アプリケーションの初期化層** + - *以前のバリエーション: `app`, `core`, `init`, `src/index`* +- `/processes` — **ビジネスプロセスの層** + - *以前のバリエーション: `processes`, `flows`, `workflows`* +- `/pages` — **アプリケーションのページ層** + - *以前のバリエーション: `pages`, `screens`, `views`, `layouts`, `components`, `containers`* +- `/features` — **機能部分の層** + - *以前のバリエーション: `features`, `components`, `containers`* +- `/entities` — **ビジネスエンティティの層** + - *以前のバリエーション: `entities`, `models`, `shared`* +- `/shared` — **再利用可能なインフラストラクチャコードの層** 🔥 + - *以前のバリエーション: `shared`, `common`, `lib`* + +#### Segments + +- `/ui` — **UIセグメント** 🔥 + - *以前のバリエーション:`ui`, `components`, `view`* +- `/model` — **ビジネスロジックのセグメント** 🔥 + - *以前のバリエーション:`model`, `store`, `state`, `services`, `controller`* +- `/lib` — **補助コードのセグメント** + - *以前のバリエーション:`lib`, `libs`, `utils`, `helpers`* +- `/api` — **APIセグメント** + - *以前のバリエーション:`api`, `service`, `requests`, `queries`* +- `/config` — **アプリケーション設定のセグメント** + - *以前のバリエーション:`config`, `env`, `get-env`* + +### `REFINED` 低結合 + +新しいレイヤーのおかげで、モジュール間の[低結合の原則][refs-low-coupling]を遵守することがはるかに簡単になりました。 + +*それでも、モジュールを「切り離す」ことが非常に難しい場合は、できるだけ避けることが推奨されます*。 + +## 参照 {#see-also} + +- [React Berlin Talk - Oleg Isonen "Feature Driven Architecture"][ext-kof-fdd] + +[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion +[refs-adaptability]: /docs/about/understanding/naming + +[ext-fdd]: https://github.com/feature-sliced/documentation/tree/rc/feature-driven +[ext-fdd-issues]: https://github.com/kof/feature-driven-architecture/issues +[ext-v2]: https://github.com/feature-sliced/documentation +[ext-kof]: https://github.com/kof +[ext-kof-fdd]: https://www.youtube.com/watch?v=BWAeYuWFHhs diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/_category_.yaml b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/_category_.yaml new file mode 100644 index 0000000000..b4c34b26eb --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/_category_.yaml @@ -0,0 +1,2 @@ +label: 技術 +position: 3 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx new file mode 100644 index 0000000000..67de70dec4 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx @@ -0,0 +1,109 @@ +--- +sidebar_position: 10 +--- +# NextJSとの併用 + +NextJSプロジェクトでFSDを実装することは可能ですが、プロジェクトの構造に関するNextJSの要件とFSDの原則の間に2つの点で対立が生じます。 + +- `pages`のファイルルーティング +- NextJSにおける`app`の対立、または欠如 + +## `pages`におけるFSDとNextJSの対立 {#pages-conflict} + +NextJSは、アプリケーションのルートを定義するために`pages`フォルダーを使用することを提案しています。`pages`フォルダー内のファイルがURLに対応することを期待しています。このルーティングメカニズムは、FSDの概念に**適合しません**。なぜなら、このようなルーティングメカニズムでは、スライスの平坦な構造を維持することができないからです。 + +### NextJSの`pages`フォルダーをプロジェクトのルートフォルダーに移動する(推奨) + +このアプローチは、NextJSの`pages`フォルダーをプロジェクトのルートフォルダーに移動し、FSDのページをNextJSの`pages`フォルダーにインポートすることにあります。これにより、`src`フォルダー内でFSDのプロジェクト構造を維持できます。 + +```sh +├── pages # NextJSのpagesフォルダー +├── src +│ ├── app +│ ├── entities +│ ├── features +│ ├── pages # FSDのpagesフォルダー +│ ├── shared +│ ├── widgets +``` + +### FSD構造における`pages`フォルダーの名前変更 + +もう一つの解決策は、FSD構造内の`pages`層の名前を変更して、NextJSの`pages`フォルダーとの名前衝突を避けることです。 +FSDの`pages`層を`views`層に変更することができます。 +このようにすることで、`src`フォルダー内のプロジェクト構造は、NextJSの要件と矛盾することなく保持されます。 + + +```sh +├── app +├── entities +├── features +├── pages # NextJSのpagesフォルダー +├── views # 名前が変更されたFSDのページフォルダー +├── shared +├── widgets +``` + +この場合、プロジェクトのREADMEや内部ドキュメントなど、目立つ場所にこの名前変更を文書化することをお勧めします。この名前変更は、[「プロジェクト知識」][project-knowledge]の一部です。 + +## NextJSにおける`app`フォルダーの欠如 {#app-absence} + +NextJSのバージョン13未満では、明示的な`app`フォルダーは存在せず、代わりにNextJSは`_app.tsx`ファイルを提供しています。このファイルは、プロジェクトのすべてのページのラッピングコンポーネントとして機能しています。 + +### `pages/_app.tsx`ファイルへの機能のインポート + +NextJSの構造における`app`フォルダーの欠如の問題を解決するために、`app`層内に`App`コンポーネントを作成し、NextJSがそれを使用できるように`pages/_app.tsx`に`App`コンポーネントをインポートすることができます。例えば + + +```tsx +// app/providers/index.tsx + +const App = ({ Component, pageProps }: AppProps) => { + return ( + + + + + + + + ); +}; + +export default App; +``` +その後、`App`コンポーネントとプロジェクトのグローバルスタイルを`pages/_app.tsx`に次のようにインポートできます。 + +```tsx +// pages/_app.tsx + +import 'app/styles/index.scss' + +export { default } from 'app/providers'; +``` + + +## App Routerの使用 {#app-router} + +App Routerは、Next.jsのバージョン13.4で安定版として登場しました。App Routerを使用すると、`pages`フォルダーの代わりに`app`フォルダーをルーティングに使用できます。 +FSDの原則に従うために、NextJSの`app`フォルダーを`pages`フォルダーとの名前衝突を解消するために推奨される方法で扱うべきです。 + +このアプローチは、NextJSの`app`フォルダーをプロジェクトのルートフォルダーに移動し、FSDのページをNextJSの`app`フォルダーにインポートすることに基づいています。これにより、`src`フォルダー内のFSDプロジェクト構造が保持されます。また、プロジェクトのルートフォルダーに`pages`フォルダーを追加することもお勧めします。なぜなら、App RouterはPages Routerと互換性があるからです。 + +``` +├── app # NextJSのappフォルダー +├── pages # 空のNextJSのpagesフォルダー +│ ├── README.md # このフォルダーの目的に関する説明 +├── src +│ ├── app # FSDのappフォルダー +│ ├── entities +│ ├── features +│ ├── pages # FSDのpagesフォルダー +│ ├── shared +│ ├── widgets +``` + +[![StackBlitzで開く](https://developer.stackblitz.com/img/open_in_stackblitz.svg)][ext-app-router-stackblitz] + +[project-knowledge]: /docs/about/understanding/knowledge-types +[ext-app-router-stackblitz]: https://stackblitz.com/edit/stackblitz-starters-aiez55?file=README.md \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx new file mode 100644 index 0000000000..a0b7de7e16 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx @@ -0,0 +1,178 @@ +--- +sidebar_position: 10 +--- +# NuxtJSとの併用 + +NuxtJSプロジェクトでFSDを実装することは可能ですが、NuxtJSのプロジェクト構造要件とFSDの原則の違いにより、以下の2点でコンフリクトが発生してしまいます。 + +- NuxtJSは`src`フォルダーなしでプロジェクトのファイル構造を提供している。つまり、ファイル構造がプロジェクトのルートに配置される。 +- ファイルルーティングは`pages`フォルダーにあるが、FSDではこのフォルダーはフラットなスライス構造に割り当てられている。 + +## `src`ディレクトリのエイリアスを追加する + +設定ファイルに`alias`オブジェクトを追加します。 +```ts +export default defineNuxtConfig({ + devtools: { enabled: true }, // FSDには関係なく、プロジェクト起動時に有効 + alias: { + "@": '../src' + }, +}) +``` +## ルーター設定方法の選択 + +NuxtJSには、コンフィグを使用する方法とファイル構造を使用する方法の2つのルーティング設定方法があります。 +ファイルベースのルーティングの場合、`app/routes`ディレクトリ内に`index.vue`ファイルを作成します。一方、コンフィグを使用する場合は、`router.options.ts`ファイルでルートを設定します。 + +### コンフィグによるルーティング + +`app`層に`router.options.ts`ファイルを作成し、設定オブジェクトをエクスポートします。 +```ts title="app/router.options.ts" +import type { RouterConfig } from '@nuxt/schema'; + +export default { + routes: (_routes) => [], +}; + +``` + +プロジェクトにホームページを追加するには、次の手順を行います。 +- `pages`層内にページスライスを追加する +- `app/router.config.ts`のコンフィグに適切なルートを追加する + +ページスライスを作成するには、[CLI](https://github.com/feature-sliced/cli)を使用します。 + +```shell +fsd pages home +``` + +`home-page.vue`ファイルを`ui`セグメント内に作成し、公開APIを介してアクセスできるようにします。 + +```ts title="src/pages/home/index.ts" +export { default as HomePage } from './ui/home-page'; +``` + +このように、ファイル構造は次のようになります。 +```sh +|── src +│ ├── app +│ │ ├── router.config.ts +│ ├── pages +│ │ ├── home +│ │ │ ├── ui +│ │ │ │ ├── home-page.vue +│ │ │ ├── index.ts +``` +最後に、ルートをコンフィグに追加します。 + +```ts title="app/router.config.ts" +import type { RouterConfig } from '@nuxt/schema' + +export default { + routes: (_routes) => [ + { + name: 'home', + path: '/', + component: () => import('@/pages/home.vue').then(r => r.default || r) + } + ], +} +``` + +### ファイルルーティング + +まず、プロジェクトのルートに`src`ディレクトリを作成し、その中に`app`層と`pages`層のレイヤー、`app`層内に`routes`フォルダーを作成します。 +このように、ファイル構造は次のようになります。 + +```sh +├── src +│ ├── app +│ │ ├── routes +│ ├── pages # FSDに割り当てられたpagesフォルダー +``` + + +NuxtJSが`app`層内の`routes`フォルダーをファイルルーティングに使用するには、`nuxt.config.ts`を次のように変更します。 +```ts title="nuxt.config.ts" +export default defineNuxtConfig({ + devtools: { enabled: true }, // FSDには関係なく、プロジェクト起動時に有効 + alias: { + "@": '../src' + }, + dir: { + pages: './src/app/routes' + } +}) +``` + + +これで、`app`層内のページに対してルートを作成し、`pages`層からページを接続できます。 + +例えば、プロジェクトに`Home`ページを追加するには、次の手順を行います。 +- `pages`層内にページスライスを追加する +- `app`層内に適切なルートを追加する +- スライスのページとルートを統合する + +ページスライスを作成するには、[CLI](https://github.com/feature-sliced/cli)を使用します。 +```shell +fsd pages home +``` + + +`home-page.vue`ファイルを`ui`セグメント内に作成し、公開APIを介してアクセスできるようにします。  + +```ts title="src/pages/home/index.ts" +export { default as HomePage } from './ui/home-page'; +``` + +このページのルートを`app`層内に作成します。 + +```sh + +├── src +│ ├── app +│ │ ├── routes +│ │ │ ├── index.vue +│ ├── pages +│ │ ├── home +│ │ │ ├── ui +│ │ │ │ ├── home-page.vue +│ │ │ ├── index.ts +``` + +`index.vue`ファイル内にページコンポーネントを追加します。 + +```html title="src/app/routes/index.vue" + + + +``` + +## `layouts`について + +`layouts`は`app`層内に配置できます。そのためには、コンフィグを次のように変更します。 + +```ts title="nuxt.config.ts" +export default defineNuxtConfig({ + devtools: { enabled: true }, // FSDには関係なく、プロジェクト起動時に有効 + alias: { + "@": '../src' + }, + dir: { + pages: './src/app/routes', + layouts: './src/app/layouts' + } +}) +``` + + +## 参照 + +- [NuxtJSのディレクトリ設定変更に関するドキュメント](https://nuxt.com/docs/api/nuxt-config#dir) +- [NuxtJSのルーター設定変更に関するドキュメント](https://nuxt.com/docs/guide/recipes/custom-routing#router-config) +- [NuxtJSのエイリアス設定変更に関するドキュメント](https://nuxt.com/docs/api/nuxt-config#alias) + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx new file mode 100644 index 0000000000..4eabab8afc --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx @@ -0,0 +1,434 @@ +--- +sidebar_position: 10 +--- + +# React Queryとの併用 + +## キーをどこに置くか問題 + +### 解決策 - エンティティごとに分割する + +プロジェクトにすでにエンティティの分割があり、各クエリが1つのエンティティに対応している場合、エンティティごとに分割するのが最良です。この場合、次の構造を使用することをお勧めします。 + +```sh +└── src/ # + ├── app/ # + | ... # + ├── pages/ # + | ... # + ├── entities/ # + | ├── {entity}/ # + | ... └── api/ # + | ├── `{entity}.query` # クエリファクトリー、キーと関数が定義されている + | ├── `get-{entity}` # エンティティを取得する関数 + | ├── `create-{entity}` # エンティティを作成する関数 + | ├── `update-{entity}` # オブジェクトを更新する関数 + | ├── `delete-{entity}` # オブジェクトを削除する関数 + | ... # + | # + ├── features/ # + | ... # + ├── widgets/ # + | ... # + └── shared/ # + ... # +``` + +もしエンティティ間に関係がある場合(例えば、「国」のエンティティに「都市」のエンティティ一覧フィールドがある場合)、`@x` アノテーションを使用した組織的なクロスインポートの[実験的アプローチ](https://github.com/feature-sliced/documentation/discussions/390#discussioncomment-5570073)を利用するか、以下の代替案を検討できます。 + +### 代替案 — クエリを公開で保存する + +エンティティごとの分割が適さない場合、次の構造を考慮できます。 + +```sh +└── src/ # + ... # + └── shared/ # + ├── api/ # + ... ├── `queries` # クエリファクトリー + | ├── `document.ts` # + | ├── `background-jobs.ts` # + | ... # + └── index.ts # +``` + +次に、`@/shared/api/index.ts`に + +```ts title="@/shared/api/index.ts" +export { documentQueries } from "./queries/document"; +``` + +## 問題「ミューテーションはどこに?」 + +ミューテーションをクエリと混合することは推奨されません。2つの選択肢が考えられます。 + +### 1. 使用場所の近くにAPIセグメントにカスタムフックを定義する + +```tsx title="@/features/update-post/api/use-update-title.ts" +export const useUpdateTitle = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ id, newTitle }) => + apiClient + .patch(`/posts/${id}`, { title: newTitle }) + .then((data) => console.log(data)), + + onSuccess: (newPost) => { + queryClient.setQueryData(postsQueries.ids(id), newPost); + }, + }); +}; +``` + +### 2. 別の場所(Shared層やEntities層)にミューテーション関数を定義し、コンポーネント内で`useMutation`を直接使用する + +```tsx +const { mutateAsync, isPending } = useMutation({ + mutationFn: postApi.createPost, +}); +``` + +```tsx title="@/pages/post-create/ui/post-create-page.tsx" +export const CreatePost = () => { + const { classes } = useStyles(); + const [title, setTitle] = useState(""); + + const { mutate, isPending } = useMutation({ + mutationFn: postApi.createPost, + }); + + const handleChange = (e: ChangeEvent) => + setTitle(e.target.value); + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + mutate({ title, userId: DEFAULT_USER_ID }); + }; + + return ( +
+ + + Create + + + ); +}; +``` + +## クエリの組織化 + +### クエリファクトリー + +このガイドでは、クエリファクトリーの使い方について説明します。 + +:::note +クエリファクトリーとは、JSオブジェクトのことで、そのオブジェクトキーの値がクエリキー一覧を返す関数である。 +::: + +```ts +const keyFactory = { + all: () => ["entity"], + lists: () => [...postQueries.all(), "list"], +}; +``` + +:::info +`queryOptions` - react-query@v5に組み込まれたユーティリティ(オプション) + +```ts +queryOptions({ + queryKey, + ...options, +}); +``` + +より高い型安全性と将来のreact-queryのバージョンとの互換性を確保し、クエリの関数やキーへのアクセスを簡素化するために、`@tanstack/react-query`の`queryOptions`関数を使用することができる[(詳細はこちら)](https://tkdodo.eu/blog/the-query-options-api#queryoptions)。 + +::: + + +### 1. クエリファクトリーの作成 + +```tsx title="@/entities/post/api/post.queries.ts" +import { keepPreviousData, queryOptions } from "@tanstack/react-query"; +import { getPosts } from "./get-posts"; +import { getDetailPost } from "./get-detail-post"; +import { PostDetailQuery } from "./query/post.query"; + +export const postQueries = { + all: () => ["posts"], + + lists: () => [...postQueries.all(), "list"], + list: (page: number, limit: number) => + queryOptions({ + queryKey: [...postQueries.lists(), page, limit], + queryFn: () => getPosts(page, limit), + placeholderData: keepPreviousData, + }), + + details: () => [...postQueries.all(), "detail"], + detail: (query?: PostDetailQuery) => + queryOptions({ + queryKey: [...postQueries.details(), query?.id], + queryFn: () => getDetailPost({ id: query?.id }), + staleTime: 5000, + }), +}; +``` + +### 2. アプリケーションコードでのクエリファクトリーの適用 + +```tsx +import { useParams } from "react-router-dom"; +import { postApi } from "@/entities/post"; +import { useQuery } from "@tanstack/react-query"; + +type Params = { + postId: string; +}; + +export const PostPage = () => { + const { postId } = useParams(); + const id = parseInt(postId || ""); + const { + data: post, + error, + isLoading, + isError, + } = useQuery(postApi.postQueries.detail({ id })); + + if (isLoading) { + return
Loading...
; + } + + if (isError || !post) { + return <>{error?.message}; + } + + return ( +
+

Post id: {post.id}

+
+

{post.title}

+
+

{post.body}

+
+
+
Owner: {post.userId}
+
+ ); +}; +``` + +### クエリファクトリーを使用する利点 +- **クエリの構造化:** ファクトリーはすべてのAPIクエリを1か所に整理し、コードをより読みやすく、保守しやすくしている +- **クエリとキーへの便利なアクセス:** ファクトリーはさまざまなタイプのクエリとそのキーへの便利なメソッドを提供している +- **クエリの再フェッチ機能:** ファクトリーは、アプリケーションのさまざまな部分でクエリキーを変更することなく、簡単に再フェッチを行うことを可能にしている + +## ページネーション + +このセクションでは、ページネーションを使用して投稿エンティティを取得するためのAPIクエリを行う`getPosts`関数の例を挙げます。 + +### 1. `getPosts`関数の作成 + +`getPosts`関数は、APIセグメント内の`get-posts.ts`ファイルにあります。 + +```tsx title="@/pages/post-feed/api/get-posts.ts" +import { apiClient } from "@/shared/api/base"; + +import { PostWithPaginationDto } from "./dto/post-with-pagination.dto"; +import { PostQuery } from "./query/post.query"; +import { mapPost } from "./mapper/map-post"; +import { PostWithPagination } from "../model/post-with-pagination"; + +const calculatePostPage = (totalCount: number, limit: number) => + Math.floor(totalCount / limit); + +export const getPosts = async ( + page: number, + limit: number, +): Promise => { + const skip = page * limit; + const query: PostQuery = { skip, limit }; + const result = await apiClient.get("/posts", query); + + return { + posts: result.posts.map((post) => mapPost(post)), + limit: result.limit, + skip: result.skip, + total: result.total, + totalPages: calculatePostPage(result.total, limit), + }; +}; +``` + +### 2. ページネーション用のクエリファクトリー + +`postQueries`クエリファクトリーは、投稿に関するさまざまなクエリオプションを定義し、事前に定義されたページとリミットを使用して投稿一覧を取得するクエリを含みます。 + +```tsx +import { keepPreviousData, queryOptions } from "@tanstack/react-query"; +import { getPosts } from "./get-posts"; + +export const postQueries = { + all: () => ["posts"], + lists: () => [...postQueries.all(), "list"], + list: (page: number, limit: number) => + queryOptions({ + queryKey: [...postQueries.lists(), page, limit], + queryFn: () => getPosts(page, limit), + placeholderData: keepPreviousData, + }), +}; +``` + + +### 3. アプリケーションコードでの使用 + +```tsx title="@/pages/home/ui/index.tsx" +export const HomePage = () => { + const itemsOnScreen = DEFAULT_ITEMS_ON_SCREEN; + const [page, setPage] = usePageParam(DEFAULT_PAGE); + const { data, isFetching, isLoading } = useQuery( + postApi.postQueries.list(page, itemsOnScreen), + ); + return ( + <> + setPage(page)} + page={page} + count={data?.totalPages} + variant="outlined" + color="primary" + /> + + + ); +}; +``` +:::note +例は簡略化されている。 +::: + +## クエリ管理用の`QueryProvider` + +このガイドでは、`QueryProvider`をどのように構成するべきかを説明します。 + +### 1. `QueryProvider`の作成 + +`query-provider.tsx`ファイルは`@/app/providers/query-provider.tsx`にあります。 + +```tsx title="@/app/providers/query-provider.tsx" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { ReactNode } from "react"; + +type Props = { + children: ReactNode; + client: QueryClient; +}; + +export const QueryProvider = ({ client, children }: Props) => { + return ( + + {children} + + + ); +}; +``` + +### 2. `QueryClient`の作成 + +`QueryClient`はAPIクエリを管理するために使用されるインスタンスです。`query-client.ts`ファイルは`@/shared/api/query-client.ts`にあります。`QueryClient`はクエリキャッシング用の特定の設定で作成されます。 + +```tsx title="@/shared/api/query-client.ts" +import { QueryClient } from "@tanstack/react-query"; + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, + gcTime: 5 * 60 * 1000, + }, + }, +}); +``` + +## コード生成 + +自動コード生成のためのツールが存在しますが、これらは上記のように設定可能なものと比較して柔軟性が低いです。Swaggerファイルが適切に構造化されている場合、これらのツールの1つを使用して`@/shared/api`ディレクトリ内のすべてのコードを生成することができます。 + +## RQの整理に関する追加のアドバイス + +### APIクライアント + +共有層であるshared層でカスタムのAPIクライアントクラスを使用することで、プロジェクト内でのAPI設定やAPI操作を標準化できます。これにより、ログ記録、ヘッダー、およびデータ交換形式(例: JSONやXML)を一元管理することができます。このアプローチにより、APIとの連携の変更や更新が簡単になり、プロジェクトのメンテナンスや開発が容易になります。 + +```tsx title="@/shared/api/api-client.ts" +import { API_URL } from "@/shared/config"; + +export class ApiClient { + private baseUrl: string; + + constructor(url: string) { + this.baseUrl = url; + } + + async handleResponse(response: Response): Promise { + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + try { + return await response.json(); + } catch (error) { + throw new Error("Error parsing JSON response"); + } + } + + public async get( + endpoint: string, + queryParams?: Record, + ): Promise { + const url = new URL(endpoint, this.baseUrl); + + if (queryParams) { + Object.entries(queryParams).forEach(([key, value]) => { + url.searchParams.append(key, value.toString()); + }); + } + const response = await fetch(url.toString(), { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + return this.handleResponse(response); + } + + public async post>( + endpoint: string, + body: TData, + ): Promise { + const response = await fetch(`${this.baseUrl}${endpoint}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + return this.handleResponse(response); + } +} + +export const apiClient = new ApiClient(API_URL); +``` + +## 参照 {#see-also} + +- [The Query Options API](https://tkdodo.eu/blog/the-query-options-api) + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx new file mode 100644 index 0000000000..c7b450db92 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx @@ -0,0 +1,96 @@ +--- +sidebar_position: 10 +--- +# SvelteKitとの併用 + +SvelteKitプロジェクトでFSDを実装することは可能ですが、SvelteKitのプロジェクト構造要件とFSDの原則の違いにより、以下の2点でコンフリクトが発生してしまいます。 + +- SvelteKitは`src/routes`フォルダー内でファイル構造を作成することを提案しているが、FSDではルーティングは`app`層の一部である必要がある +- SvelteKitは、ルーティングに関係のないすべてのものを`src/lib`フォルダーに入れることを提案している + +## コンフィグファイルの設定 + +```ts title="svelte.config.ts" +import adapter from '@sveltejs/adapter-auto'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config}*/ +const config = { + preprocess: [vitePreprocess()], + kit: { + adapter: adapter(), + files: { + routes: 'src/app/routes', // ルーティングをapp層内に移動 + lib: 'src', + appTemplate: 'src/app/index.html', // アプリケーションのエントリーポイントをapp層内に移動 + assets: 'public' + }, + alias: { + '@/*': 'src/*' // srcディレクトリのエイリアスを作成 + } + } +}; +export default config; +``` + +## `src/app`内へのファイルルーティングの移動 + +`app`層を作成し、アプリケーションのエントリーポイントである`index.html`を移動し、`routes`フォルダーを作成します。 +最終的にファイル構造は次のようになります。 + +```sh +├── src +│ ├── app +│ │ ├── index.html +│ │ ├── routes +│ ├── pages # FSDに割り当てられたpagesフォルダー +``` + +これで、`app`内にページのルートを作成したり、`pages`からのページをルートに接続したりできます。 + +例えば、プロジェクトにホームページを追加するには、次の手順を実行します。 +- `pages`層内にホームページスライスを追加する +- `app`層の`routes`フォルダーに対応するルートを追加する +- スライスのページとルートを統合する + +ホームページスライスを作成するには、[CLI](https://github.com/feature-sliced/cli)を使用します。 + +```shell +fsd pages home +``` + +`ui`セグメント内に`home-page.svelte`ファイルを作成し、公開APIを介してアクセスできるようにします。  + +```ts title="src/pages/home/index.ts" +export { default as HomePage } from './ui/home-page'; +``` + +このページのルートを`app`層内に作成します。 + +```sh + +├── src +│ ├── app +│ │ ├── routes +│ │ │ ├── +page.svelte +│ │ ├── index.html +│ ├── pages +│ │ ├── home +│ │ │ ├── ui +│ │ │ │ ├── home-page.svelte +│ │ │ ├── index.ts +``` + +最後に`index.svelte`ファイル内にページコンポーネントを追加します。 + +```html title="src/app/routes/+page.svelte" + + + + +``` + +## 参照 +- [SvelteKitのディレクトリ設定変更に関するドキュメント](https://kit.svelte.dev/docs/configuration#files) \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/intro.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/intro.mdx new file mode 100644 index 0000000000..738b12efaf --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/intro.mdx @@ -0,0 +1,69 @@ +--- +sidebar_position: 1 +slug: / +pagination_next: get-started/index +--- + +# ドキュメント + +![feature-sliced-banner](/img/banner.jpg) + +**Feature-Sliced Design** (FSD) とは、フロントエンドアプリケーションの設計方法論です。簡単に言えば、コードを整理するためのルールと規約の集大成です。FSDの主な目的は、ビジネス要件が絶えず変化する中で、プロジェクトをより理解しやすく、構造化されたものにすることです。 + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { RocketOutlined, ThunderboltOutlined, FundViewOutlined } from "@ant-design/icons"; +import Link from "@docusaurus/Link"; + + + + + +
+ + + + + + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx new file mode 100644 index 0000000000..86d8f4b2c1 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx @@ -0,0 +1,38 @@ +--- +hide_table_of_contents: true +pagination_prev: guides/index +--- + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { ApiOutlined, GroupOutlined, AppstoreOutlined, NodeIndexOutlined } from "@ant-design/icons"; + +# 📚 参考書 + +

+FSDの重要な概念に関するセクション +

+ + + + + \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml new file mode 100644 index 0000000000..b6ec783a3f --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml @@ -0,0 +1 @@ +label: 分離 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md new file mode 100644 index 0000000000..7b6be93160 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md @@ -0,0 +1,147 @@ +--- +sidebar_position: 1 +--- + +# 低結合と高凝集 + +アプリケーションのモジュールは、**強い結合性**(明確なタスクを解決することに焦点を当てる)と**弱い結合性**(他のモジュールからできるだけ依存しない)を持つように設計されるべきです。 + +
+ + +
+ インスパイア先: https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/ +
+
+ +FSDでは、以下の方法で達成されます。 + +* アプリケーションを層とスライスに分割する - 特定の機能を実現するモジュール。 +* 各モジュールには、[公開API][refs-public-api]を提供することが求められます。 +* モジュール間の[相互作用][refs-isolation]に特別な制限を設ける - 各モジュールは「下位」のモジュールにのみ依存でき、同じ層またはそれ以上の層のモジュールには依存できません。 + +## コンポーネントの構成(UIレベル) {#components-composition-ui-level} + +ほとんどの現代のUIフレームワークやライブラリは、各コンポーネントが独自のプロパティ、状態、子コンポーネントを持つことができるコンポーネントモデルを提供しています。 + +このモデルにより、**直接的に関連しないさまざまなコンポーネントの構成**としてインターフェースを構築し、**コンポーネントの弱い結合性**を達成することができます。 + +### 例 {#example} + +**ヘッダー付きリスト**の例を考えてみましょう。 + +#### 拡張性を考慮する {#laying-the-extensibility} + +リストコンポーネントは、ヘッダーとリストアイテムの構造を自ら定義せず、代わりにそれらをパラメータとして受け取ります。 + +```tsx +interface ListProps { + Header: React.ReactNode; + Items: React.ReactNode; +} + +const List: Component = ({ Header, Items }) => ( +
+ {Header} +
    + {Items} +
+
+) +``` + +#### 構成を使用する {#using-the-composition} + +これにより、**異なるバージョンのヘッダーやリストアイテムのコンポーネントを再利用し、独立して変更する**ことが可能になります。ヘッダーとリストアイテムのコンポーネントは、それぞれ独自のローカル状態やアプリケーションの共通状態の任意の部分へのバインディングを持つことができ、リストコンポーネントはそれについて何も知らず、したがってそれに依存しません。 + +```tsx +} Items={} /> + +} /> + +} Items={} /> +``` + +## 層の構成(アプリレベル) {#layer-composition-app-level} + +FSDは、ユーザーにとって価値のある機能を個別のモジュール - **フィーチャー(features)** - に分割し、ビジネスエンティティに関連するロジックを**エンティティ(entities)**に分けることを提案します。フィーチャーとエンティティは、**高い結合性を持つモジュール**として設計されるべきであり、すなわち**特定のタスクを解決することに焦点を当てる**か、**特定のエンティティの周りに集中する**べきです。 + +これらのモジュール間のすべての相互作用は、上記のUIコンポーネントの例と同様に、**さまざまなモジュールの構成**として整理されるべきです。 + +### 例 {#example} + +チャットアプリケーションの例を考えてみましょう。 + +* 連絡先リストを開いて友達を選択できる +* 選択した友達とのチャットを開くことができる + +FSDに基づいて、次のように表現できます。 + +エンティティ + +* ユーザー(ユーザーの状態を含む) +* 連絡先(連絡先リストの状態、特定の連絡先を操作するためのツール) +* チャット(現在のチャットの状態とその操作) + +フィーチャー + +* メッセージ送信フォーム +* チャット選択メニュー + +#### すべてを結びつける {#lets-tie-it-all-together} + +アプリケーションには、最初に1つのページがあり、インターフェースは最初の例の少し修正されたコンポーネントに基づいています。 + +```tsx title="page/main/ui.tsx" +} + Items={} + Footer={} +/> +``` + +#### データモデル {#data-model} + +ページのデータモデルは、**フィーチャーとエンティティの構成**として整理されます。この例では、フィーチャーはファクトリーとして実装され、これらのファクトリーのパラメータを介してエンティティのインターフェースにアクセスします。 + +> ただし、ファクトリーとしての実装は必須ではなく、フィーチャーは下位層に依存し、直接的にアクセスすることもできます。 + +```ts title="pages/main/model.ts" +import { userModel } from "entitites/user" +import { conversationModel } from "entities/conversation" +import { contactModel } from "entities/contact" + +import { createMessageInput } from "features/message-input" +import { createConversationSwitch } from "features/conversation-switch" + +import { beautifiy } from "shared/lib/beautify-text" + +export const { allConversations, setConversation } = createConversationSwitch({ + contacts: contactModel.allContacts, + setConversation: conversationModel.setConversation, + currentConversation: conversationModel.conversation, + currentUser: userModel.currentUser +}) + +export const { sendMessage, attachFile } = createMessageInput({ + author: userModel.currentUser, + send: conversationModel.sendMessage, + formatMessage: beautify +}) +``` + +## まとめ {#summary} + +1. モジュールは**強い結合性**を持つべきであり(1つの責任を持ち、特定のタスクを解決する)、[**公開API**][refs-public-api]を提供する必要があります。 +2. **弱い結合性**は、UIコンポーネント、フィーチャー、エンティティの要素の構成を通じて達成されます。 +3. また、結合性を低下させるために、モジュールは**公開APIを介してのみ互いに依存するべきです** - これにより、モジュールは互いの内部実装から独立します。 + +## 参照 {#see-also} + +* [(記事) 低結合と高凝集についての視覚的説明](https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/) + * *最初の図はこの論文からインスパイアを受けています* +* [(記事) 低結合と高凝集。デメトリの法則](https://medium.com/german-gorelkin/low-coupling-high-cohesion-d36369fb1be9) +* [(プレゼンテーション) 設計原則について(低結合と高凝集を含む)](https://www.slideshare.net/cristalngo/software-design-principles-57388843) + +[refs-public-api]: /docs/reference/public-api +[refs-isolation]: /docs/reference/isolation diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx new file mode 100644 index 0000000000..e4162bdd1e --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx @@ -0,0 +1,21 @@ +--- +sidebar_position: 2 +sidebar_class_name: sidebar-item--wip +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# エンティティの分離 + + + +> タイプのクロスインポート、アダプター、エンティティ間の明示的な関係の構築について + +> また、神話的な完全に分離されたエンティティについても + +## 参照 {#see-also} + +- [(スレッド) エンティティの分解と明示的な関係の構築に関するメモ](https://t.me/feature_sliced/3633) +- [(スレッド) 「関連するエンティティ」(ユーザー/ペット/友人)の分解の例](https://t.me/feature_sliced/3316) +- [(スレッド) エンティティにおけるタイプ/アダプターのクロスインポートについて](https://t.me/feature_sliced/4276) +- [(スレッド) エンティティと機能の境界について](https://t.me/feature_sliced/4521) \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md new file mode 100644 index 0000000000..70de1bb20d --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md @@ -0,0 +1,63 @@ +# モジュールの分離 + +FSDの枠組みの中で、すべてのモジュールは責任の領域(レイヤー、スライス、セグメント)に分配されています。 + +レイヤーは縦に組織されています。 + +- "下層"には再利用可能なモジュール(ui-kit、プロジェクトの内部ライブラリ)があり、最も抽象的です。 +- "上層"に進むにつれて、より特定的なモジュールが配置されます。 + +どのスライスに属していても、各モジュールは[**公開アクセスインターフェースを提供する義務があります**][refs-public-api]。 + +## 要件 {#requirements} + +各モジュールが他のアプリケーションと相互作用する際には、いくつかの要件を考慮して設計されます。 + +1. **他のモジュールとの弱い結合** + - *1つのモジュールの変更は、他のモジュールに対して弱く予測可能な影響を与えるべきです。* +1. **高い結合性** - 各モジュールの責任は「1つのタスク」に焦点を当てています。 + - *モジュールがあまりにも多くの責任を持つ場合(「やりすぎる」場合)、それはできるだけ早く認識されるべきです。* +1. **アプリケーション全体での循環依存の不在** + - *これはしばしば予期しない望ましくない動作を引き起こすため、完全に避けるべきです。* + +## ルール {#rule} + +これらの要件を満たすために、方法論の枠組みの中で基本的なルールを守る必要があります。 + +:::info 重要 + +モジュールは「下層」のモジュールにのみ依存でき、同じ層またはそれ以上の層のモジュールには依存できません。 + +::: + +- `features/auth` **は** `features/filters` **に依存できません** **し、逆も同様です。** +- `features/auth` **は** `shared/ui/button` **に依存できますが、逆はできません。** + +このルールに従うことで、依存関係を**「一方向」に保つ**ことができ、これにより**循環インポートを自動的に排除し**、モジュール間の依存関係の追跡を大幅に**簡素化**します。 + +## 問題の特定 {#identifying-problems} + + +このルールの違反は問題の信号です。 + +1. モジュールが自層の他のモジュールから**インポートを持つ** + - モジュールが**過剰に細分化されている**か、**余分な責任を持っている**可能性があります。 + - インポートされたモジュールと**統合する**か、**部分的または完全に下層に移動する**か、上層のモジュールに依存関係のロジックを移動する必要があります。 +1. モジュールが自層の多くのモジュールから**インポートされる** + - モジュールが**余分な責任を持っている**可能性があります。 + - **部分的または完全に下層に移動する**か、上層のモジュールに依存関係のロジックを移動する必要があります。 +1. モジュールが自層の多くのモジュールから**インポートを持つ** + - モジュールが**別の責任領域に属している**可能性があります。 + - **部分的または完全に上層に移動する**必要があります。 + +## 参照 {#see-also} + +- [(ガイド) 低い結合性の達成について][refs-low-coupling] +- [(ディスカッション) 方法論におけるエンティティとその結合性](https://github.com/feature-sliced/documentation/discussions/49) +- [(ディスカッション) クロスインポートと依存関係の分析について](https://github.com/feature-sliced/documentation/discussions/65#discussioncomment-480822) +- [パターン **GRASP**](https://ru.wikipedia.org/wiki/GRASP) + +[refs-public-api]: /docs/reference/public-api +[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/layers.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/reference/layers.mdx new file mode 100644 index 0000000000..665317d047 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/layers.mdx @@ -0,0 +1,181 @@ +--- +sidebar_position: 1 +pagination_next: reference/slices-segments +--- + +# レイヤー + +レイヤー(層)は、Feature-Sliced Designにおける組織階層の最初のレベルです。その目的は、コードを必要な責任の量とアプリケーション内の他のモジュールへの依存度に基づいて分割することです。 + +:::note + +このページでのモジュールは、アプリケーション内のファイルやインデックスファイルを持つディレクトリを指している。npmパッケージと混同しないでください。 + +::: + +各レイヤーは、コード内のモジュールにどれだけの責任を割り当てるべきかを判断するのに役立つ特別な意味を持っています。レイヤー名とレイヤーの意味は、Feature-Sliced Designを使用して構築されたすべてのプロジェクトで標準化されています。 + +合計で7つのレイヤーがあり、最も責任と依存度が高いものから最も低いものへと配置されています。 + +ファイルシステムのツリーは、1つのルートフォルダsrcと7つのサブフォルダ(app、processes、pages、widgets、features、entities、shared)で構成されています。processesフォルダは少し薄く表示されています。 +ファイルシステムのツリーは、1つのルートフォルダsrcと7つのサブフォルダ(app、processes、pages、widgets、features、entities、shared)で構成されています。processesフォルダは少し薄く表示されています。 + +1. App (アップ) +2. Processes (プロセス、非推奨) +3. Pages (ページ) +4. Widgets (ウィジェット) +5. Features (フィーチャー) +6. Entities (エンティティ) +7. Shared (シェアード) + +プロジェクトで全てのレイヤーを使用する必要はないので、プロジェクトに価値をもたらすレイヤーだけを追加してください。 + +## レイヤーのインポートルール {#import-rule-on-layers} + +レイヤーは、強く結合されたモジュールのグループであるスライスから構成されています。Feature-Sliced Designは低い結合度をサポートしているため、スライス間の依存関係はレイヤーのインポートルールによって制御されます。 + +> _スライス内のモジュールは、下層のレイヤーにあるスライスのみをインポートできる。_ + +例えば、`~/features/aaa` では、スライスは `aaa` であるため、`~/features/aaa/api/request.ts` ファイルは `~/features/bbb` フォルダー内のモジュールからコードをインポートすることはできませんが、`~/entities` や `~/shared` から、また `~/features/aaa` 内の隣接モジュールからはインポートできます。 + +## レイヤーの定義 + +### Shared層 + +Shared層は、プロジェクトやビジネスの特性から切り離された、孤立したモジュール、コンポーネント、抽象化のことです。 + +このレイヤーは他のレイヤーとは異なり、スライスではなく直接セグメントで構成されています。 + +**内容の例** + +* UIライブラリ +* APIクライアント +* ブラウザAPIと連携するコード + +### Entities層 + +Entities層は、プロジェクトの本質を形成する現実世界の概念です。通常、これはビジネスがプロダクトを説明するために使用する用語です。 + +このレイヤーの各スライスは、ユーザーインターフェースの静的要素、データストレージ、およびCRUD(作成・読み取り・更新・削除)操作を含みます。 + +**スライスの例** + + + +
SNS Gitフロントエンド(例:GitHub)
    +
  • ユーザー
  • +
  • 投稿
  • +
  • グループ
  • +
    +
  • リポジトリ
  • +
  • ファイル
  • +
  • コミット
  • +
+ +:::tip + +Gitフロントエンドの例では、リポジトリファイルを含むことに気付くかもしれません。これは、リポジトリが他のエンティティを内包する高レベルのエンティティであることを示しています。このような高レベルのエンティティを作成ことは一般的が、この場合、レイヤーのインポートルールを破らないことは時に難しいです。 + +この問題を解決するためのいくつかの提案があります。 +* エンティティのUIは、下位レベルのエンティティを挿入するためのスロットを含むべき +* エンティティ間の相互作用に関連するビジネスロジックは、通常、Features層に配置されるべき +* データベースのエンティティインターフェースは、APIクライアントの近くにあるShared層に抽出できる + +::: + +### Features層 + +Features層は、ユーザーがアプリケーション内でビジネスエンティティとインタラクションするために行うアクションで、価値のある結果を達成するためのものです。ここには、ユーザーのためにアプリケーションが実行するアクションも含まれています。 + +このレイヤーのスライスは、価値を生み出すアクションを実行するためのインタラクティブなUI要素、内部状態、およびAPIリクエストを含むことができます。 + +**スライスの例** + + + +
SNS Gitフロントエンド(例:GitHub) ユーザーの代わりに行うアクション
    +
  • ログイン
  • +
  • 投稿を作成
  • +
  • グループに参加
  • +
    +
  • ファイルを変更
  • +
  • コメントを残す
  • +
  • ブランチをマージ
  • +
    +
  • ダークテーマを自動的に有効にする
  • +
  • バックグラウンドで計算を実行する
  • +
  • User-Agentに基づくアクション
  • +
+ +### Widgets層 + +Widgets層は、独立したUIブロックであり、エンティティやフィーチャーなどの低レベルユニットの組み合わせです。 + +このレイヤーは、エンティティのインターフェースに残されたスロットを、他のフィーチャーからのインタラクティブ要素やエンティティで埋めることを可能にしています。したがって、通常、このレイヤーにはビジネスロジックは配置されず、代わりにフィーチャーに保存されます。このレイヤーの各スライスは、使用可能なUIコンポーネントを含み、時にはビジネスロジック以外のロジック(例えば、ジェスチャー、キーボードとの相互作用など)を含むことがあります。 + +時には、このレイヤーにビジネスロジックを配置する方が便利な場合もあります。これは、ウィジェットがかなりのインタラクティブ性を持っている場合(例えば、インタラクティブテーブル)で、その中のビジネスロジックが再利用されない場合によく発生します。 + +**スライスの例** + + + +
SNS Gitフロントエンド(例:GitHub)
    +
  • 投稿カード
  • +
  • ユーザープロフィールのヘッダー(アクション付き)
  • +
    +
  • リポジトリ内のファイル一覧(アクション付き)
  • +
  • スレッド内のコメント
  • +
  • リポジトリカード
  • +
+ +:::tip + +ネストされたルーティングシステム(例えば、[Remix][ext--remix]ルーター)を使用している場合、Widgets層をPages層と同様に使用することが便利なケースがあります。例えば、バックエンドからのデータを取得し、読み込み状態やエラー処理を含むインターフェースブロックを作成する際に役立てます。また、Pages層のレイアウトをここに配置することもできます。 +::: + +### Pages層 + +Pages層は、ページベースのアプリケーション(例えば、ウェブサイト)のページや、画面ベースのアプリケーション(例えば、モバイルアプリ)の画面やアクティビティです。 + +このレイヤーは、その構成的な性質においてWidgets層に似ていますが、より大きな規模で構成されています。Pages層の各スライスは、ルーターに接続できるUIコンポーネントを含むほか、データ取得やエラー処理のロジックを含むこともできます。 + +**スライスの例** + + + +
SNS Gitフロントエンド(例:GitHub)
    +
  • ニュースフィード
  • +
  • コミュニティページ
  • +
  • 公開ユーザープロフィール
  • +
    +
  • リポジトリページ
  • +
  • ユーザーのリポジトリ
  • +
  • リポジトリ内のブランチ
  • +
+ +### Processes層 + +:::caution + +このレイヤーは、廃止されています。現在の仕様バージョンでは、これを避け、内容を `features`層 と `app`層 に移動することを推奨しています。 + +::: + +Processes層は、複雑なマルチページインタラクションが必要な際に使用されます。 + +このレイヤーは意図的にあまり定義されていません。ほとんどのアプリケーションにはこのレイヤーは必要ありません。ルーターやサーバーレベルのロジックはApp層に残すべきです。このレイヤーは、App層が成長しすぎて管理できなくなった場合にのみ使用を検討してください。 + +### App層 + +App層は、アプリ全体に関するすべてのことです。技術的な意味(例えば、コンテキストプロバイダー)とビジネス的な意味(例えば、分析)を含みます。 + +このレイヤーは通常、Shared層と同様にスライスを含まず、直接セグメントで構成されています。 + +**内容の例** + +* スタイル +* ルーター +* データストレージやその他のコンテキストプロバイダー +* 分析の初期化 + +[ext--remix]: https://remix.run \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/public-api.md b/i18n/ja/docusaurus-plugin-content-docs/current/reference/public-api.md new file mode 100644 index 0000000000..8b07850319 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/public-api.md @@ -0,0 +1,216 @@ +--- +sidebar_position: 3 +sidebar_label: 公開API +pagination_next: about/index +--- + +# 公開API + +FSDでの各エンティティは、**使いやすく統合しやすいモジュール**として設計されています。 + +## 目的 {#goals} + +モジュールの使いやすさと統合しやすさは、*いくつかの目的*を達成することによって実現されます。 + +1. アプリケーションは、個々モジュール内部構造の**変更から保護されるべき** +1. モジュール内部構造の再設計は、**他のモジュールに影響を与えてはならない** +1. モジュールの動作の重要な変更は、**簡単に特定できるべき** + > **モジュールの動作に関する重要な変更**とは、モジュール利用者の期待を壊す変更 + +これらの目的を達成するために、公開API(公開インターフェース)が導入され、モジュール機能への単一アクセス点を提供し、モジュールと外部世界との相互作用の「契約」を定義します。 + +:::info 重要 + +エンティティの構造は、公開APIを提供する単一のエントリーポイントを持つべき + +::: + +```sh +└── features/                        #  + └── auth-form/                  # フィーチャーの内部構造 + ├── ui/                    # + ├── model/                 # + ├── {...}/                 # + └── index.ts               # フィーチャーの公開APIを持つエントリーポイント +``` + +```ts title="**/**/index.ts" +export { Form as AuthForm } from "./ui" +export * as authFormModel from "./model" +``` + +## 公開APIの要件 {#requirements-for-the-public-api} + +下記の要件を満たすことで、モジュールとの相互作用を**公開API契約の実行**に制限し、モジュールの信頼性と使いやすさを達成できます。 + +### 1. アクセス制御 {#1-access-control} + +公開APIは、モジュール内容への**アクセス制御**を行うべきです。 + +- アプリケーションの他の部分は、**公開APIで提供されるモジュールのエンティティのみを使用できる** +- 公開APIのないモジュールの内部部分は、**モジュール自身のみがアクセスできる** + +#### 例 {#examples} + +##### プライベートインポートからの排除 {#suspension-from-private-imports} + +- **悪い例**: 公開APIをバイパスしてモジュールの内部部分に直接アクセスすることは危険であり、特にモジュールのリファクタリング時に問題を引き起こす可能性がある。 + + ```diff + - import { Form } from "features/auth-form/components/view/form" + ``` + +- **良い例**: APIは事前に必要なものだけをエクスポートし、モジュールの開発者はリファクタリング時に公開APIを壊さないことだけを考えればよい。 + + ```diff + + import { AuthForm } from "features/auth-form" + ``` + +### 2. 変更への耐性 {#2-sustainability-for-changes} + +公開APIは、モジュール内部の**変更に対して耐性があるべきです**。 + +- モジュールの動作を壊す変更は、公開APIの変更として反映されるべき + +#### 例 {#examples} + +##### 実装からの抽象化 {#abstracting-from-the-implementation} + +内部構造の変更は、公開APIの変更を引き起こすべきではありません。 + +- **悪い例**: このコンポーネントをフィーチャー内で移動、または名前変更すると、すべての使用場所でインポートをリファクタリングする必要が生じる。 + + ```diff + - import { Form } from "features/auth-form/ui/form" + ``` + +- **良い例**: フィーチャーのインターフェースは内部構造を反映せず、外部の「ユーザー」はフィーチャー内のコンポーネントの移動や名前変更の影響を受けない。 + + ```diff + + import { AuthForm } from "features/auth-form" + ``` + +### 3. 統合性 {#3-integrability} + +公開APIは、**簡単で柔軟な統合を促進するべきです**。 + +- 公開APIは、アプリケーションの他の部分での使用が便利であり、特に名前衝突問題を解決する必要がある。 + +#### 例 {#examples} + +##### 名前の衝突 {#name-collision} + +- **悪い例**: 名前の衝突が発生してしまう。 + + ```ts title="features/auth-form/index.ts" + export { Form } from "./ui" + export * as model from "./model" + ``` + + ```ts title="features/post-form/index.ts" + export { Form } from "./ui" + export * as model from "./model" + ``` + + ```diff + - import { Form, model } from "features/auth-form" + - import { Form, model } from "features/post-form" + ``` + +- **良い例**: インターフェースレベルで名前の衝突が解決される。 + + ```ts title="features/auth-form/index.ts" + export { Form as AuthForm } from "./ui" + export * as authFormModel from "./model" + ``` + + ```ts title="features/post-form/index.ts" + export { Form as PostForm } from "./ui" + export * as postFormModel from "./model" + ``` + + ```diff + + import { AuthForm, authFormModel } from "features/auth-form" + + import { PostForm, postFormModel } from "features/post-form" + ``` + +##### 柔軟な使用 {#flexible-use} + +- **悪い例**: 書きにくく、読みづらく、「ユーザー」は不便を感じます。 + + ```diff + - import { storeActionUpdateUserDetails } from "features/auth-form" + - dispatch(storeActionUpdateUserDetails(...)) + ``` + +- **良い例**: 「ユーザー」は必要なものに対して反復的かつ柔軟にアクセスできます。 + + ```diff + + import { authFormModel } from "features/auth-form" + + dispatch(authFormModel.effects.updateUserDetails(...)) // redux + + authFormModel.updateUserDetailsFx(...) // effector + ``` + +##### 衝突の解決 {#resolution-of-collisions} + +名前の衝突は、実装レベルではなく公開APIのレベルで解決されるべきです。 + +- **悪い例**: 名前の衝突が実装レベルで解決される。 + + ```ts title="features/auth-form/index.ts" + export { AuthForm } from "./ui" + export { authFormActions, authFormReducer } from "model" + ``` + + ```ts title="features/post-form/index.ts" + export { PostForm } from "./ui" + export { postFormActions, postFormReducer } from "model" + ``` + +- **良い例**: 名前の衝突がインターフェースレベルで解決される。 + + ```ts title="features/auth-form/model.ts" + export { actions, reducer } + ``` + + ```ts title="features/auth-form/index.ts" + export { Form as AuthForm } from "./ui" + export * as authFormModel from "./model" + ``` + + ```ts title="features/post-form/model.ts" + export { actions, reducer } + ``` + + ```ts title="features/post-form/index.ts" + export { Form as PostForm } from "./ui" + export * as postFormModel from "./model" + ``` + +## 再エクスポートについて {#about-re-exports} + +JavaScriptでは、モジュールの公開APIは、モジュール内部のエンティティを`index`ファイルで再エクスポートすることによって作成されます。 + +```ts title="**/**/index.ts" +export { Form as AuthForm } from "./ui" +export * as authModel from "./model" +``` + +### 欠点 {#disadvantages} + +- ほとんどの人気のバンドラーでは、再エクスポートのために**コード分割の効果が低下してしまいます**。なぜなら、このアプローチでは[ツリーシェイキング](https://webpack.js.org/guides/tree-shaking/)が安全にモジュール全体しか削除することができないからです。 + > 例えば、ページモデルで`authModel`をインポートすると、たとえ使用されていなくても、`AuthForm`コンポーネントがそのページのチャンクに含まれてしまいます。 + +- 結果として、チャンクの初期化が高コストになり、ブラウザはその中のすべてのモジュールを処理する必要があります。 + +### 可能な解決策 {#possible-solutions} + +- `webpack`は、再エクスポートファイルを[**副作用なし**](https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free)としてマークすることを可能にしています。これにより、`webpack`はそのファイルを扱う際に攻撃的な最適化を使用できるようになります。 + +## 参照 {#see-also} + +- [**SOLID**原則][ext-solid] +- [**GRASP**パターン][ext-grasp] + +[ext-solid]: https://ja.wikipedia.org/wiki/SOLID +[ext-grasp]: https://ja.wikipedia.org/wiki/GRASP diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx new file mode 100644 index 0000000000..a3f29279a5 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx @@ -0,0 +1,57 @@ +--- +title: スライスとセグメント +sidebar_position: 2 +pagination_next: reference/public-api +--- + +# スライスとセグメント + +## スライス + +スライスは、Feature-Sliced Designの組織階層における第2のレベルです。その主な目的は、プロダクト、ビジネス、または単にアプリケーションに対する意味に基づいてコードをグループ化することです。 + +スライスの名前は標準化されておらず、アプリケーションのビジネス領域によって直接決定されます。例えば、フォトギャラリーには`photo`、`create-album`、`gallery-page`というスライスがあるかもしれません。SNSには、`post`、`add-user-to-friends`、`news-feed`のようなスライスが必要になるでしょう。 + +密接に関連するスライスは、同じフォルダーに構造的にグループ化できますが、他のスライスと同じ隔離ルールを遵守する必要があります。この場合、ディレクトリには、**複数のスライスによって共有されるコードは存在してはなりません**。 + +![「compose」(作成)、「like」(いいね)、「delete」(削除)の機能が「post」(投稿)フォルダーにグループ化されています。このフォルダーには「some-shared-code.ts」というファイルもあり、その名前は取り消し線が引かれており、そこに存在してはいけないことを示しています。](/img/graphic-nested-slices.svg) + +Shared層とApp層にはスライスが含まれていません。それは、Shared層がビジネスロジックを含むべきではないため、プロダクトに対して意味を持っていないからです。また、App層はアプリケーション全体に関係するコードのみを含むべきであるため、分割の必要がないからです。 + +### スライスの公開APIルール + +スライス内では、コードは自由に整理でき、スライスが質の高い公開APIを提供している限り、それに問題がありません。これが**スライスの公開APIルール**の本質です。 + +> _すべてのスライス(およびスライスを持たないレイヤーのセグメント)は、公開APIの定義を含む必要がある_ +> +> _スライス/セグメントの外部にあるモジュールは、スライス/セグメントの内部ファイル構造ではなく、公開APIのみを参照すべき_ + +公開APIの要件とその作成に関するベストプラクティスについては、[公開APIガイド][ref--public-api]を参照してください。 + +## セグメント + +セグメントは、組織階層の第3レベルおよび最終レベルであり、その目的は技術的な性質に基づいてコードをグループ化することです。 + +いくつかの標準化されたセグメント名があります。 +* `ui` - UIコンポーネント、データフォーマット関数 +* `model` - ビジネスロジックとデータストレージ、これらのデータを操作するための関数 +* `lib` - 補助的なインフラストラクチャコード +* `api` - 外部APIとの通信、バックエンドAPIメソッド + +他のセグメントも許可されていますが、必要に応じてのみ作成されるべきです。カスタムセグメントの最も一般的な場所は、スライスが意味を持たないApp層とShared層です。 + +### 例 + +| レイヤー | `ui` | `model` | `lib` | `api` | +| :----------- | :----------- | :----------- | :----------- | :----------- | +| Shared層 | UIライブラリ | 通常は使用されない | 複数の関連ファイルからのユーティリティモジュール。
個別のヘルパー関数が必要な場合は、[`lodash-es`][ext--lodash]などのユーティリティライブラリを検討してください。 | 認証やキャッシュなどの追加機能を持つシンプルななAPIクライアント。 | +| Entities層 | インタラクティブ要素のスロットを持つビジネスエンティティの骨組み | エンティティのインスタンスのデータストレージと、それらのデータを操作するための関数。
サーバーからのデータを保存するのに最適。[TanStack Query][ext--tanstack-query]や他の暗黙的なストレージメソッドを使用する場合、省略できる。 | データストレージに関連しないエンティティのインスタンスを操作するための関数 | Shared層からのAPIクライアントを使用してバックエンドとの通信を簡素化するAPIメソッド | +| Features層 | ユーザーが機能を使用できるためのインタラクティブ要素 | 必要に応じてビジネスロジックとインフラストラクチャデータストレージ(例:アプリケーションの現在のテーマ)。ユーザーに価値を提供するコードがここにある | `model`セグメントのビジネスロジックを簡潔に説明するためのインフラストラクチャコード | バックエンドで機能を表すAPIメソッド。
Entities層からのAPIメソッドを組み合わせることがある。 | +| Widgets層 | Entities層とFeatures層を自己完結型のUIブロックに構成する。
エラーバウンダリやローディング状態を含むこともできる。 | 必要に応じてインフラストラクチャデータストレージを含むことができる | ページ上でウィジェットブロックが機能するために必要な非ビジネスインタラクション(例:ジェスチャー)やその他のコード | 通常は使用されないが、ネストされたルーティングの文脈でデータローダーを含むことがある(例: [Remix][ext--remix]) | +| Pages層 | Entities層、Features層、Widgets層の構成。
エラーバウンダリやローディング状態を含むこともできる。 | 通常は使用されない | UXを提供するために必要な非ビジネスインタラクション(例:ジェスチャー)やその他のコード | SSR(サーバーサイドレンダリング)指向のフレームワーク用のデータローダー | + +[ref--public-api]: /docs/reference/public-api + +[ext--lodash]: https://www.npmjs.com/package/lodash-es +[ext--tanstack-query]: https://tanstack.com/query/latest +[ext--remix]: https://remix.run diff --git a/i18n/ja/docusaurus-theme-classic/footer.json b/i18n/ja/docusaurus-theme-classic/footer.json new file mode 100644 index 0000000000..3fe117791d --- /dev/null +++ b/i18n/ja/docusaurus-theme-classic/footer.json @@ -0,0 +1,66 @@ +{ + "link.title.Specs": { + "message": "仕様", + "description": "The title of the footer links column with title=Specs in the footer" + }, + "link.title.Community": { + "message": "コミュニティ", + "description": "The title of the footer links column with title=Community in the footer" + }, + "link.title.More": { + "message": "その他", + "description": "The title of the footer links column with title=More in the footer" + }, + "link.item.label.Documentation": { + "message": "ドキュメント", + "description": "The label of footer link with label=Документация linking to /docs" + }, + "link.item.label.Community": { + "message": "コミュニティ", + "description": "The label of the footer link with label=Community linking to /community" + }, + "link.item.label.Help": { + "message": "ヘルプ", + "description": "The label of the footer link with label=Help linking to /nav" + }, + "link.item.label.Discussions": { + "message": "ディスカッション", + "description": "The label of footer link with label=Обсуждения linking to https://github.com/feature-sliced/documentation/discussions" + }, + "link.item.label.License": { + "message": "ライセンス", + "description": "The label of footer link with label=License linking to LICENSE" + }, + "link.item.label.Contribution Guide (RU)": { + "message": "コントリビューションガイド (RU)", + "description": "The label of footer link with label=Contribution Guide (RU) linking to CONTRIBUTING.md" + }, + "link.item.label.Discord": { + "message": "Discord", + "description": "The label of footer link with label=Discord linking to https://discord.com/invite/S8MzWTUsmp" + }, + "link.item.label.Telegram": { + "message": "Telegram", + "description": "The label of footer link with label=Telegram linking to https://t.me/feature_sliced" + }, + "link.item.label.Twitter": { + "message": "X", + "description": "The label of footer link with label=X linking to https://x.com/feature_sliced" + }, + "link.item.label.Open Collective": { + "message": "Open Collective", + "description": "The label of footer link with label=Open Collective linking to https://opencollective.com/feature-sliced" + }, + "link.item.label.YouTube": { + "message": "YouTube", + "description": "The label of footer link with label=YouTube linking to https://www.youtube.com/c/FeatureSlicedDesign" + }, + "link.item.label.GitHub": { + "message": "GitHub", + "description": "The label of footer link with label=GitHub linking to https://github.com/feature-sliced" + }, + "copyright": { + "message": "Copyright © 2018-2024 Feature-Sliced Design", + "description": "The footer copyright" + } +} diff --git a/i18n/ja/docusaurus-theme-classic/navbar.json b/i18n/ja/docusaurus-theme-classic/navbar.json new file mode 100644 index 0000000000..344f9415ab --- /dev/null +++ b/i18n/ja/docusaurus-theme-classic/navbar.json @@ -0,0 +1,50 @@ +{ + "title": { + "message": "", + "description": "The title in the navbar" + }, + "item.label.🛠 Examples": { + "message": "🛠 実装例", + "description": "Navbar item with label Examples" + }, + "item.label.📖 Docs": { + "message": "📖 ドキュメント", + "description": "Navbar item with label Docs" + }, + "item.label.🔎 Intro": { + "message": "🔎 紹介", + "description": "Navbar item with label Intro" + }, + "item.label.🚀 Get Started": { + "message": "🚀 はじめに", + "description": "Navbar item with label Get Started" + }, + "item.label.🧩 Concepts": { + "message": "🧩 コンセプト", + "description": "Navbar item with label Concepts" + }, + "item.label.🎯 Guides": { + "message": "🎯 ガイド", + "description": "Navbar item with label Guides" + }, + "item.label.📚 Reference": { + "message": "📚 参考書", + "description": "Navbar item with label Reference" + }, + "item.label.🍰 About": { + "message": "🍰 FSD設計方法論について", + "description": "Navbar item with label About" + }, + "item.label.💫 Community": { + "message": "💫 コミュニティ", + "description": "Navbar item with label Community" + }, + "item.label.❔ Help": { + "message": "❔ ヘルプ", + "description": "Navbar item with label Help" + }, + "item.label.📝 Blog": { + "message": "📝 ブログ", + "description": "Navbar item with label Blog" + } +} diff --git a/package.json b/package.json index 76c6fe73c5..3765108237 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "start:en": "docusaurus start --locale en", "start:uz": "docusaurus start --locale uz", "start:kr": "docusaurus start --locale kr", + "start:ja": "docusaurus start --locale ja", "build": "docusaurus build", "swizzle": "docusaurus swizzle", "test": "pnpm run test:lint && pnpm run build", From 60c93463b7aff7672f35e15f58d4e2a3f13965e9 Mon Sep 17 00:00:00 2001 From: InJaEE <45154110+InJaEE@users.noreply.github.com> Date: Tue, 8 Oct 2024 03:23:06 +0900 Subject: [PATCH 06/29] feat: main, tutorial, and FAQ pages translated into Korean (#730) --- i18n/kr/code.json | 48 +- .../current/get-started/faq.md | 69 + .../current/get-started/tutorial.md | 2270 +++++++++++++++++ 3 files changed, 2363 insertions(+), 24 deletions(-) create mode 100644 i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md create mode 100644 i18n/kr/docusaurus-plugin-content-docs/current/get-started/tutorial.md diff --git a/i18n/kr/code.json b/i18n/kr/code.json index 64379880c6..1cbbc5d536 100644 --- a/i18n/kr/code.json +++ b/i18n/kr/code.json @@ -1,82 +1,82 @@ { "pages.home.features.title": { - "message": "Features", + "message": "특징", "description": "Features" }, "pages.home.features.logic.title": { - "message": "Explicit business logic", + "message": "명시적인 비즈니스 로직", "description": "Feature title" }, "pages.home.features.logic.description": { - "message": "Easily discoverable architecture thanks to domain scopes", + "message": "도메인 스코프 덕분에 찾고자 하는 로직을 쉽게 발견할 수 있는 아키텍처입니다.", "description": "Feature description" }, "pages.home.features.adaptability.title": { - "message": "Adaptability", + "message": "유연성", "description": "Feature title" }, "pages.home.features.adaptability.description": { - "message": "Architecture components can be flexibly replaced and added for new requirements", + "message": "아키텍처 구성 요소를 새로운 요구사항에 맞춰 유연하게 교체하고 추가할 수 있습니다.", "description": "Feature description" }, "pages.home.features.debt.title": { - "message": "Tech debt & Refactoring", + "message": "기술 부채 및 리팩토링", "description": "Feature title" }, "pages.home.features.debt.description": { - "message": "Each module can be independently modified / rewritten without side effects", + "message": "각 모듈을 부작용 없이 독립적으로 수정, 재작성할 수 있습니다.", "description": "Feature description" }, "pages.home.features.shared.title": { - "message": "Explicit code reuse", + "message": "명시적 코드 재사용", "description": "Feature title" }, "pages.home.features.shared.description": { - "message": "A balance is maintained between DRY and local customization", + "message": "DRY 원칙과 로컬 커스터마이징 사이에 균형을 유지합니다.", "description": "Feature description" }, "pages.home.concepts.title": { - "message": "Concepts", + "message": "개념", "description": "Concepts" }, "pages.home.concepts.public.title": { - "message": "Public API", + "message": "공용 API", "description": "Concept title" }, "pages.home.concepts.public.description": { - "message": "Each module must have a declaration of its public API at the top level", + "message": "각 모듈에는 최상위 레벨에 공용 API 선언이 있어야 합니다.", "description": "Concept description" }, "pages.home.concepts.isolation.title": { - "message": "Isolation", + "message": "격리", "description": "Concept title" }, "pages.home.concepts.isolation.description": { - "message": "The module should not depend directly on other modules of the same layer or overlying layers", + "message": "같은 레이어 또는 상위 레이어의 모듈에 직접 의존하지 않아야 합니다.", "description": "Concept description" }, "pages.home.concepts.needs.title": { - "message": "Needs Driven", + "message": "요구사항 중심", "description": "Concept title" }, "pages.home.concepts.needs.description": { - "message": "Orientation to business and user needs", + "message": "비즈니스 및 사용자 요구사항을 중심으로 합니다.", "description": "Concept description" }, "pages.home.scheme.title": { - "message": "Scheme", + "message": "구조", "description": "Scheme" }, "pages.home.companies.using": { - "message": "Companies using FSD", + "message": "FSD를 사용하는 기업", "description": "Companies using FSD" }, "pages.home.companies.add_me": { - "message": "FSD is used in your company?", + "message": "FSD를 사용하는 기업이신가요?", "description": "FSD is used in your company?" }, "pages.home.companies.tell_us": { - "message": "Tell us", + "message": "알려주세요", "description": "Tell us" }, "pages.examples.title": { @@ -192,19 +192,19 @@ "description": "The placeholder for rating stars input" }, "features.hero.tagline": { - "message": "Architectural methodology for frontend projects", + "message": "프론트엔드 프로젝트를 위한 아키텍처 방법론", "description": "Architectural methodology for frontend projects" }, "features.hero.get_started": { - "message": "Get Started", + "message": "시작하기", "description": "Get Started" }, "features.hero.examples": { - "message": "Examples", + "message": "예제", "description": "Examples" }, "features.hero.previous": { - "message": "Previous version", + "message": "이전 버전", "description": "Previous version" }, "shared.wip.title": { diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md new file mode 100644 index 0000000000..c244282277 --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md @@ -0,0 +1,69 @@ +--- +sidebar_position: 20 +pagination_next: guides/index +--- + +# FAQ + +:::info + +여러분은 [Telegram chat][telegram], [Discord community][discord] 그리고 [GitHub Discussions][github-discussions]에서 질문을 할 수 있습니다. + +::: + +### toolkit이나 linter가 있나요? + +공식 ESLint 설정인 [@feature-sliced/eslint-config][eslint-config-official]와 커뮤니티 멤버인 Aleksandr Belous가 만든 ESLint 플러그인 [@conarti/eslint-plugin-feature-sliced][eslint-plugin-conarti]가 있습니다. 이 프로젝트들에 기여하거나 여러분만의 프로젝트를 시작해보세요! + +### Where to store the layout/template of pages? + +순수한 마크업 레이아웃이 필요하다면 `shared/ui`에 보관할 수 있습니다. 상위 계층을 사용해야 한다면 몇 가지 옵션이 있습니다. + +- 레이아웃이 필요 없을 수도 있습니다. 레이아웃이 몇 줄밖에 안 된다면, 추상화하려고 하기보다는 각 페이지에서 코드를 중복하는 것이 합리적일 수 있습니다. +- 레이아웃이 필요하다면, 별도의 위젯이나 페이지로 만들고 App의 라우터 설정에서 조합할 수 있습니다. 중첩 라우팅도 다른 옵션입니다. + +### feature와 entity의 차이점이 무엇인가요? + +*entity*는 앱이 다루는 실제 개념입니다. *feature*는 앱 사용자에게 실제 가치를 제공하는 상호작용, 즉 사람들이 entity로 하고 싶어하는 것입니다. + +더 자세한 정보와 예시는 [slices][reference-entities] 참조 페이지를 확인하세요. + +### pages/features/entities를 서로 포함시킬 수 있나요? + +네, 하지만 이런 포함은 상위 계층에서 이루어져야 합니다. 예를 들어, 위젯 내부에서 여러 기능을 가져와서 하나의 기능을 다른 기능의 props/children으로 삽입할 수 있습니다. + +한 기능을 다른 기능에서 가져올 수는 없습니다. 이는 [**계층에 대한 가져오기 규칙**][import-rule-layers]에 의해 금지됩니다. + +### 아토믹 디자인은 어떤가요? + +현재 버전의 방법론은 Feature-Sliced Design과 함께 아토믹 디자인을 사용하는 것을 요구하지도, 금지하지도 않습니다. + +예를 들어, 아토믹 디자인은 모듈의 `ui` 세그먼트에 [잘 적용될 수 있습니다](https://t.me/feature_sliced/1653). + +### FSD에 대한 유용한 리소스/기사 등이 있나요? + +네! https://github.com/feature-sliced/awesome 를 참조하세요. + +### Feature-Sliced Design이 왜 필요한가요? + +프로젝트를 주요 가치 창출 구성 요소 측면에서 빠르게 개요를 파악하는 데 도움이 됩니다. 표준화된 아키텍처는 온보딩 속도를 높이고 코드 구조에 대한 논쟁을 해결합니다. FSD가 만들어진 이유에 대해 더 자세히 알아보려면 [동기][motivation] 페이지를 참조하세요. + +### 초보 개발자에게 아키텍처/방법론이 필요한가요? + +그렇다고 볼 수 있습니다. + +*보통 한 사람이 프로젝트를 설계하고 개발할 때는 모든 것이 순조롭게 진행됩니다. 하지만 개발에 중단이 있거나 새로운 개발자가 팀에 합류하면 문제가 발생합니다* + + +### 인증 컨텍스트는 어떻게 다루나요? + +[여기](/docs/guides/examples/auth)에서 답변했습니다. + +[import-rule-layers]: /docs/reference/layers#import-rule-on-layers +[reference-entities]: /docs/reference/layers#entities +[eslint-config-official]: https://github.com/feature-sliced/eslint-config +[eslint-plugin-conarti]: https://github.com/conarti/eslint-plugin-feature-sliced +[motivation]: /docs/about/motivation +[telegram]: https://t.me/feature_sliced +[discord]: https://discord.gg/S8MzWTUsmp +[github-discussions]: https://github.com/feature-sliced/documentation/discussions diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/get-started/tutorial.md b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/tutorial.md new file mode 100644 index 0000000000..ba8c07b495 --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -0,0 +1,2270 @@ +--- +sidebar_position: 2 +--- +# 튜토리얼 + +## Part 1. 설계 + +이 튜토리얼에서는 Real World App이라고도 알려진 Conduit를 살펴보겠습니다. Conduit는 기본적인 [Medium](https://medium.com/) 클론입니다 - 글을 읽고 쓸 수 있으며 다른 사람의 글에 댓글을 달 수 있습니다. + +![Conduit home page](/img/tutorial/realworld-feed-anonymous.jpg) + +이 애플리케이션은 매우 작은 애플리케이션이므로 과도한 분해를 피하고 간단하게 유지할 것입니다. 전체 애플리케이션이 세 개의 레이어인 **App**, **Pages**, 그리고 **Shared**에 맞춰 들어갈 것입니다. 그렇지 않다면 우리는 계속해서 추가적인 레이어를 도입할 것입니다. 준비되셨나요? + +### 먼저 페이지를 나열해 봅시다. + +위의 스크린샷을 보면 최소한 다음과 같은 페이지들이 있다고 가정할 수 있습니다: + +- 홈 (글 피드) +- 로그인 및 회원가입 +- 글 읽기 +- 글 편집기 +- 사용자 프로필 보기 +- 사용자 프로필 편집 (사용자 설정) + +이 페이지들 각각은 Pages *레이어*의 독립된 *슬라이스*가 될 것입니다. 개요에서 언급했듯이 슬라이스는 단순히 레이어 내의 폴더이고, 레이어는 `pages`와 같은 미리 정의된 이름을 가진 폴더일 뿐입니다. + +따라서 우리의 Pages 폴더는 다음과 같이 보일 것입니다. + +``` +📂 pages/ + 📁 feed/ + 📁 sign-in/ + 📁 article-read/ + 📁 article-edit/ + 📁 profile/ + 📁 settings/ +``` + +Feature-Sliced Design이 규제되지 않은 코드 구조와 다른 주요 차이점은 페이지들이 서로를 참조할 수 없다는 것입니다. 즉, 한 페이지가 다른 페이지의 코드를 가져올 수 없습니다. 이는 **레이어의 import 규칙** 때문입니다. + +*슬라이스의 모듈은 엄격히 아래에 있는 레이어에 위치한 다른 슬라이스만 가져올 수 있습니다.* + +이 경우 페이지는 슬라이스이므로, 이 페이지 내의 모듈(파일)은 같은 레이어인 Pages가 아닌 아래 레이어의 코드만 참조할 수 있습니다. + +### 피드 자세히 보기 + +
+ ![Anonymous user’s perspective](/img/tutorial/realworld-feed-anonymous.jpg) +
+ _익명 사용자의 관점_ +
+
+ +
+ ![Authenticated user’s perspective](/img/tutorial/realworld-feed-authenticated.jpg) +
+ _인증된 사용자의 관점_ +
+
+ +피드 페이지에는 세 가지 동적 영역이 있습니다. + +1. 로그인 여부를 나타내는 로그인 링크 +2. 피드에서 필터링을 트리거하는 태그 목록 +3. 좋아요 버튼이 있는 하나/두 개의 글 피드 + +로그인 링크는 모든 페이지에 공통적인 헤더의 일부이므로 나중에 따로 다루겠습니다. + +#### 태그 목록 + +태그 목록을 만들기 위해서는 사용 가능한 태그를 가져오고, 각 태그를 칩으로 렌더링하고, 선택된 태그를 클라이언트 측 저장소에 저장해야 합니다. 이러한 작업들은 각각 "API 상호작용", "사용자 인터페이스", "저장소" 카테고리에 속합니다. Feature-Sliced Design에서는 코드를 *세그먼트*를 사용하여 목적별로 분리합니다. 세그먼트는 슬라이스 내의 폴더이며, 목적을 설명하는 임의의 이름을 가질 수 있지만, 일부 목적은 너무 일반적이어서 특정 세그먼트 이름에 대한 규칙이 있습니다. + + +- 📂 `api/` 백엔드 상호작용 +- 📂 `ui/` 렌더링과 외관을 다루는 코드 +- 📂 `model/` 저장소와 비즈니스 로직 +- 📂 `config/` 기능 플래그, 환경 변수 및 기타 구성 형식 + +태그를 가져오는 코드는 `api`에, 태그 컴포넌트는 `ui`에, 저장소 상호작용은 `model`에 배치할 것입니다. + +#### 글 + +같은 그룹화 원칙을 사용하여 글 피드를 같은 세 개의 세그먼트로 분해할 수 있습니다. + +- 📂 `api/`: 좋아요 수가 포함된 페이지네이션된 글 가져오기 +- 📂 `ui/`: + - 태그가 선택된 경우 추가 탭을 렌더링할 수 있는 탭 목록 + - 개별 글 + - 기능적 페이지네이션 +- 📂 `model/`: 현재 로드된 글과 현재 페이지의 클라이언트 측 저장소 (필요한 경우) + +### 일반적인 코드 재사용 + +대부분의 페이지는 의도가 매우 다르지만, 앱 전체에 걸쳐 일부 요소는 동일하게 유지됩니다. 예를 들어, 디자인 언어를 준수하는 UI 키트나 모든 것이 동일한 인증 방식으로 REST API를 통해 수행되는 백엔드의 규칙 등이 있습니다. 슬라이스는 격리되도록 설계되었기 때문에, 코드 재사용은 더 낮은 계층인 **Shared**에 의해 촉진됩니다. + + +Shared는 슬라이스가 아닌 세그먼트를 포함한다는 점에서 다른 계층과 다릅니다. 이런 면에서 Shared 계층은 계층과 슬라이스의 하이브리드로 생각할 수 있습니다. + +일반적으로 Shared의 코드는 미리 계획되지 않고 개발 중에 추출됩니다. 실제로 어떤 코드 부분이 공유되는지는 개발 중에만 명확해지기 때문입니다. 그러나 어떤 종류의 코드가 자연스럽게 Shared에 속하는지 머릿속에 메모해 두는 것은 여전히 도움이 됩니다. + + +- 📂 `ui/` — UI 키트, 비즈니스 로직이 없는 순수한 UI. 예: 버튼, 모달 대화 상자, 폼 입력. +- 📂 `api/` — 요청 생성 기본 요소(예: 웹의 `fetch()`)에 대한 편의 래퍼 및 선택적으로 백엔드 사양에 따라 특정 요청을 트리거하는 함수. +- 📂 `config/` — 환경 변수 파싱 +- 📂 `i18n/` — 언어 지원에 대한 구성 +- 📂 `router/` — 라우팅 기본 요소 및 라우트 상수 + +이는 Shared의 세그먼트 이름의 몇 가지 예시일 뿐이며, 이 중 일부를 생략하거나 자신만의 세그먼트를 만들 수 있습니다. 새로운 세그먼트를 만들 때 기억해야 할 유일한 중요한 점은 세그먼트 이름이 **본질(무엇인지)이 아닌 목적(왜)을 설명해야 한다**는 것입니다. "components", "hooks", "modals"과 같은 이름은 이 파일들이 무엇인지는 설명하지만 내부 코드를 탐색하는 데 도움이 되지 않기 때문에 사용해서는 안 됩니다. 이는 팀원들이 이러한 폴더의 모든 파일을 파헤쳐야 하며, 관련 없는 코드를 가까이 유지하게 되어 리팩토링의 영향을 받는 코드 영역이 넓어지고 결과적으로 코드 리뷰와 테스트를 더 어렵게 만듭니다. + +### 엄격한 공개 API 정의 + +Feature-Sliced Design의 맥락에서 *공개 API*라는 용어는 슬라이스나 세그먼트가 프로젝트의 다른 모듈에서 가져올 수 있는 것을 선언하는 것을 의미합니다. 예를 들어, JavaScript에서는 슬라이스의 다른 파일에서 객체를 다시 내보내는 `index.js` 파일일 수 있습니다. 이를 통해 외부 세계와의 계약(즉, 공개 API)이 동일하게 유지되는 한 슬라이스 내부의 코드를 자유롭게 리팩토링할 수 있습니다. + +슬라이스가 없는 Shared 계층의 경우, Shared의 모든 것에 대한 단일 인덱스를 정의하는 것과 반대로 각 세그먼트에 대해 별도의 공개 API를 정의하는 것이 일반적으로 더 편리합니다. 이렇게 하면 Shared에서의 가져오기가 자연스럽게 의도별로 구성됩니다. 슬라이스가 있는 다른 계층의 경우 반대가 사실입니다 — 일반적으로 슬라이스당 하나의 인덱스를 정의하고 슬라이스가 외부 세계에 알려지지 않은 자체 세그먼트 세트를 결정하도록 하는 것이 더 실용적입니다. 다른 계층은 일반적으로 내보내기가 훨씬 적기 때문입니다. + +우리의 슬라이스/세그먼트는 서로에게 다음과 같이 나타날 것입니다. + +``` +📂 pages/ + 📂 feed/ + 📄 index + 📂 sign-in/ + 📄 index + 📂 article-read/ + 📄 index + 📁 … +📂 shared/ + 📂 ui/ + 📄 index + 📂 api/ + 📄 index + 📁 … +``` + +`pages/feed`나 `shared/ui`와 같은 폴더 내부의 내용은 해당 폴더에만 알려져 있으며, 다른 파일은 이러한 폴더의 내부 구조에 의존해서는 안 됩니다. + + +### UI의 큰 재사용 블록 + +앞서 모든 페이지에 나타나는 헤더를 다시 살펴보기로 했습니다. 모든 페이지에서 처음부터 다시 만드는 것은 비실용적이므로 재사용하고 싶을 것입니다. 우리는 이미 코드 재사용을 용이하게 하는 Shared를 가지고 있지만, Shared에 큰 UI 블록을 넣는 데는 주의할 점이 있습니다 — Shared 계층은 위의 계층에 대해 알지 못해야 합니다. + +Shared와 Pages 사이에는 Entities, Features, Widgets의 세 가지 다른 계층이 있습니다. 일부 프로젝트는 이러한 계층에 큰 재사용 가능한 블록에 필요한 것이 있을 수 있으며, 이는 해당 재사용 가능한 블록을 Shared에 넣을 수 없다는 것을 의미합니다. 그렇지 않으면 상위 계층에서 가져오게 되어 금지됩니다. 이것이 Widgets 계층이 필요한 이유입니다. Widgets는 Shared, Entities, Features 위에 위치하므로 이들 모두를 사용할 수 있습니다. + +우리의 경우, 헤더는 매우 간단합니다 — 정적 로고와 최상위 탐색입니다. 탐색은 사용자가 현재 로그인했는지 여부를 확인하기 위해 API에 요청을 해야 하지만, 이는 `api` 세그먼트에서 간단한 가져오기로 처리할 수 있습니다. 따라서 우리는 헤더를 Shared에 유지할 것입니다. + +### 폼이 있는 페이지 자세히 보기 + +읽기가 아닌 편집을 위한 페이지도 살펴보겠습니다. + +![Conduit post editor](/img/tutorial/realworld-editor-authenticated.jpg) + +간단해 보이지만, 폼 유효성 검사, 오류 상태, 데이터 지속성 등 아직 탐구하지 않은 애플리케이션 개발의 여러 측면을 포함하고 있습니다. + +이 페이지를 만들려면 Shared에서 일부 입력과 버튼을 가져와 이 페이지의 `ui` 세그먼트에서 폼을 구성할 것입니다. 그런 다음 `api` 세그먼트에서 백엔드에 글을 생성하는 변경 요청을 정의할 것입니다. + +요청을 보내기 전에 유효성을 검사하려면 유효성 검사 스키마가 필요하며, 이를 위한 좋은 위치는 데이터 모델이기 때문에 `model` 세그먼트입니다. 여기서 오류 메시지를 생성하고 `ui` 세그먼트의 다른 컴포넌트를 사용하여 표시할 것입니다. + +사용자 경험을 개선하기 위해 우발적인 데이터 손실을 방지하기 위해 입력을 지속시킬 수도 있습니다. 이것도 `model` 세그먼트의 작업입니다. + +### 요약 + +우리는 여러 페이지를 검토하고 애플리케이션의 예비 구조를 개략적으로 설명했습니다. + +1. Shared layer + 1. `ui`는 재사용 가능한 UI 키트를 포함할 것입니다. + 2. `api`는 백엔드와의 기본적인 상호작용을 포함할 것입니다. + 3. 나머지는 필요에 따라 정리될 것입니다. +2. Pages layer — 각 페이지는 별도의 슬라이스입니다. + 1. `ui`는 페이지 자체와 모든 부분을 포함할 것입니다. + 2. `api`는 `shared/api`를 사용하여 더 특화된 데이터 가져오기를 포함할 것입니다. + 3. `model`은 표시할 데이터의 클라이언트 측 저장소를 포함할 수 있습니다. + +이제 코드 작성을 시작해 봅시다! + +## Part 2. 코드 작성 + +이제 설계를 완료했으니 실제로 코드를 작성해 봅시다. React와 [Remix](https://remix.run)를 사용할 것입니다. + +이 프로젝트를 위한 템플릿이 준비되어 있습니다. GitHub에서 클론하여 시작하세요. [https://github.com/feature-sliced/tutorial-conduit/tree/clean](https://github.com/feature-sliced/tutorial-conduit/tree/clean). + +`npm install`로 의존성을 설치하고 `npm run dev`로 개발 서버를 시작하세요. [http://localhost:3000](http://localhost:3000)을 열면 빈 앱이 보일 것입니다. + + +### 페이지 레이아웃 + +모든 페이지에 대한 빈 컴포넌트를 만드는 것부터 시작하겠습니다. 프로젝트에서 다음 명령을 실행하세요. + +```bash +npx fsd pages feed sign-in article-read article-edit profile settings --segments ui +``` + +이렇게 하면 `pages/feed/ui/`와 같은 폴더와 모든 페이지에 대한 인덱스 파일인 `pages/feed/index.ts`가 생성됩니다. + +### 피드 페이지 연결 + +애플리케이션의 루트 경로를 피드 페이지에 연결해 봅시다. `pages/feed/ui`에 `FeedPage.tsx` 컴포넌트를 만들고 다음 내용을 넣으세요: + +```tsx title="pages/feed/ui/FeedPage.tsx" +export function FeedPage() { + return ( +
+
+
+

conduit

+

A place to share your knowledge.

+
+
+
+ ); +} +``` + +그런 다음 피드 페이지의 공개 API인 `pages/feed/index.ts` 파일에서 이 컴포넌트를 다시 내보내세요. + +```ts title="pages/feed/index.ts" +export { FeedPage } from "./ui/FeedPage"; +``` + +이제 루트 경로에 연결합니다. Remix에서 라우팅은 파일 기반이며, 라우트 파일은 `app/routes` 폴더에 있어 Feature-Sliced Design과 잘 맞습니다. + +`app/routes/_index.tsx`에서 `FeedPage` 컴포넌트를 사용하세요. + +```tsx title="app/routes/_index.tsx" +import type { MetaFunction } from "@remix-run/node"; +import { FeedPage } from "pages/feed"; + +export const meta: MetaFunction = () => { + return [{ title: "Conduit" }]; +}; + +export default FeedPage; +``` + +그런 다음 개발 서버를 실행하고 애플리케이션을 열면 Conduit 배너가 보일 것입니다! + +![The banner of Conduit](/img/tutorial/conduit-banner.jpg) + +### API 클라이언트 + +RealWorld 백엔드와 통신하기 위해 Shared에 편리한 API 클라이언트를 만들어 봅시다. 클라이언트를 위한 `api`와 백엔드 기본 URL과 같은 변수를 위한 `config`, 두 개의 세그먼트를 만드세요. + + +```bash +npx fsd shared --segments api config +``` + +그런 다음 `shared/config/backend.ts`를 만드세요. + +```tsx title="shared/config/backend.ts" +export const backendBaseUrl = "https://api.realworld.io/api"; +``` + +```tsx title="shared/config/index.ts" +export { backendBaseUrl } from "./backend"; +``` + +RealWorld 프로젝트는 편리하게 [OpenAPI 사양](https://github.com/gothinkster/realworld/blob/main/api/openapi.yml)을 제공하므로, 클라이언트를 위한 자동 생성 타입을 활용할 수 있습니다. 추가 타입 생성기가 포함된 [`openapi-fetch` 패키지](https://openapi-ts.pages.dev/openapi-fetch/)를 사용할 것입니다. + +다음 명령을 실행하여 최신 API 타입을 생성하세요. + +```bash +npm run generate-api-types +``` + +이렇게 하면 `shared/api/v1.d.ts` 파일이 생성됩니다. 이 파일을 사용하여 `shared/api/client.ts`에 타입이 지정된 API 클라이언트를 만들 것입니다. + +```tsx title="shared/api/client.ts" +import createClient from "openapi-fetch"; + +import { backendBaseUrl } from "shared/config"; +import type { paths } from "./v1"; + +export const { GET, POST, PUT, DELETE } = createClient({ baseUrl: backendBaseUrl }); +``` + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; +``` + +### 피드의 실제 데이터 + +이제 백엔드에서 가져온 글을 피드에 추가할 수 있습니다. 글 미리보기 컴포넌트를 구현하는 것부터 시작하겠습니다. + +다음 내용으로 `pages/feed/ui/ArticlePreview.tsx`를 만드세요. + +```tsx title="pages/feed/ui/ArticlePreview.tsx" +export function ArticlePreview({ article }) { /* TODO */ } +``` + +TypeScript를 사용하고 있으므로 글 객체에 타입을 지정하면 좋을 것 같습니다. 생성된 `v1.d.ts`를 살펴보면 글 객체가 `components["schemas"]["Article"]`을 통해 사용 가능한 것을 볼 수 있습니다. 그럼 Shared에 데이터 모델이 있는 파일을 만들고 모델을 내보내겠습니다. + +```tsx title="shared/api/models.ts" +import type { components } from "./v1"; + +export type Article = components["schemas"]["Article"]; +``` + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; + +export type { Article } from "./models"; +``` + +이제 글 미리보기 컴포넌트로 돌아가 데이터로 마크업을 채울 수 있습니다. 컴포넌트를 다음 내용으로 업데이트하세요. + +```tsx title="pages/feed/ui/ArticlePreview.tsx" +import { Link } from "@remix-run/react"; +import type { Article } from "shared/api"; + +interface ArticlePreviewProps { + article: Article; +} + +export function ArticlePreview({ article }: ArticlePreviewProps) { + return ( +
+
+ + + +
+ + {article.author.username} + + + {new Date(article.createdAt).toLocaleDateString(undefined, { + dateStyle: "long", + })} + +
+ +
+ +

{article.title}

+

{article.description}

+ Read more... +
    + {article.tagList.map((tag) => ( +
  • + {tag} +
  • + ))} +
+ +
+ ); +} +``` + +좋아요 버튼은 지금은 아무 작업도 하지 않습니다. 글 읽기 페이지를 만들고 좋아요 기능을 구현할 때 수정하겠습니다. + +이제 글을 가져와서 이러한 카드를 여러 개 렌더링할 수 있습니다. Remix에서 데이터 가져오기는 *로더* — 페이지가 필요로 하는 것을 정확히 가져오는 서버 측 함수 — 를 통해 수행됩니다. 로더는 페이지를 대신하여 API와 상호 작용하므로 페이지의 `api` 세그먼트에 넣을 것입니다: + +```tsx title="pages/feed/api/loader.ts" +import { json } from "@remix-run/node"; + +import { GET } from "shared/api"; + +export const loader = async () => { + const { data: articles, error, response } = await GET("/articles"); + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return json({ articles }); +}; +``` + +페이지에 연결하려면 라우트 파일에서 `loader`라는 이름으로 내보내야 합니다. + +```tsx title="pages/feed/index.ts" +export { FeedPage } from "./ui/FeedPage"; +export { loader } from "./api/loader"; +``` + +```tsx title="app/routes/_index.tsx" +import type { MetaFunction } from "@remix-run/node"; +import { FeedPage } from "pages/feed"; + +export { loader } from "pages/feed"; + +export const meta: MetaFunction = () => { + return [{ title: "Conduit" }]; +}; + +export default FeedPage; +``` + +마지막 단계는 피드에 이러한 카드를 렌더링하는 것입니다. `FeedPage`를 다음 코드로 업데이트하세요. + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; + +export function FeedPage() { + const { articles } = useLoaderData(); + + return ( +
+
+
+

conduit

+

A place to share your knowledge.

+
+
+ +
+
+
+ {articles.articles.map((article) => ( + + ))} +
+
+
+
+ ); +} +``` + +### 태그로 필터링 + +태그와 관련해서는 백엔드에서 태그를 가져오고 현재 선택된 태그를 저장해야 합니다. 가져오기 방법은 이미 알고 있습니다 — 로더에서 또 다른 요청을 하면 됩니다. `remix-utils` 패키지에서 `promiseHash`라는 편리한 함수를 사용할 것입니다. 이 패키지는 이미 설치되어 있습니다. + +로더 파일인 `pages/feed/api/loader.ts`를 다음 코드로 업데이트하세요. + +```tsx title="pages/feed/api/loader.ts" +import { json } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async () => { + return json( + await promiseHash({ + articles: throwAnyErrors(GET("/articles")), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + + +오류 처리를 일반 함수 `throwAnyErrors`로 추출했다는 점에 주목하세요. 꽤 유용해 보이므로 나중에 재사용할 수 있을 것 같습니다. 지금은 그냥 주목해 두겠습니다. + +이제 태그 목록으로 넘어갑시다. 이는 상호작용이 가능해야 합니다 — 태그를 클릭하면 해당 태그가 선택되어야 합니다. Remix 규칙에 따라 URL 검색 매개변수를 선택된 태그의 저장소로 사용할 것입니다. 브라우저가 저장을 처리하게 하고 우리는 더 중요한 일에 집중하겠습니다. + +`pages/feed/ui/FeedPage.tsx`를 다음 코드로 업데이트하세요. + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { Form, useLoaderData } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import type { loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; + +export function FeedPage() { + const { articles, tags } = useLoaderData(); + + return ( +
+
+
+

conduit

+

A place to share your knowledge.

+
+
+ +
+
+
+ {articles.articles.map((article) => ( + + ))} +
+ +
+
+

Popular Tags

+ +
+ +
+ {tags.tags.map((tag) => ( + + ))} +
+ +
+
+
+
+
+ ); +} +``` + +그런 다음 로더에서 `tag` 검색 매개변수를 사용해야 합니다. `pages/feed/api/loader.ts`의 `loader` 함수를 다음과 같이 변경하세요. + +```tsx title="pages/feed/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const url = new URL(request.url); + const selectedTag = url.searchParams.get("tag") ?? undefined; + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles", { params: { query: { tag: selectedTag } } }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + +이게 전부입니다. `model` 세그먼트가 필요하지 않습니다. Remix는 꽤 깔끔하죠. + +### 페이지네이션 + +비슷한 방식으로 페이지네이션을 구현할 수 있습니다. 직접 시도해 보거나 아래 코드를 복사하세요. 어차피 당신을 판단할 사람은 없습니다. + +```tsx title="pages/feed/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +/** Amount of articles on one page. */ +export const LIMIT = 20; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const url = new URL(request.url); + const selectedTag = url.searchParams.get("tag") ?? undefined; + const page = parseInt(url.searchParams.get("page") ?? "", 10); + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles", { + params: { + query: { + tag: selectedTag, + limit: LIMIT, + offset: !Number.isNaN(page) ? page * LIMIT : undefined, + }, + }, + }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { Form, useLoaderData, useSearchParams } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import { LIMIT, type loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; + +export function FeedPage() { + const [searchParams] = useSearchParams(); + const { articles, tags } = useLoaderData(); + const pageAmount = Math.ceil(articles.articlesCount / LIMIT); + const currentPage = parseInt(searchParams.get("page") ?? "1", 10); + + return ( +
+
+
+

conduit

+

A place to share your knowledge.

+
+
+ +
+
+
+ {articles.articles.map((article) => ( + + ))} + +
+ +
    + {Array(pageAmount) + .fill(null) + .map((_, index) => + index + 1 === currentPage ? ( +
  • + {index + 1} +
  • + ) : ( +
  • + +
  • + ), + )} +
+ +
+ +
+
+

Popular Tags

+ +
+ +
+ {tags.tags.map((tag) => ( + + ))} +
+ +
+
+
+
+
+ ); +} +``` + +이것으로 완료되었습니다. 탭 목록도 비슷하게 구현할 수 있지만, 인증을 구현할 때까지 잠시 보류하겠습니다. 그런데 말이 나왔으니! + +### 인증 + +인증에는 두 개의 페이지가 관련됩니다 - 로그인과 회원가입입니다. 이들은 대부분 동일하므로 필요한 경우 코드를 재사용할 수 있도록 `sign-in`이라는 동일한 슬라이스에 유지하는 것이 합리적입니다. + +`pages/sign-in`의 `ui` 세그먼트에 다음 내용으로 `RegisterPage.tsx`를 만드세요. + +```tsx title="pages/sign-in/ui/RegisterPage.tsx" +import { Form, Link, useActionData } from "@remix-run/react"; + +import type { register } from "../api/register"; + +export function RegisterPage() { + const registerData = useActionData(); + + return ( +
+
+
+
+

Sign up

+

+ Have an account? +

+ + {registerData?.error && ( +
    + {registerData.error.errors.body.map((error) => ( +
  • {error}
  • + ))} +
+ )} + +
+
+ +
+
+ +
+
+ +
+ +
+
+
+
+
+ ); +} +``` + +이제 고쳐야 할 깨진 import가 있습니다. 새로운 세그먼트가 필요하므로 다음과 같이 만드세요. + +```bash +npx fsd pages sign-in -s api +``` + +그러나 등록의 백엔드 부분을 구현하기 전에 Remix가 세션을 처리할 수 있도록 일부 인프라 코드가 필요합니다. 다른 페이지에서도 필요할 수 있으므로 이는 Shared로 갑니다. + +다음 코드를 `shared/api/auth.server.ts`에 넣으세요. 이는 Remix에 매우 특화된 것이므로 너무 걱정하지 마세요. 그냥 복사-붙여넣기 하세요. + +```tsx title="shared/api/auth.server.ts" +import { createCookieSessionStorage, redirect } from "@remix-run/node"; +import invariant from "tiny-invariant"; + +import type { User } from "./models"; + +invariant( + process.env.SESSION_SECRET, + "SESSION_SECRET must be set for authentication to work", +); + +const sessionStorage = createCookieSessionStorage<{ + user: User; +}>({ + cookie: { + name: "__session", + httpOnly: true, + path: "/", + sameSite: "lax", + secrets: [process.env.SESSION_SECRET], + secure: process.env.NODE_ENV === "production", + }, +}); + +export async function createUserSession({ + request, + user, + redirectTo, +}: { + request: Request; + user: User; + redirectTo: string; +}) { + const cookie = request.headers.get("Cookie"); + const session = await sessionStorage.getSession(cookie); + + session.set("user", user); + + return redirect(redirectTo, { + headers: { + "Set-Cookie": await sessionStorage.commitSession(session, { + maxAge: 60 * 60 * 24 * 7, // 7 days + }), + }, + }); +} + +export async function getUserFromSession(request: Request) { + const cookie = request.headers.get("Cookie"); + const session = await sessionStorage.getSession(cookie); + + return session.get("user") ?? null; +} + +export async function requireUser(request: Request) { + const user = await getUserFromSession(request); + + if (user === null) { + throw redirect("/login"); + } + + return user; +} +``` + +그리고 바로 옆에 있는 `models.ts` 파일에서 `User` 모델도 내보내세요. + +```tsx title="shared/api/models.ts" +import type { components } from "./v1"; + +export type Article = components["schemas"]["Article"]; +export type User = components["schemas"]["User"]; +``` + +이 코드가 작동하려면 `SESSION_SECRET` 환경 변수를 설정해야 합니다. 프로젝트 루트에 `.env` 파일을 만들고 `SESSION_SECRET=`을 작성한 다음 키보드에서 무작위로 키를 눌러 긴 무작위 문자열을 만드세요. 다음과 같은 결과가 나와야 합니다. + + +```bash title=".env" +SESSION_SECRET=dontyoudarecopypastethis +``` + +마지막으로 이 코드를 사용하기 위해 공개 API에 일부 내보내기를 추가하세요. + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; + +export type { Article } from "./models"; + +export { createUserSession, getUserFromSession, requireUser } from "./auth.server"; +``` + +이제 RealWorld 백엔드와 실제로 통신하여 등록을 수행하는 코드를 작성할 수 있습니다. 그것을 `pages/sign-in/api`에 유지할 것입니다. `register.ts`라는 파일을 만들고 다음 코드를 넣으세요. + + +```tsx title="pages/sign-in/api/register.ts" +import { json, type ActionFunctionArgs } from "@remix-run/node"; + +import { POST, createUserSession } from "shared/api"; + +export const register = async ({ request }: ActionFunctionArgs) => { + const formData = await request.formData(); + const username = formData.get("username")?.toString() ?? ""; + const email = formData.get("email")?.toString() ?? ""; + const password = formData.get("password")?.toString() ?? ""; + + const { data, error } = await POST("/users", { + body: { user: { email, password, username } }, + }); + + if (error) { + return json({ error }, { status: 400 }); + } else { + return createUserSession({ + request: request, + user: data.user, + redirectTo: "/", + }); + } +}; +``` + +```tsx title="pages/sign-in/index.ts" +export { RegisterPage } from './ui/RegisterPage'; +export { register } from './api/register'; +``` + +거의 다 왔습니다! 페이지와 액션을 `/register` 라우트에 연결하기만 하면 됩니다. `app/routes`에 `register.tsx`를 만드세요. + +```tsx title="app/routes/register.tsx" +import { RegisterPage, register } from "pages/sign-in"; + +export { register as action }; + +export default RegisterPage; +``` + +이제 [http://localhost:3000/register](http://localhost:3000/register)로 가면 사용자를 생성할 수 있어야 합니다! 애플리케이션의 나머지 부분은 아직 이에 반응하지 않을 것입니다. 곧 그 문제를 해결하겠습니다. + +매우 유사한 방식으로 로그인 페이지를 구현할 수 있습니다. 직접 시도해 보거나 그냥 코드를 가져와서 계속 진행하세요. + +```tsx title="pages/sign-in/api/sign-in.ts" +import { json, type ActionFunctionArgs } from "@remix-run/node"; + +import { POST, createUserSession } from "shared/api"; + +export const signIn = async ({ request }: ActionFunctionArgs) => { + const formData = await request.formData(); + const email = formData.get("email")?.toString() ?? ""; + const password = formData.get("password")?.toString() ?? ""; + + const { data, error } = await POST("/users/login", { + body: { user: { email, password } }, + }); + + if (error) { + return json({ error }, { status: 400 }); + } else { + return createUserSession({ + request: request, + user: data.user, + redirectTo: "/", + }); + } +}; +``` + +```tsx title="pages/sign-in/ui/SignInPage.tsx" +import { Form, Link, useActionData } from "@remix-run/react"; + +import type { signIn } from "../api/sign-in"; + +export function SignInPage() { + const signInData = useActionData(); + + return ( +
+
+
+
+

Sign in

+

+ Need an account? +

+ + {signInData?.error && ( +
    + {signInData.error.errors.body.map((error) => ( +
  • {error}
  • + ))} +
+ )} + +
+
+ +
+
+ +
+ +
+
+
+
+
+ ); +} +``` + +```tsx title="pages/sign-in/index.ts" +export { RegisterPage } from './ui/RegisterPage'; +export { register } from './api/register'; +export { SignInPage } from './ui/SignInPage'; +export { signIn } from './api/sign-in'; +``` + +```tsx title="app/routes/login.tsx" +import { SignInPage, signIn } from "pages/sign-in"; + +export { signIn as action }; + +export default SignInPage; +``` + +이제 사용자가 이 페이지에 실제로 접근할 수 있는 방법을 제공해 봅시다. + +### 헤더 + +1부에서 논의했듯이, 앱 헤더는 일반적으로 Widgets나 Shared에 배치됩니다. 매우 간단하고 모든 비즈니스 로직을 외부에 유지할 수 있기 때문에 Shared에 넣을 것입니다. 이를 위한 장소를 만들어 봅시다. + +```bash +npx fsd shared ui +``` + +이제 다음 내용으로 `shared/ui/Header.tsx`를 만드세요. + +```tsx title="shared/ui/Header.tsx" +import { useContext } from "react"; +import { Link, useLocation } from "@remix-run/react"; + +import { CurrentUser } from "../api/currentUser"; + +export function Header() { + const currentUser = useContext(CurrentUser); + const { pathname } = useLocation(); + + return ( + + ); +} +``` + +이 컴포넌트를 `shared/ui`에서 내보내세요. + +```tsx title="shared/ui/index.ts" +export { Header } from "./Header"; +``` + +헤더에서는 `shared/api`에 유지되는 컨텍스트에 의존합니다. 그것도 만드세요. + +```tsx title="shared/api/currentUser.ts" +import { createContext } from "react"; + +import type { User } from "./models"; + +export const CurrentUser = createContext(null); +``` + +```tsx title="shared/api/index.ts" +export { GET, POST, PUT, DELETE } from "./client"; + +export type { Article } from "./models"; + +export { createUserSession, getUserFromSession, requireUser } from "./auth.server"; +export { CurrentUser } from "./currentUser"; +``` + +이제 페이지에 헤더를 추가해 봅시다. 모든 페이지에 있어야 하므로 루트 라우트에 추가하고 outlet(페이지가 렌더링될 위치)을 `CurrentUser` 컨텍스트 제공자로 감싸는 것이 합리적입니다. 이렇게 하면 전체 앱과 헤더가 현재 사용자 객체에 접근할 수 있습니다. 또한 쿠키에서 실제로 현재 사용자 객체를 가져오는 로더를 추가할 것입니다. `app/root.tsx`에 다음 내용을 넣으세요. + +```tsx title="app/root.tsx" +import { cssBundleHref } from "@remix-run/css-bundle"; +import type { LinksFunction, LoaderFunctionArgs } from "@remix-run/node"; +import { + Links, + LiveReload, + Meta, + Outlet, + Scripts, + ScrollRestoration, + useLoaderData, +} from "@remix-run/react"; + +import { Header } from "shared/ui"; +import { getUserFromSession, CurrentUser } from "shared/api"; + +export const links: LinksFunction = () => [ + ...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []), +]; + +export const loader = ({ request }: LoaderFunctionArgs) => + getUserFromSession(request); + +export default function App() { + const user = useLoaderData(); + + return ( + + + + + + + + + + + + + +
+ + + + + + + + ); +} +``` + +이 시점에서 홈 페이지에 다음과 같은 내용이 표시되어야 합니다. + +
+ ![The feed page of Conduit, including the header, the feed, and the tags. The tabs are still missing.](/img/tutorial/realworld-feed-without-tabs.jpg) + +
헤더, 피드, 태그를 포함한 Conduit의 피드 페이지. 탭은 아직 없습니다.
+
+ +### 탭 + +이제 인증 상태를 감지할 수 있으므로 탭과 글 좋아요를 빠르게 구현하여 피드 페이지를 완성해 봅시다. 또 다른 폼이 필요하지만 이 페이지 파일이 꽤 커지고 있으므로 이러한 폼을 인접한 파일로 옮기겠습니다. `Tabs.tsx`, `PopularTags.tsx`, `Pagination.tsx`를 다음 내용으로 만들 것입니다. + + +```tsx title="pages/feed/ui/Tabs.tsx" +import { useContext } from "react"; +import { Form, useSearchParams } from "@remix-run/react"; + +import { CurrentUser } from "shared/api"; + +export function Tabs() { + const [searchParams] = useSearchParams(); + const currentUser = useContext(CurrentUser); + + return ( +
+
+
    + {currentUser !== null && ( +
  • + +
  • + )} +
  • + +
  • + {searchParams.has("tag") && ( +
  • + + {searchParams.get("tag")} + +
  • + )} +
+
+
+ ); +} +``` + +```tsx title="pages/feed/ui/PopularTags.tsx" +import { Form, useLoaderData } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import type { loader } from "../api/loader"; + +export function PopularTags() { + const { tags } = useLoaderData(); + + return ( +
+

Popular Tags

+ +
+ +
+ {tags.tags.map((tag) => ( + + ))} +
+ +
+ ); +} +``` + +```tsx title="pages/feed/ui/Pagination.tsx" +import { Form, useLoaderData, useSearchParams } from "@remix-run/react"; +import { ExistingSearchParams } from "remix-utils/existing-search-params"; + +import { LIMIT, type loader } from "../api/loader"; + +export function Pagination() { + const [searchParams] = useSearchParams(); + const { articles } = useLoaderData(); + const pageAmount = Math.ceil(articles.articlesCount / LIMIT); + const currentPage = parseInt(searchParams.get("page") ?? "1", 10); + + return ( +
+ +
    + {Array(pageAmount) + .fill(null) + .map((_, index) => + index + 1 === currentPage ? ( +
  • + {index + 1} +
  • + ) : ( +
  • + +
  • + ), + )} +
+ + ); +} +``` + +이제 `FeedPage`를 다음과 같이 업데이트하세요. + +```tsx title="pages/feed/ui/FeedPage.tsx" +import { useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { ArticlePreview } from "./ArticlePreview"; +import { Tabs } from "./Tabs"; +import { PopularTags } from "./PopularTags"; +import { Pagination } from "./Pagination"; + +export function FeedPage() { + const { articles } = useLoaderData(); + + return ( +
+
+
+

conduit

+

A place to share your knowledge.

+
+
+ +
+
+
+ + + {articles.articles.map((article) => ( + + ))} + + +
+ +
+ +
+
+
+
+ ); +} +``` + +마지막으로 로더를 업데이트하여 새로운 필터를 처리하세요. + +```tsx title="pages/feed/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET, requireUser } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + /* unchanged */ +} + +/** Amount of articles on one page. */ +export const LIMIT = 20; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const url = new URL(request.url); + const selectedTag = url.searchParams.get("tag") ?? undefined; + const page = parseInt(url.searchParams.get("page") ?? "", 10); + + if (url.searchParams.get("source") === "my-feed") { + const userSession = await requireUser(request); + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles/feed", { + params: { + query: { + limit: LIMIT, + offset: !Number.isNaN(page) ? page * LIMIT : undefined, + }, + }, + headers: { Authorization: `Token ${userSession.token}` }, + }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); + } + + return json( + await promiseHash({ + articles: throwAnyErrors( + GET("/articles", { + params: { + query: { + tag: selectedTag, + limit: LIMIT, + offset: !Number.isNaN(page) ? page * LIMIT : undefined, + }, + }, + }), + ), + tags: throwAnyErrors(GET("/tags")), + }), + ); +}; +``` + +피드 페이지를 떠나기 전에, 글에 대한 좋아요를 처리하는 코드를 추가해 봅시다. `ArticlePreview.tsx`를 다음과 같이 변경하세요. + +```tsx title="pages/feed/ui/ArticlePreview.tsx" +import { Form, Link } from "@remix-run/react"; +import type { Article } from "shared/api"; + +interface ArticlePreviewProps { + article: Article; +} + +export function ArticlePreview({ article }: ArticlePreviewProps) { + return ( +
+
+ + + +
+ + {article.author.username} + + + {new Date(article.createdAt).toLocaleDateString(undefined, { + dateStyle: "long", + })} + +
+
+ +
+
+ +

{article.title}

+

{article.description}

+ Read more... +
    + {article.tagList.map((tag) => ( +
  • + {tag} +
  • + ))} +
+ +
+ ); +} +``` + +이 코드는 글에 좋아요를 표시하기 위해 `/article/:slug`로 `_action=favorite`과 함께 POST 요청을 보냅니다. 아직 작동하지 않겠지만, 글 읽기 페이지 작업을 시작하면서 이것도 구현할 것입니다. + +이것으로 피드가 공식적으로 완성되었습니다! 야호! + +### 글 읽기 페이지 + +먼저 데이터가 필요합니다. 로더를 만들어 봅시다. + +```bash +npx fsd pages article-read -s api +``` + +```tsx title="pages/article-read/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import invariant from "tiny-invariant"; +import type { FetchResponse } from "openapi-fetch"; +import { promiseHash } from "remix-utils/promise"; + +import { GET, getUserFromSession } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async ({ request, params }: LoaderFunctionArgs) => { + invariant(params.slug, "Expected a slug parameter"); + const currentUser = await getUserFromSession(request); + const authorization = currentUser + ? { Authorization: `Token ${currentUser.token}` } + : undefined; + + return json( + await promiseHash({ + article: throwAnyErrors( + GET("/articles/{slug}", { + params: { + path: { slug: params.slug }, + }, + headers: authorization, + }), + ), + comments: throwAnyErrors( + GET("/articles/{slug}/comments", { + params: { + path: { slug: params.slug }, + }, + headers: authorization, + }), + ), + }), + ); +}; +``` + +```tsx title="pages/article-read/index.ts" +export { loader } from "./api/loader"; +``` + + +이제 `/article/:slug` 라우트에 연결할 수 있습니다. `article.$slug.tsx`라는 라우트 파일을 만드세요. + +```tsx title="app/routes/article.$slug.tsx" +export { loader } from "pages/article-read"; +``` + +페이지 자체는 세 가지 주요 블록으로 구성됩니다 - 글 헤더와 액션(두 번 반복), 글 본문, 댓글 섹션입니다. 다음은 페이지의 마크업입니다. 특별히 흥미로운 내용은 없습니다: + +```tsx title="pages/article-read/ui/ArticleReadPage.tsx" +import { useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { ArticleMeta } from "./ArticleMeta"; +import { Comments } from "./Comments"; + +export function ArticleReadPage() { + const { article } = useLoaderData(); + + return ( +
+
+
+

{article.article.title}

+ + +
+
+ +
+
+
+

{article.article.body}

+
    + {article.article.tagList.map((tag) => ( +
  • + {tag} +
  • + ))} +
+
+
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +} +``` + +더 흥미로운 것은 `ArticleMeta`와 `Comments`입니다. 이들은 글 좋아요, 댓글 작성 등과 같은 쓰기 작업을 포함합니다. 이들을 작동시키려면 먼저 백엔드 부분을 구현해야 합니다. 페이지의 `api` 세그먼트에 `action.ts`를 만드세요: + +```tsx title="pages/article-read/api/action.ts" +import { redirect, type ActionFunctionArgs } from "@remix-run/node"; +import { namedAction } from "remix-utils/named-action"; +import { redirectBack } from "remix-utils/redirect-back"; +import invariant from "tiny-invariant"; + +import { DELETE, POST, requireUser } from "shared/api"; + +export const action = async ({ request, params }: ActionFunctionArgs) => { + const currentUser = await requireUser(request); + + const authorization = { Authorization: `Token ${currentUser.token}` }; + + const formData = await request.formData(); + + return namedAction(formData, { + async delete() { + invariant(params.slug, "Expected a slug parameter"); + await DELETE("/articles/{slug}", { + params: { path: { slug: params.slug } }, + headers: authorization, + }); + return redirect("/"); + }, + async favorite() { + invariant(params.slug, "Expected a slug parameter"); + await POST("/articles/{slug}/favorite", { + params: { path: { slug: params.slug } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async unfavorite() { + invariant(params.slug, "Expected a slug parameter"); + await DELETE("/articles/{slug}/favorite", { + params: { path: { slug: params.slug } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async createComment() { + invariant(params.slug, "Expected a slug parameter"); + const comment = formData.get("comment"); + invariant(typeof comment === "string", "Expected a comment parameter"); + await POST("/articles/{slug}/comments", { + params: { path: { slug: params.slug } }, + headers: { ...authorization, "Content-Type": "application/json" }, + body: { comment: { body: comment } }, + }); + return redirectBack(request, { fallback: "/" }); + }, + async deleteComment() { + invariant(params.slug, "Expected a slug parameter"); + const commentId = formData.get("id"); + invariant(typeof commentId === "string", "Expected an id parameter"); + const commentIdNumeric = parseInt(commentId, 10); + invariant( + !Number.isNaN(commentIdNumeric), + "Expected a numeric id parameter", + ); + await DELETE("/articles/{slug}/comments/{id}", { + params: { path: { slug: params.slug, id: commentIdNumeric } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async followAuthor() { + const authorUsername = formData.get("username"); + invariant( + typeof authorUsername === "string", + "Expected a username parameter", + ); + await POST("/profiles/{username}/follow", { + params: { path: { username: authorUsername } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + async unfollowAuthor() { + const authorUsername = formData.get("username"); + invariant( + typeof authorUsername === "string", + "Expected a username parameter", + ); + await DELETE("/profiles/{username}/follow", { + params: { path: { username: authorUsername } }, + headers: authorization, + }); + return redirectBack(request, { fallback: "/" }); + }, + }); +}; +``` + +그 슬라이스에서 이를 내보내고 라우트에서도 내보내세요. 그리고 페이지 자체도 연결하겠습니다. + +```tsx title="pages/article-read/index.ts" +export { ArticleReadPage } from "./ui/ArticleReadPage"; +export { loader } from "./api/loader"; +export { action } from "./api/action"; +``` + +```tsx title="app/routes/article.$slug.tsx" +import { ArticleReadPage } from "pages/article-read"; + +export { loader, action } from "pages/article-read"; + +export default ArticleReadPage; +``` + +이제 독자 페이지에서 좋아요 버튼을 아직 구현하지 않았지만, 피드의 좋아요 버튼이 작동하기 시작할 것입니다! 이 라우트로 "좋아요" 요청을 보내고 있었기 때문입니다. 한번 시도해 보세요. + +`ArticleMeta`와 `Comments`는 다시 한번 폼들의 모음입니다. 이전에 이미 해봤으니, 코드를 가져와서 넘어가겠습니다. + +```tsx title="pages/article-read/ui/ArticleMeta.tsx" +import { Form, Link, useLoaderData } from "@remix-run/react"; +import { useContext } from "react"; + +import { CurrentUser } from "shared/api"; +import type { loader } from "../api/loader"; + +export function ArticleMeta() { + const currentUser = useContext(CurrentUser); + const { article } = useLoaderData(); + + return ( +
+
+ + + + +
+ + {article.article.author.username} + + {article.article.createdAt} +
+ + {article.article.author.username == currentUser?.username ? ( + <> + + Edit Article + +    + + + ) : ( + <> + + +    + + + )} +
+
+ ); +} +``` + +```tsx title="pages/article-read/ui/Comments.tsx" +import { useContext } from "react"; +import { Form, Link, useLoaderData } from "@remix-run/react"; + +import { CurrentUser } from "shared/api"; +import type { loader } from "../api/loader"; + +export function Comments() { + const { comments } = useLoaderData(); + const currentUser = useContext(CurrentUser); + + return ( +
+ {currentUser !== null ? ( +
+
+ +
+
+ + +
+
+ ) : ( +
+
+

+ Sign in +   or   + Sign up +   to add comments on this article. +

+
+
+ )} + + {comments.comments.map((comment) => ( +
+
+

{comment.body}

+
+ +
+ + + +   + + {comment.author.username} + + {comment.createdAt} + {comment.author.username === currentUser?.username && ( + +
+ + +
+
+ )} +
+
+ ))} +
+ ); +} +``` + +이것으로 우리의 글 읽기 페이지도 완성되었습니다! 이제 작성자를 팔로우하고, 글에 좋아요를 누르고, 댓글을 남기는 버튼들이 예상대로 작동해야 합니다. + +
+ ![Article reader with functioning buttons to like and follow](/img/tutorial/realworld-article-reader.jpg) + +
기능하는 좋아요와 팔로우 버튼이 있는 글 읽기 페이지
+
+ +### 글 작성 페이지 + +이것은 이 튜토리얼에서 다룰 마지막 페이지이며, 여기서 가장 흥미로운 부분은 폼 데이터를 어떻게 검증할 것인가 입니다. + +페이지 자체인 `article-edit/ui/ArticleEditPage.tsx`는 꽤 간단할 것이며, 추가적인 복잡성은 다른 두 개의 컴포넌트로 숨겨질 것입니다. + +```tsx title="pages/article-edit/ui/ArticleEditPage.tsx" +import { Form, useLoaderData } from "@remix-run/react"; + +import type { loader } from "../api/loader"; +import { TagsInput } from "./TagsInput"; +import { FormErrors } from "./FormErrors"; + +export function ArticleEditPage() { + const article = useLoaderData(); + + return ( +
+
+
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+
+
+
+ ); +} +``` + +이 페이지는 현재 글(새로 작성하는 경우가 아니라면)을 가져와서 해당하는 폼 필드를 채웁니다. 이전에 본 적이 있습니다. 흥미로운 부분은 `FormErrors`인데, 이는 검증 결과를 받아 사용자에게 표시할 것입니다. 한번 살펴보겠습니다. + +```tsx title="pages/article-edit/ui/FormErrors.tsx" +import { useActionData } from "@remix-run/react"; +import type { action } from "../api/action"; + +export function FormErrors() { + const actionData = useActionData(); + + return actionData?.errors != null ? ( +
    + {actionData.errors.map((error) => ( +
  • {error}
  • + ))} +
+ ) : null; +} +``` + +여기서는 우리의 액션이 `errors` 필드, 즉 사람이 읽을 수 있는 오류 메시지 배열을 반환할 것이라고 가정하고 있습니다. 곧 액션에 대해 다루겠습니다. + +또 다른 컴포넌트는 태그 입력입니다. 이는 단순한 입력 필드에 선택된 태그의 추가적인 미리보기가 있는 것입니다. 여기에는 특별한 것이 없습니다: + +```tsx title="pages/article-edit/ui/TagsInput.tsx" +import { useEffect, useRef, useState } from "react"; + +export function TagsInput({ + name, + defaultValue, +}: { + name: string; + defaultValue?: Array; +}) { + const [tagListState, setTagListState] = useState(defaultValue ?? []); + + function removeTag(tag: string): void { + const newTagList = tagListState.filter((t) => t !== tag); + setTagListState(newTagList); + } + + const tagsInput = useRef(null); + useEffect(() => { + tagsInput.current && (tagsInput.current.value = tagListState.join(",")); + }, [tagListState]); + + return ( + <> + + setTagListState(e.target.value.split(",").filter(Boolean)) + } + /> +
+ {tagListState.map((tag) => ( + + + [" ", "Enter"].includes(e.key) && removeTag(tag) + } + onClick={() => removeTag(tag)} + >{" "} + {tag} + + ))} +
+ + ); +} +``` + +이제 API 부분입니다. 로더는 URL을 살펴보고, 글 슬러그가 포함되어 있다면 기존 글을 수정하는 것이므로 해당 데이터를 로드해야 합니다. 그렇지 않으면 아무것도 반환하지 않습니다. 그 로더를 만들어 봅시다. + +```ts title="pages/article-edit/api/loader.ts" +import { json, type LoaderFunctionArgs } from "@remix-run/node"; +import type { FetchResponse } from "openapi-fetch"; + +import { GET, requireUser } from "shared/api"; + +async function throwAnyErrors( + responsePromise: Promise>, +) { + const { data, error, response } = await responsePromise; + + if (error !== undefined) { + throw json(error, { status: response.status }); + } + + return data as NonNullable; +} + +export const loader = async ({ params, request }: LoaderFunctionArgs) => { + const currentUser = await requireUser(request); + + if (!params.slug) { + return { article: null }; + } + + return throwAnyErrors( + GET("/articles/{slug}", { + params: { path: { slug: params.slug } }, + headers: { Authorization: `Token ${currentUser.token}` }, + }), + ); +}; +``` + +액션은 새로운 필드 값들을 받아 우리의 데이터 스키마를 통해 실행하고, 모든 것이 올바르다면 이러한 변경사항을 백엔드에 커밋합니다. 이는 기존 글을 업데이트하거나 새 글을 생성하는 방식으로 이루어집니다. + +```tsx title="pages/article-edit/api/action.ts" +import { json, redirect, type ActionFunctionArgs } from "@remix-run/node"; + +import { POST, PUT, requireUser } from "shared/api"; +import { parseAsArticle } from "../model/parseAsArticle"; + +export const action = async ({ request, params }: ActionFunctionArgs) => { + try { + const { body, description, title, tags } = parseAsArticle( + await request.formData(), + ); + const tagList = tags?.split(",") ?? []; + + const currentUser = await requireUser(request); + const payload = { + body: { + article: { + title, + description, + body, + tagList, + }, + }, + headers: { Authorization: `Token ${currentUser.token}` }, + }; + + const { data, error } = await (params.slug + ? PUT("/articles/{slug}", { + params: { path: { slug: params.slug } }, + ...payload, + }) + : POST("/articles", payload)); + + if (error) { + return json({ errors: error }, { status: 422 }); + } + + return redirect(`/article/${data.article.slug ?? ""}`); + } catch (errors) { + return json({ errors }, { status: 400 }); + } +}; +``` + +스키마는 `FormData`를 위한 파싱 함수로도 작동하여, 깨끗한 필드를 편리하게 얻거나 마지막에 처리할 오류를 던질 수 있게 해줍니다. 그 파싱 함수는 다음과 같이 보일 수 있습니다. + +```tsx title="pages/article-edit/model/parseAsArticle.ts" +export function parseAsArticle(data: FormData) { + const errors = []; + + const title = data.get("title"); + if (typeof title !== "string" || title === "") { + errors.push("Give this article a title"); + } + + const description = data.get("description"); + if (typeof description !== "string" || description === "") { + errors.push("Describe what this article is about"); + } + + const body = data.get("body"); + if (typeof body !== "string" || body === "") { + errors.push("Write the article itself"); + } + + const tags = data.get("tags"); + if (typeof tags !== "string") { + errors.push("The tags must be a string"); + } + + if (errors.length > 0) { + throw errors; + } + + return { title, description, body, tags: data.get("tags") ?? "" } as { + title: string; + description: string; + body: string; + tags: string; + }; +} +``` + +물론 이는 다소 길고 반복적이지만, 사람이 읽을 수 있는 오류 메시지를 위해 우리가 지불해야 하는 대가입니다. 이것은 Zod 스키마일 수도 있지만, 그렇게 하면 프론트엔드에서 오류 메시지를 렌더링해야 하고, 이 폼은 그런 복잡성을 감당할 만한 가치가 없습니다. + +마지막 단계로 - 페이지, 로더, 그리고 액션을 라우트에 연결합니다. 우리는 생성과 편집을 모두 깔끔하게 지원하므로 `editor._index.tsx`와 `editor.$slug.tsx` 모두에서 동일한 것을 내보낼 수 있습니다. + +```tsx title="pages/article-edit/index.ts" +export { ArticleEditPage } from "./ui/ArticleEditPage"; +export { loader } from "./api/loader"; +export { action } from "./api/action"; +``` + +```tsx title="app/routes/editor._index.tsx, app/routes/editor.$slug.tsx (same content)" +import { ArticleEditPage } from "pages/article-edit"; + +export { loader, action } from "pages/article-edit"; + +export default ArticleEditPage; +``` + +이제 완료되었습니다! 로그인하고 새 글을 작성해보세요. 또는 글을 "잊어버리고" 검증이 작동하는 것을 확인해보세요. + +
+ ![The Conduit article editor, with the title field saying “New article” and the rest of the fields empty. Above the form there are two errors: “**Describe what this article is about” and “Write the article itself”.**](/img/tutorial/realworld-article-editor.jpg) + +
제목 필드에 "새 글"이라고 쓰여 있고 나머지 필드는 비어 있는 Conduit 글 편집기. 폼 위에 두 개의 오류가 있습니다. **"이 글이 무엇에 관한 것인지 설명해주세요"**, **"글 본문을 작성해주세요"**.
+
+ +프로필과 설정 페이지는 글 읽기와 편집기 페이지와 매우 유사하므로, 독자인 여러분의 연습 과제로 남겨두겠습니다 :) From 39ae10f99ef832e849bd1802ffa9893455d5c74a Mon Sep 17 00:00:00 2001 From: Minsu <52266597+Gaic4o@users.noreply.github.com> Date: Fri, 11 Oct 2024 06:51:34 +0900 Subject: [PATCH 07/29] feat: guides page translated into Korean (#732) --- .../current/guides/index.mdx | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 i18n/kr/docusaurus-plugin-content-docs/current/guides/index.mdx diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/index.mdx b/i18n/kr/docusaurus-plugin-content-docs/current/guides/index.mdx new file mode 100644 index 0000000000..6d7a02ccda --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/index.mdx @@ -0,0 +1,50 @@ +--- +hide_table_of_contents: true +pagination_prev: get-started/index +--- + +# 🎯 Guides + +PRACTICE-ORIENTED + +

+Feature-Sliced Design(FSD)의 적용을 위한 종합 가이드입니다. 구체적인 예시, 마이그레이션 전략, 그리고 FSD 코드에서 발견할 수 있는 흔한 설계상의 문제들을 다룹니다. FSD를 프로젝트에 도입하거나 기존 구조를 개선하고자 할 때 참고하기 좋은 리소스입니다. +

+ +## Main + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { ToolOutlined, ImportOutlined, BugOutlined, FunctionOutlined } from "@ant-design/icons"; + + + + + + + + + From 9b25b250ea31aeeb7e935a6ba332621fc21487f2 Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Sat, 19 Oct 2024 10:58:31 +0200 Subject: [PATCH 08/29] fix: fix typos in the SvelteKit guides (#737) --- .../current/guides/tech/with-nuxtjs.mdx | 8 ++++---- .../current/guides/tech/with-sveltekit.mdx | 12 ++++++------ .../current/guides/tech/with-sveltekit.mdx | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx index 08855b6869..929bdcaf51 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx @@ -66,7 +66,7 @@ Thus, the file structure will look like this: │ │ │ │ ├── home-page.vue │ │ │ ├── index.ts ``` -Finally, let's add a root to the config: +Finally, let's add a route to the config: ```ts title="app/router.config.ts" import type { RouterConfig } from '@nuxt/schema' @@ -111,8 +111,8 @@ Now, you can create routes for pages within `app` and connect pages from `pages` For example, to add a `Home` page to your project, you need to do the following steps: - Add a page slice inside the `pages` layer -- Add the corresponding root inside the `app` layer -- Align the page from the slice with the root +- Add the corresponding route inside the `app` layer +- Connect the page from the slice with the route To create a page slice, let's use the [CLI](https://github.com/feature-sliced/cli): @@ -126,7 +126,7 @@ Create a ``home-page.vue`` file inside the ui segment, access it using the Publi export { default as HomePage } from './ui/home-page'; ``` -Create a root for this page inside the `app` layer: +Create a route for this page inside the `app` layer: ```sh diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx index 08c81813da..886b2381ee 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx @@ -44,10 +44,10 @@ Thus, your file structure should look like this: │ ├── app │ │ ├── index.html │ │ ├── routes -│ ├── pages # Папка pages, закреплённая за FSD +│ ├── pages # FSD Pages folder ``` -Now, you can create roots for pages within `app` and connect pages from `pages` to them. +Now, you can create routes for pages within `app` and connect pages from `pages` to them. For example, to add a home page to your project, you need to do the following steps: - Add a page slice inside the `pages` layer @@ -60,13 +60,13 @@ To create a page slice, let's use the [CLI](https://github.com/feature-sliced/cl fsd pages home ``` -Create a ``home-page.vue`` file inside the ui segment, access it using the Public API +Create a ``home-page.svelte`` file inside the ui segment, access it using the Public API ```ts title="src/pages/home/index.ts" -export { default as HomePage } from './ui/home-page'; +export { default as HomePage } from './ui/home-page.svelte'; ``` -Create a root for this page inside the `app` layer: +Create a route for this page inside the `app` layer: ```sh @@ -82,7 +82,7 @@ Create a root for this page inside the `app` layer: │ │ │ ├── index.ts ``` -Add your page component inside the `index.svelte` file: +Add your page component inside the `+page.svelte` file: ```html title="src/app/routes/+page.svelte" +``` + +## Ambient 선언 파일(*.d.ts) + +[Vite][ext-vite]나 [ts-reset][ext-ts-reset] 같은 일부 패키지는 앱 전반에서 작동하기 위해 Ambient 선언 파일을 필요로 합니다. 이러한 파일들은 보통 크거나 복잡하지 않기 때문에 `src/` 폴더에 두어도 괜찮습니다. 더 정리된 구조를 위해 `app/ambient/` 폴더에 두는 것도 좋은 방법입니다. + +타이핑이 없는 패키지인 경우, 해당 패키지를 미타입으로 선언하거나 직접 타이핑을 작성할 수 있습니다. 이러한 타이핑을 위한 좋은 위치는 `shared/lib` 폴더 내의 `shared/lib/untyped-packages` 폴더입니다. 이 폴더에 `%LIBRARY_NAME%.d.ts` 파일을 생성하고 필요한 타입을 선언합니다 + +```ts title="shared/lib/untyped-packages/use-react-screenshot.d.ts" +// 이 라이브러리는 타입 정의가 없으며 작성하는 것을 생략했습니다. +declare module "use-react-screenshot"; +``` + +## 타입 자동 생성 + +외부 소스로부터 타입을 생성하는 일은 흔히 발생합니다. 예를 들어, OpenAPI 스키마로부터 백엔드 타입을 생성하는 경우가 있습니다.
+이러한 타입을 위한 전용 위치를 코드베이스에 만드는 것이 좋습니다. 예를 들어 `shared/api/openapi`와 같은 위치가 적합합니다. 이상적으로는 이러한 파일이 무엇인지, 어떻게 재생성하는지 등을 설명하는 README 파일도 포함하는 것이 좋습니다. + +[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers +[ext-type-fest]: https://github.com/sindresorhus/type-fest +[ext-zod]: https://zod.dev +[ext-vite]: https://vitejs.dev +[ext-ts-reset]: https://www.totaltypescript.com/ts-reset From 363c739a3c991c480b628843e7a78193f4ff42bc Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Wed, 6 Nov 2024 09:26:59 +0100 Subject: [PATCH 15/29] fix (tutorial:ru): replace wrong usage of the word "segment" (#746) --- .../current/get-started/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md index 3bd40159a6..5063269dee 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -696,7 +696,7 @@ export function FeedPage() { ### Аутентификация {#authentication} -Аутентификация включает в себя две страницы — одну для входа в систему и другую для регистрации. Они, в основном, очень схожие, поэтому имеет смысл держать их в одном сегменте, `sign-in`, чтобы при необходимости можно было переиспользовать код. +Аутентификация включает в себя две страницы — одну для входа в систему и другую для регистрации. Они, в основном, очень схожие, поэтому имеет смысл держать их в одном слайсе, `sign-in`, чтобы при необходимости можно было переиспользовать код. Создайте `RegisterPage.tsx` в сегменте `ui` в `pages/sign-in` со следующим содержимым: From dd7be1864457174ce213b44277f6d1e65c71ebb2 Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Wed, 13 Nov 2024 21:05:22 +0100 Subject: [PATCH 16/29] feat: Feature-Sliced Design 2.1 (#703) --- CHANGELOG.md | 61 ++++- config/docusaurus/extensions.js | 2 +- config/docusaurus/routes.js | 18 +- .../current.json | 2 +- .../current/get-started/faq.md | 6 +- .../current/get-started/tutorial.md | 2 +- .../current/guides/examples/auth.md | 2 +- .../current/guides/migration/from-custom.md | 2 +- .../current/guides/migration/from-v1.md | 6 +- .../current/guides/migration/from-v2-0.md | 45 +++ .../current/reference/index.mdx | 8 +- .../reference/isolation/_category_.yaml | 1 - .../reference/isolation/coupling-cohesion.md | 149 ---------- .../reference/isolation/decouple-entities.mdx | 21 -- .../current/reference/isolation/index.md | 71 ----- .../current/reference/layers.mdx | 169 +++++------- .../current/reference/public-api.md | 256 +++++++---------- .../current/reference/slices-segments.mdx | 62 +++-- .../current.json | 2 +- .../current/get-started/faq.md | 6 +- .../current/guides/migration/from-v1.md | 2 +- .../current/reference/index.mdx | 8 +- .../reference/isolation/coupling-cohesion.md | 3 +- .../current/reference/isolation/index.md | 2 - .../current/get-started/faq.md | 6 +- .../current.json | 2 +- .../current/get-started/faq.md | 6 +- .../current/get-started/tutorial.md | 2 +- .../current/guides/examples/auth.md | 2 +- .../current/guides/migration/from-custom.md | 2 +- .../current/guides/migration/from-v1.md | 4 +- .../current/guides/migration/from-v2-0.md | 45 +++ .../current/reference/index.mdx | 8 +- .../reference/isolation/_category_.yaml | 1 - .../reference/isolation/coupling-cohesion.md | 149 ---------- .../reference/isolation/decouple-entities.mdx | 21 -- .../current/reference/isolation/index.md | 63 ----- .../current/reference/layers.mdx | 180 +++++------- .../current/reference/public-api.md | 258 +++++++----------- .../current/reference/slices-segments.mdx | 64 +++-- .../current.json | 2 +- .../current/reference/index.mdx | 6 - package.json | 2 +- src/pages/versions/index.tsx | 11 +- static/img/circular-import-dark.svg | 1 + static/img/circular-import-light.svg | 1 + 46 files changed, 616 insertions(+), 1126 deletions(-) create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md delete mode 100644 i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml delete mode 100644 i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md delete mode 100644 i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx delete mode 100644 i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/index.md create mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md delete mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml delete mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md delete mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx delete mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/index.md create mode 100644 static/img/circular-import-dark.svg create mode 100644 static/img/circular-import-light.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index d5ff4196d2..a85ab86bc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,64 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Since last release][since-last-release] + -### Added +## [2.1.0] - 2024-10-31 + +The new revision of Feature-Sliced Design is here! The main difference with FSD 2.0 is the new approach to decomposition — “pages first”. + +### What's “pages-first”? + +You do “pages first” by keeping more code in pages. For example, large blocks of UI, forms and data logic that are not reused on other pages should now stay in the slice of the page that they are used in. The division by segments (`ui`, `api`, `model`, etc.) still applies to all this code, and we encourage you to further split and organize code into folders inside of segments — don't just pile all the code into a single file. + +In the same way, widgets are no longer just a compositional layer, instead they should also store code that isn't currently needed outside of that widget, including its own stores, business logic, and API interactions. + +When you have a need to reuse code in several widgets or pages, consider putting it in Shared. If that code involves business logic (i. e. managing specific modal dialogs), consider breaking it up into infrastructural code, like the modal manager, and the business code, like the content of the modals. The infrastructure can then go to Shared, and the content can stay in the pages that use this infrastructure. + +### How is it different? + +In FSD 2.0 we explained how to identify entities and features in your application, and then combine them in widgets and pages. Over time we started disliking this approach, mostly for the following reasons: + +- Code cohesion is much worse in this approach + - You need to jump around several folders just to make changes to a single user flow + - Unused code is harder to delete because it's somewhere else +- Finding entities and features is still an advanced skill that needs to be developed over time + - It requires understanding of the business context, which not all developers want to bother with + - On the other hand, splitting by pages is natural and requires little training + - Different developers have different understandings of these concepts, which leads to everyone having their own idea of FSD, which causes conflict and misunderstanding + +### Is it hard to migrate from FSD 2.0? + +This is a non-breaking change, so you don’t even necessarily need to migrate your current FSD projects to FSD 2.1, but we still think the new way of thinking will lead to a more cohesive and less opinionated structure. We’ve compiled a few steps you can take in [the migration guide](https://feature-sliced.design/docs/guides/migration/from-v2-0). -- New article about how to use FSD with Next.js (#644). +### What else happened since the last release? + +Another exciting new thing in the FSD ecosystem is our architectural linter, [Steiger](https://github.com/feature-sliced/steiger). It's still in active development, but it is production-ready. + +A couple more minor clarifications to the docs were made as well: + +1. Application-aware things like the route constants, the API calls, or company logo, are now explicitly allowed in Shared. Business logic is still not allowed, but these things are not considered to be business logic. +2. Imports between segments in App and Shared were always allowed, but it's been made explicit too. + +And here's what happened to the documentation website: + +#### Added + +- Slightly rewritten and expanded overview page to give some details about FSD right away (#685). +- New partial translations: Korean (#739, #736, #735, #742, #732, #730, #715), Japanese (#728). - The tutorial was rewritten. Technical details were stripped out, more FSD theory has been added (#665). +- Guides on how to deal with common frontend issues like page layouts (#708), types (#701), authentication (#693). +- Guides on how to use FSD with Nuxt (#710, #689, #683, #679), SvelteKit (#698), Next.js (#699, #664, #644), and TanStack Query (#673). +- A new feedback widget, powered by PushFeedback! Go give it a try and let us know what you think of the new pages (#695). +- Comparison of FSD with Atomic Design (#671). + +#### Changed + +- The migration guide from a custom architecture (formerly known as "from legacy") has been actualized (#725). + +#### Removed + +- The decomposition cheatsheet is now unlisted for an undefined period of time. It proved to be more harmful than useful, but maybe it can be saved later (#649). ## [2.0.0] - 2023-10-01 @@ -41,5 +93,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The overview page has been rewritten to be more concise and informative (#512, #515, #516). - FSD has updated its branding, and there are now guidelines to the brand usage. The standard spelling of the name is now "Feature-Sliced Design" (#496, #499, #500, #465). -[since-last-release]: https://github.com/feature-sliced/documentation/compare/v2.0.0...HEAD +[since-last-release]: https://github.com/feature-sliced/documentation/compare/v2.1.0...HEAD +[2.1.0]: https://github.com/feature-sliced/documentation/releases/tag/v2.1.0 [2.0.0]: https://github.com/feature-sliced/documentation/releases/tag/v2.0.0 diff --git a/config/docusaurus/extensions.js b/config/docusaurus/extensions.js index fd52101074..1909f746b1 100644 --- a/config/docusaurus/extensions.js +++ b/config/docusaurus/extensions.js @@ -43,7 +43,7 @@ const presets = [ showLastUpdateTime: true, versions: { current: { - label: `v2.0.0 🍰`, + label: `v2.1`, }, }, sidebarItemsGenerator, diff --git a/config/docusaurus/routes.js b/config/docusaurus/routes.js index 6b06359c86..1a657eabbe 100644 --- a/config/docusaurus/routes.js +++ b/config/docusaurus/routes.js @@ -109,17 +109,17 @@ const LEGACY_ROUTES = [ { title: "Decouple of entities", from: "/docs/concepts/decouple-entities", - to: "/docs/reference/isolation/decouple-entities", + to: "/docs/reference/layers#import-rule-on-layers", }, { title: "Low Coupling & High Cohesion", from: "/docs/concepts/low-coupling", - to: "/docs/reference/isolation/coupling-cohesion", + to: "/docs/reference/slices-segments#zero-coupling-high-cohesion", }, { title: "Cross-communication", from: "/docs/concepts/cross-communication", - to: "/docs/reference/isolation", + to: "/docs/reference/layers#import-rule-on-layers", }, { title: "App splitting", @@ -276,6 +276,18 @@ const LEGACY_ROUTES = [ }, ], }, + { + group: "Deduplication of Reference", + details: + "Cleaned up the Reference section and deduplicated the material", + children: [ + { + title: "Isolation of modules", + from: "/docs/reference/isolation", + to: "/docs/reference/layers#import-rule-on-layers", + }, + ], + }, ]; // @returns { from, to }[] diff --git a/i18n/en/docusaurus-plugin-content-docs/current.json b/i18n/en/docusaurus-plugin-content-docs/current.json index 9af1eb6531..599055a3cf 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current.json +++ b/i18n/en/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "v2.0.0 🍰", + "message": "v2.1", "description": "The label for version current" }, "sidebar.getstartedSidebar.category.Tutorials": { diff --git a/i18n/en/docusaurus-plugin-content-docs/current/get-started/faq.md b/i18n/en/docusaurus-plugin-content-docs/current/get-started/faq.md index a09a1600a1..2f9b4bda5b 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/get-started/faq.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/get-started/faq.md @@ -13,7 +13,7 @@ You can ask your question in our [Telegram chat][telegram], [Discord community][ ### Is there a toolkit or a linter? -There is an official ESLint config — [@feature-sliced/eslint-config][eslint-config-official], and an ESLint plugin — [@conarti/eslint-plugin-feature-sliced][eslint-plugin-conarti], created by Aleksandr Belous, a community member. You're welcome to contribute to these projects or start your own! +Yes! We have a linter called [Steiger][ext-steiger] to check your project's architecture and [folder generators][ext-tools] through a CLI or IDEs. ### Where to store the layout/template of pages? @@ -58,10 +58,10 @@ Rather yes than no Answered [here](/docs/guides/examples/auth) +[ext-steiger]: https://github.com/feature-sliced/steiger +[ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools [import-rule-layers]: /docs/reference/layers#import-rule-on-layers [reference-entities]: /docs/reference/layers#entities -[eslint-config-official]: https://github.com/feature-sliced/eslint-config -[eslint-plugin-conarti]: https://github.com/conarti/eslint-plugin-feature-sliced [motivation]: /docs/about/motivation [telegram]: https://t.me/feature_sliced [discord]: https://discord.gg/S8MzWTUsmp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/get-started/tutorial.md b/i18n/en/docusaurus-plugin-content-docs/current/get-started/tutorial.md index 346217a6a5..662020d924 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/get-started/tutorial.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -38,7 +38,7 @@ As such, our Pages folder will look like this: The key difference of Feature-Sliced Design from an unregulated code structure is that pages cannot reference each other. That is, one page cannot import code from another page. This is due to the **import rule on layers**: -*A module in a slice can only import other slices when they are located on layers strictly below.* +*A module (file) in a slice can only import other slices when they are located on layers strictly below.* In this case, a page is a slice, so modules (files) inside this page can only reference code from layers below, not from the same layer, Pages. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/auth.md b/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/auth.md index 5a96d32275..bf8a33b9e2 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/auth.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/auth.md @@ -189,7 +189,7 @@ To store the token in the User entity, create a reactive store in the `model` se Since the API client is usually defined in `shared/api` or spreaded across the entities, the main challenge to this approach is making the token available to other requests that need it without breaking [the import rule on layers][import-rule-on-layers]: -> A module in a slice can only import other slices when they are located on layers strictly below. +> A module (file) in a slice can only import other slices when they are located on layers strictly below. There are several solutions to this challenge: diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md index 04eb9b40cc..235f7c34f3 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 1 sidebar_label: From a custom architecture --- diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md index 241a964b12..4c0a98a649 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md @@ -1,8 +1,8 @@ --- -sidebar_position: 4 +sidebar_position: 2 --- -# Migration from v1 +# Migration from v1 to v2 ## Why v2? @@ -158,7 +158,7 @@ Now it is much easier to [observe the principle of low coupling][refs-low-coupli - [New ideas v2 with explanations (atomicdesign-chat)][ext-tg-v2-draft] - [Discussion of abstractions and naming for the new version of the methodology (v2)](https://github.com/feature-sliced/documentation/discussions/31) -[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion +[refs-low-coupling]: /docs/reference/slices-segments#zero-coupling-high-cohesion [refs-adaptability]: /docs/about/understanding/naming [ext-v1]: https://feature-sliced.github.io/featureslices.dev/v1.0.html diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md new file mode 100644 index 0000000000..af057a421e --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 3 +--- + +# Migration from v2.0 to v2.1 + +The main change in v2.1 is the new mental model for decomposing an interface — pages first. + +In v2.0, FSD would recommend identifying entities and features in your interface, considering even the smallest bits of entity representation and interactivity for decomposition. Then you would build widgets and pages from entities and features. In this model of decomposition, most of the logic was in entities and features, and pages were just compositional layers that didn't have much significance on their own. + +In v2.1, we recommend starting with pages, and possibly even stopping there. Most people already know how to separate the app into individual pages, and pages are also a common starting point when trying to locate a component in the codebase. In this new model of decomposition, you keep most of the UI and logic in each individual page, maintaining a reusable foundation in Shared. If a need arises to reuse business logic across several pages, you can move it to a layer below. + +Another addition to Feature-Sliced Design is the standardization of cross-imports between entities with the `@x`-notation. + +## How to migrate {#how-to-migrate} + +There are no breaking changes in v2.1, which means that a project written with FSD v2.0 is also a valid project in FSD v2.1. However, we believe that the new mental model is more beneficial for teams and especially onboarding new developers, so we recommend making minor adjustments to your decomposition. + +### Merge slices + +A simple way to start is by running our linter, [Steiger][steiger], on the project. Steiger is built with the new mental model, and the most helpful rules will be: + +- [`insignificant-slice`][insignificant-slice] — if an entity or feature is only used in one page, this rule will suggest merging that entity or feature into the page entirely. +- [`excessive-slicing`][excessive-slicing] — if a layer has too many slices, it's usually a sign that the decomposition is too fine-grained. This rule will suggest merging or grouping some slices to help project navigation. + +```bash +npx steiger src +``` + +This will help you identify which slices are only used once, so that you could reconsider if they are really necessary. In such considerations, keep in mind that a layer forms some kind of global namespace for all the slices inside of it. Just as you wouldn't pollute the global namespace with variables that are only used once, you should treat a place in the namespace of a layer as valuable, to be used sparingly. + +### Standardize cross-imports + +If you had cross-imports between in your project before (we don't judge!), you may now take advantage of a new notation for cross-importing in Feature-Sliced Design — the `@x`-notation. It looks like this: + +```ts title="entities/B/some/file.ts" +import type { EntityA } from "entities/A/@x/B"; +``` + +For more details, check out the [Public API for cross-imports][public-api-for-cross-imports] section in the reference. + +[insignificant-slice]: https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/insignificant-slice +[steiger]: https://github.com/feature-sliced/steiger +[excessive-slicing]: https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/excessive-slicing +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx b/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx index f1f31cd9d9..d944747bd3 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/reference/index.mdx @@ -25,15 +25,9 @@ A detailed description of the key concepts of Feature-Sliced Design. to="/docs/reference/slices-segments" Icon={AppstoreOutlined} /> - diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml b/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml deleted file mode 100644 index df39e2f2b1..0000000000 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml +++ /dev/null @@ -1 +0,0 @@ -label: Isolation diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md b/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md deleted file mode 100644 index 9ca0e6cd8c..0000000000 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Low Coupling & High Cohesion - -Application modules should be designed according to **high cohesion** (should solve one specific task) and **low coupling** (independent of other modules) principles. - -
- - -
- Image inspired by https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/ -
-
- -Within the methodology, this is achieved through: - -* Splitting the application into layers and slices that implement specific functionality -* Providing a [public access interface][refs-public-api] for each module -* Setting up restrictions for [modules interactions][refs-isolation] - each module can depend only on the modules below it, but not on modules from the same or higher layer - -## Components composition (UI level) - -The majority of modern UI frameworks and libraries provide a component model in which each component can have its own properties, state, child components, and even slots. - -This model allows you to design an interface as a **composition of various components that are not directly related to each other** and, thereby, achieve **low coupling** of the interface components. - -### Example - -Let's consider such a composition using the example of a **list with a header:** - -#### Laying the extensibility - -List component will not itself define the look and structure of the header components and list elements, instead it will accept them as parameters - -```tsx -interface ListProps { - Header: React.ReactNode; - Items: React.ReactNode; -} - -const List: Component = ({ Header, Items }) => ( -
- {Header} -
    - {Items} -
-
-) - -``` - -#### Using the composition - -This allows you to **reuse and independently change** components with different Header and list Items. Header and Items components can have both their own local state and their binding to the general state of the application - the List component will not know anything about it, and therefore will not depend on it - -```tsx -} Items={} /> - -} /> - -} Items={} /> - -``` - -## Layer composition (APP level) - -The methodology suggests putting the functionality that is valuable for the user into **features slice**, and the logic related to business entities - into **entities**. Both features and entities **should be designed as modules with high cohesion**, i.e. aimed at solving **one specific task** or related to **one specific entity.** - -All interactions between such modules, similar to the UI components from the example above, should be coordinated via a **modules composition**. - -### Example - -Let's use an example of a chat application with the following features: - -* user can open a contact list and select a friend -* user can open a conversation with a selected friend - -According to methodology principles, it can be represented as: - -Entities - -* User (contains user's state) -* Contact (state of the contact list, utilities for working with an individual contact) -* Chat (the state of the current chat and utilies for it) - -Features - -* Form for sending a message -* Chat selection menu - -#### Let's tie it all together - -The application, to begin with, will have one page, and the interface will be slightly modified from the first example - -```tsx title="page/main/ui.tsx" -} - Items={} - Footer={} -/> -``` - -#### Data model - -The page data model will be organized as a **composition of features and entities**. In this example, the features will be implemented as factories and they will access the interface of entities through the parameters of these factories. - -> However, the implementation using factory is optional - the feature may directly depend on the lower layers. - -```ts title="pages/main/model.ts" -import { userModel } from "entitites/user" -import { conversationModel } from "entities/conversation" -import { contactModel } from "entities/contact" - -import { createMessageInput } from "features/message-input" -import { createConversationSwitch } from "features/conversation-switch" - -import { beautifiy } from "shared/lib/beautify-text" - -export const { allConversations, setConversation } = createConversationSwitch({ - contacts: contactModel.allContacts, - setConversation: conversationModel.setConversation, - currentConversation: conversationModel.conversation, - currentUser: userModel.currentUser -}) - -export const { sendMessage, attachFile } = createMessageInput({ - author: userModel.currentUser - send: conversationModel.sendMessage, - formatMessage: beautify -}) -``` - -## Summary - -1. Modules must have **high cohesion** (have one responsibility, solve one specific task) and provide a [**public interface**][refs-public-api] access -2. **Low coupling** is achieved through the composition of elements - UI components, features and entities -3. To reduce entanglement, modules **should interact with each other only through a public interfaces** - this makes modules independent of each other's internal implementation - -## See also - -* [(Article) Low Coupling and High Cohesion in details](https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/) - * *The diagram at the beginning is inspired by this article* -* [(Article) Low Coupling and High Cohesion. The Law of Demeter](https://medium.com/german-gorelkin/low-coupling-high-cohesion-d36369fb1be9) -* [(Presentation) On design principles (including Low Coupling & High Cohesion)](https://www.slideshare.net/cristalngo/software-design-principles-57388843) - -[refs-public-api]: /docs/reference/public-api -[refs-isolation]: /docs/reference/isolation diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx b/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx deleted file mode 100644 index 6b8d757d7a..0000000000 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -sidebar_position: 2 -sidebar_class_name: sidebar-item--wip ---- - -import WIP from '@site/src/shared/ui/wip/tmpl.mdx' - -# Decouple entities - - - -> About cross-imports of types, adapters and about how to explicitly build connections between entities - -> Also about mythical absolutely-decoupled entities - -## See also - -- [(Thread) Memo about decomposition by entities and building explicit links between them](https://t.me/feature_sliced/3633) -- [(Thread) Example of decomposition for "connected entities" (users/pets/friends)](https://t.me/feature_sliced/3316) -- [(Thread) About cross-imports of types/adapters in entities](https://t.me/feature_sliced/4276) -- [(Thread) About the boundaries of entities and features](https://t.me/feature_sliced/4521) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/index.md b/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/index.md deleted file mode 100644 index 42756834fd..0000000000 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/isolation/index.md +++ /dev/null @@ -1,71 +0,0 @@ -# Isolation of modules - -Within the framework of the methodology, all modules are distributed by scopes of responsibility (layer, slice, segment) - -The layers, in turn, are organized vertically: - -- "At the bottom" are the reused modules (ui-kit, internal libraries of the project), as the most abstract -- And as you move "up", more specific modules are located. - -Regardless of whether it belongs to any slice, each module [**is required to provide a public access interface**][refs-public-api]. - -## Requirements - -The interaction of each module with the rest of the application is designed taking into account a number of requirements: - -1. **Low coupling** with other modules - - *A change in one module should have a weak and predictable effect on others* - -1. **High cohesion** - the responsibilities of each module are "focused" on one task - - - *If the module has too many responsibilities (starts "doing too much") - this should be noticed as soon as possible* -1. **Absence of cyclic dependencies** on the scale of the entire application - - - *Often lead to unexpected, undesirable behavior, it is better to avoid them altogether* - -## Rule - -To meet these requirements, within the framework of the methodology, it is necessary to observe the basic rule: - -:::info Important - -A module can depend only on "underlying" modules, but not on modules from the same or higher layer - -::: - -- `features/auth` **cannot** depend on `features/filters` **and vice versa** -- `features/auth` **may** depend on `shared/ui/button`, **but not vice versa** - -Following this rule allows you to keep dependencies **"unidirectional"** - which automatically **eliminates cyclic imports** and significantly **simplifies tracking dependencies** between modules in the application. - -## Identifying problems - - -Violation of this rule is a signal of problems: - -1. The module has **import from another module** from its own layer - - - Perhaps the module was **unnecessarily fragmented** or has **unnecessary responsibility.** - - You should **combine** it with the imported module or **move it (partially or completely) to the layer below** or transfer the logic of relationships to modules on higher layers. - -1. The module **is imported by many modules** from its own layer - - - Perhaps the module has **extra responsibility.** - - You should **move it (partially or entirely) to the layer below**, or transfer the logic of connections to modules on higher layers. - -1. The module **has imports from many modules** from its own layer - - - Perhaps the module belongs to **another scope of responsibility.** - - You should **move it (partially or completely) to the layer above**. - -## See also - -- [(Guide) About achieving low coupling][refs-low-coupling] -- [(Discussion) Coupled entities](https://github.com/feature-sliced/documentation/discussions/49) -- [(Discussion) About cross-imports and analysis зависимостей](https://github.com/feature-sliced/documentation/discussions/65#discussioncomment-480822) -- [**GRASP** Patterns](https://en.wikipedia.org/wiki/GRASP_(object-oriented_design)) - -[refs-public-api]: /docs/reference/public-api -[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/layers.mdx b/i18n/en/docusaurus-plugin-content-docs/current/reference/layers.mdx index 8782c9d45f..e541e553ba 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/layers.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/reference/layers.mdx @@ -5,15 +5,7 @@ pagination_next: reference/slices-segments # Layers -Layers are the first level of organisational hierarchy in Feature-Sliced Design. Their purpose is to separate code based on how much responsibility it needs and how many other modules in the app it depends on. - -:::note - -On this page, a _module_ refers to an internal module in the application — a file or directory with an index file. Not to be confused with npm packages. - -::: - -Every layer carries special semantic meaning to help you determine how much responsibility you should allocate to a module in your code. The names and meanings of layers are standardized across all projects built with Feature-Sliced Design. +Layers are the first level of organisational hierarchy in Feature-Sliced Design. Their purpose is to separate code based on how much responsibility it needs and how many other modules in the app it depends on. Every layer carries special semantic meaning to help you determine how much responsibility you should allocate to your code. There are **7 layers** in total, arranged from most responsibility and dependency to least: @@ -28,133 +20,107 @@ There are **7 layers** in total, arranged from most responsibility and depe 6. Entities 7. Shared -You don't have to use every layer in your project — only add them if you think it brings value to your project. +You don't have to use every layer in your project — only add them if you think it brings value to your project. Typically, most frontend projects will have at least the Shared, Pages, and App layers. + +In practice, layers are folders with lowercase names (for example, `📁 shared`, `📁 pages`, `📁 app`). Adding new layers is _not recommended_ because their semantics are standardized. ## Import rule on layers -Layers are made up of _slices_ — highly cohesive groups of modules. Feature-Sliced Design promotes low coupling, which is why dependencies between slices are regulated by **the import rule on layers**: +Layers are made up of _slices_ — highly cohesive groups of modules. Dependencies between slices are regulated by **the import rule on layers**: + +> _A module (file) in a slice can only import other slices when they are located on layers strictly below._ + +For example, the folder `📁 ~/features/aaa` is a slice with the name "aaa". A file inside of it, `~/features/aaa/api/request.ts`, cannot import code from any file in `📁 ~/features/bbb`, but can import code from `📁 ~/entities` and `📁 ~/shared`, as well as any sibling code from `📁 ~/features/aaa`, for example, `~/features/aaa/lib/cache.ts`. -> _A module in a slice can only import other slices when they are located on layers strictly below._ +Layers App and Shared are **exceptions** to this rule — they are both a layer and a slice at the same time. Slices partition code by business domain, and these two layers are exceptions because Shared does not have business domains, and App combines all business domains. -For example, in `~/features/aaa`, `aaa` is the slice, so a file `~/features/aaa/api/request.ts` cannot import code from any module in `~/features/bbb`, but can import code from `~/entities` and `~/shared`, as well as any sibling code from `~/features/aaa`. +In practice, this means that layers App and Shared are made up of segments, and segments can import each other freely. ## Layer definitions +This section describes the semantic meaning of each layer to create an intuition for what kind of code belongs there. + ### Shared -Isolated modules, components and abstractions that are detached from the specifics of the project or business. -Warning: not to be treated like [a utility dump][ext--sova-utility-dump]! +This layer forms a foundation for the rest of the app. It's a place to create connections with the external world, for example, backends, third-party libraries, the environment. It is also a place to define your own highly contained libraries. -This layer, unlike others, does not consist of slices, and instead consists of segments directly. +This layer, like the App layer, _does not contain slices_. Slices are intended to divide the layer into business domains, but business domains do not exist in Shared. This means that all files in Shared can reference and import from each other. -**Content examples**: +Here are the segments that you can typically find in this layer: -* UI kit -* API client -* Code working with browser APIs +- `📁 api` — the API client and potentially also functions to make requests to specific backend endpoints. +- `📁 ui` — the application's UI kit. + Components on this layer should not contain business logic, but it's okay for them to be business-themed. For example, you can put the company logo and page layout here. Components with UI logic are also allowed (for example, autocomplete or a search bar). +- `📁 lib` — a collection of internal libraries. + This folder should not be treated as helpers or utilities ([read here why these folders often turn into a dump][ext-sova-utility-dump]). Instead, every library in this folder should have one area of focus, for example, dates, colors, text manipulation, etc. That area of focus should be documented in a README file. The developers in your team should know what can and cannot be added to these libraries. +- `📁 config` — environment variables, global feature flags and other global configuration for your app. +- `📁 routes` — route constants or patterns for matching routes. +- `📁 i18n` — setup code for translations, global translation strings. -### Entities +You are free to add more segments, but make sure that the name of these segments describes the purpose of the content, not its essence. For example, `components`, `hooks`, and `types` are bad segment names because they aren't that helpful when you're looking for code. -Concepts from the real world that form together the essence of the project. Commonly, these are the terms that the business uses to describe the product. +### Entities -Each slice in this layer contains static UI elements, data stores and CRUD operations. +Slices on this layer represent concepts from the real world that the project is working with. Commonly, they are the terms that the business uses to describe the product. For example, a social network might work with business entities like User, Post, and Group. -**Slice examples**: +An entity slice might contain the data storage (`📁 model`), data validation schemas (`📁 model`), entity-related API request functions (`📁 api`), as well as the visual representation of this entity in the interface (`📁 ui`). The visual representation doesn't have to produce a complete UI block — it is primarily meant to reuse the same appearance across several pages in the app, and different business logic may be attached to it through props or slots. - - -
For a social network For a Git frontend (e.g., GitHub)
    -
  • User
  • -
  • Post
  • -
  • Group
  • -
    -
  • Repository
  • -
  • File
  • -
  • Commit
  • -
+#### Entity relationships +Entities in FSD are slices, and by default, slices cannot know about each other. In real life, however, entities often interact with each other, and sometimes one entity owns or contains other entities. Because of that, the business logic of these interactions is preferably kept in higher layers, like Features or Pages. -:::tip +When one entity's data object contains other data objects, usually it's a good idea to make the connection between the entities explicit and side-step the slice isolation by making a cross-reference API with the `@x` notation. The reason is that connected entities need to be refactored together, so it's best to make the connection impossible to miss. -You may notice in the example of a Git frontend that a _repository_ contains _files_. This makes the repository a higher-level entity which has other entities nested inside. That is a common situation with entities, and sometimes it's hard to manage such higher-level entities without breaking the import rule on layers. +For example: -Here are a few suggestions to overcome this issue: -* The UI of entities should contain slots for places where the lower-level entities are to be inserted -* The business logic related to entity interaction should be placed in features (most of the time) -* The typings of database entities can be extracted to the Shared layer below, next to the API client +```ts title="entities/artist/model/artist.ts" +import type { Song } from "entities/song/@x/artist"; -::: +export interface Artist { + name: string; + songs: Array; +} +``` -### Features +```ts title="entities/song/@x/artist.ts" +export type { Song } from "../model/song.ts"; +``` -Actions that a user can make in the application to interact with the business entities to achieve a valuable outcome. This also includes actions that the app makes on behalf of the user to produce value for them. +Learn more about the `@x` notation in the [Public API for cross-imports][public-api-for-cross-imports] section. -Each slice in this layer can contain _interactive_ UI elements, internal state and API calls that enable value-producing actions. +### Features -**Slice examples**: +This layer is for the main interactions in your app, things that your users care to do. These interactions often involve business entities, because that's what the app is about. - - -
For a social network For a Git frontend (e.g., GitHub) Actions on behalf of users
    -
  • Authenticate
  • -
  • Create a post
  • -
  • Join a group
  • -
    -
  • Edit a file
  • -
  • Leave a comment
  • -
  • Merge branches
  • -
    -
  • Detect dark mode
  • -
  • Perform background computation
  • -
  • User-Agent-based actions
  • -
+A crucial principle for using the Features layer effectively is: **not everything needs to be a feature**. A good indicator that something needs to be a feature is the fact that it is reused on several pages. -### Widgets +For example, if the app has several editors, and all of them have comments, then comments are a reused feature. Remember that slices are a mechanism for finding code quickly, and if there are too many features, the important ones are drowned out. -Self-sufficient UI blocks that emerged from the composition of lower-level units like entities and features. +Ideally, when you arrive in a new project, you would discover its functionality by looking through the pages and features. When deciding on what should be a feature, optimize for the experience of a newcomer to the project to quickly discover large important areas of code. -This layer provides a way to fill in the slots left in the UI of Entities with other Entities and interactive elements from Features. Therefore, it is common not to have business logic on this layer, instead keeping it in Features. Each slice in this layer contains ready-to-use UI components and sometimes non-business logic such as gestures, keyboard interaction, etc. +A feature slice might contain the UI to perform the interaction like a form (`📁 ui`), the API calls needed to make the action (`📁 api`), validation and internal state (`📁 model`), feature flags (`📁 config`). -Sometimes, however, it is more convenient to have business logic on this layer. Usually it happens when the widget is quite rich in interactivity (e.g., interactive data tables) and the business logic inside them is not used in other places. +### Widgets -**Slice examples**: +The Widgets layer is intended for large self-sufficient blocks of UI. Widgets are most useful when they are reused across multiple pages, or when the page that they belong to has multiple large indepdendent blocks, and this is one of them. - - -
For a social network For a Git frontend (e.g., GitHub)
    -
  • Post card
  • -
  • User profile header (with actions)
  • -
    -
  • List of files in a repository (with actions)
  • -
  • Comment in a thread
  • -
  • Repository card
  • -
+If a block of UI makes up most of the interesting content on a page, and is never reused, it **should not be a widget**, and instead it should be placed directly inside that page. :::tip -If you're using a nested routing system (e.g. the router of [Remix][ext--remix]), it may be helpful to use the Widgets layer in the same way as a flat routing system would use the Pages layer — to create complete interface blocks, complete with related data fetching, loading states, and error boundaries. In the same way, you can store page layouts on this layer. +If you're using a nested routing system (like the router of [Remix][ext-remix]), it may be helpful to use the Widgets layer in the same way as a flat routing system would use the Pages layer — to create full router blocks, complete with related data fetching, loading states, and error boundaries. + +In the same way, you can store page layouts on this layer. ::: ### Pages -Complete pages for a page-based application (like a website) or screens/activities for screen-based applications (like mobile apps). - -This layer is similar to Widgets in its compositional nature, albeit on a larger scale. Each slice in this layer contains UI components that are ready to be plugged into a router and sometimes data-fetching logic and error handling. +Pages are what makes up websites and applications (also known as screens or activities). One page usually corresponds to one slice, however, if there are several very similar pages, they can be grouped into one slice, for example, registration and login forms. -**Slice examples**: +There's no limit to how much code you can place in a page slice as long as your team still finds it easy to navigate. If a UI block on a page is not reused, it's perfectly fine to keep it inside the page slice. - - -
For a social network For a Git frontend (e.g., GitHub)
    -
  • News feed
  • -
  • Community page
  • -
  • User's public profile
  • -
    -
  • Repository page
  • -
  • User's repositories
  • -
  • Branches in a repository
  • -
+In a page slice you can typically find the page's UI as well as loading states and error boundaries (`📁 ui`) and the data fetching and mutating requests (`📁 api`). It's not common for a page to have a dedicated data model, and tiny bits of state can be kept in the components themselves. ### Processes @@ -164,7 +130,7 @@ This layer has been deprecated. The current version of the spec recommends avoid ::: -Escape hatches for multi-page interactions. +Processes are escape hatches for multi-page interactions. This layer is deliberately left undefined. Most applications should not use this layer, and keep router-level and server-level logic on the App layer. Consider using this layer only when the App layer grows large enough to become unmaintainable and needs unloading. @@ -172,14 +138,15 @@ This layer is deliberately left undefined. Most applications should not use this All kinds of app-wide matters, both in the technical sense (e.g., context providers) and in the business sense (e.g., analytics). -This layer usually doesn't contain slices, like Shared, instead having segments directly. +This layer usually doesn't contain slices, as well as Shared, instead having segments directly. -**Content examples**: +Here are the segments that you can typically find in this layer: -* Styles -* Routing -* Store and other context providers -* Analytics initialization +- `📁 routes` — the router configuration +- `📁 store` — global store configuration +- `📁 styles` — global styles +- `📁 entrypoint` — the entrypoint to the application code, framework-specific -[ext--remix]: https://remix.run -[ext--sova-utility-dump]: https://dev.to/sergeysova/why-utils-helpers-is-a-dump-45fo +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports +[ext-remix]: https://remix.run +[ext-sova-utility-dump]: https://dev.to/sergeysova/why-utils-helpers-is-a-dump-45fo diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/public-api.md b/i18n/en/docusaurus-plugin-content-docs/current/reference/public-api.md index 9a6ef1fc9a..8861ae5c13 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/public-api.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/reference/public-api.md @@ -1,217 +1,153 @@ --- sidebar_position: 3 -pagination_next: about/index --- # Public API -Each entity of the methodology is designed as a **user-friendly and integrable module.** +A public API is a _contract_ between a group of modules, like a slice, and the code that uses it. It also acts as a gate, only allowing access to certain objects, and only through that public API. -## Goals +In practice, it's usually implemented as an index file with re-exports: -The convenience of using and integrating the module is achieved through the fulfillment of *a number of goals*: - -1. The application must be **protected from changes** to the internal structure of individual modules -1. The processing of the internal structure of the module **should not affect** other modules -1. Significant changes in the behavior of the module should be **easily detectable** - > **Significant changes in the behavior of the module** - changes that break the expectations of the user entities of the module. - -These goals can be achieved by introducing a public interface (Public API), which is a single access point to the module's capabilities and defines the "contract" of the module's interaction with the outside world. - -:::info Important - -The entity structure must have a single entry point that provides a public interface - -::: - -```sh -└── features/               #  - ├── auth-form / # Internal structure of the feature - | ├── ui/        # - | ├── model/     # - | ├── {...}/     # - ├── index.ts # Entrypoint features with its public API +```js title="pages/auth/index.js" +export { LoginPage } from "./ui/LoginPage"; +export { RegisterPage } from "./ui/RegisterPage"; ``` -```ts title="**/**/index.ts" -export { Form as AuthForm } from "./ui" -export * as authFormModel from "./model" -``` - -## Requirements for the public API - -Meeting these requirements allows you to reduce interaction with the module to **the implementation of a public interface-contract** and, thereby, achieve reliability and ease of use of the module. - -### 1. Access Control - -The public API must **control access** to the contents of the module - -- Other parts of the application can use **only those module entities that are presented in the public interface** -- The internal part of the module outside the public interface **is accessible only to the module itself**. - -#### Examples +## What makes a good public API? -##### Suspension from private imports +A good public API makes using and integrating into other code a slice convenient and reliable. It can be achieved by setting these three goals: -- **Bad**: There is a direct access to the internal parts of the module, bypassing the public access interface - it is dangerous, especially when refactoring the module +1. The rest of the application must be protected from structural changes to the slice, like a refactoring +1. Significant changes in the behavior of the slice that break the previous expectations should cause changes in the public API +1. Only the necessary parts of the slice should be exposed - ```diff - - import { Form } from "features/auth-form/components/view/form" - ``` +The last goal has some important practical implications. It may be tempting to create wildcard re-exports of everything, especially in early development of the slice, because any new objects you export from your files are also automatically exported from the slice: -- **Good:** The API exports only what is necessary and allowed in advance, the module developer now needs to think only about not breaking the Public API when refactoring - - ```diff - + import { AuthForm } from "features/auth-form" - ``` - -### 2. Sustainability for changes - -The public API should be sustainable for changes inside the module - -- Breaking changes in the behavior of the module are reflected in the change of the Public API - -#### Examples - -##### Abstracting from the implementation - -Changing the internal structure should not lead to a change in the Public API - -- **Bad:** moving or renaming this component inside the feature will lead to the need to refactor imports in all places where the component is used. +```js title="Bad practice, features/comments/index.js" +// ❌ BAD CODE BELOW, DON'T DO THIS +export * from "./ui/Comment"; // 👎 don't try this at home +export * from "./model/comments"; // 💩 this is bad practice +``` - ```diff - - import { Form } from "features/auth-form/ui/form" - ``` +This hurts the discoverability of a slice because you can't easily tell what the interface of this slice is. Not knowing the interface means that you have to dig deep into the code of a slice to understand how to integrate it. Another problem is that you might accidentally expose the module internals accidentally, which will make refactoring difficult if someone starts depending on them. -- **Good:** the interface of the feature does not display its internal structure, external "users" of the feature will not suffer from moving or renaming the component inside the feature +## Public API for cross-imports {#public-api-for-cross-imports} - ```diff - + import { AuthForm } from "features/auth-form" - ``` +Cross-imports are a situation when one slice imports from another slice on the same layer. Usually that is prohibited by the [import rule on layers][import-rule-on-layers], but often there are legitimate reasons to cross-import. For example, business entities often reference each other in the real world, and it's best to reflect these relationships in the code instead of working around them. -### 3. Integrability +For this purpose, there's a special kind of public API, also known as the `@x`-notation. If you have entities A and B, and entity B needs to import from entity A, then entity A can declare a separate public API just for entity B. -The public API should facilitate **easy and flexible integration** +- `📂 entities` + - `📂 A` + - `📂 @x` + - `📄 B.ts` — a special public API just for code inside `entities/B/` + - `📄 index.ts` — the regular public API -- Should be convenient for use by the rest of the application, in particular, to solve the problem of name collisions +Then the code inside `entities/B/` can import from `entities/A/@x/B`: -#### Examples +```ts +import type { EntityA } from "entities/A/@x/B"; +``` -##### Name collision +The notation `A/@x/B` is meant to be read as "A crossed with B". -- **Bad:** there will be a name collision +:::note - ```ts title="features/auth-form/index.ts" - export { Form } from "./ui" - export * as model from "./model" - ``` +Try to keep cross-imports to a minimum, and **only use this notation on the Entities layer**, where eliminating cross-imports is often unreasonable. - ```ts title="features/post-form/index.ts" - export { Form } from "./ui" - export * as model from "./model" - ``` +::: - ```diff - - import { Form, model } from "features/auth-form" - - import { Form, model } from "features/post-form" - ``` +## Issues with index files -- **Good:** the collision is solved at the interface level +Index files like `index.js`, also known as barrel files, are the most common way to define a public API. They are easy to make, but they are known to cause problems with certain bundlers and frameworks. - ```ts title="features/auth-form/index.ts" - export { Form as AuthForm } from "./ui" - export * as authFormModel from "./model" - ``` +### Circular imports - ```ts title="features/post-form/index.ts" - export { Form as PostForm } from "./ui" - export * as postFormModel from "./model" - ``` +Circular import is when two or more files import each other in a circle. - ```diff - + import { AuthForm, authFormModel } from "features/auth-form" - + import { PostForm, postFormModel } from "features/post-form" - ``` + -##### Flexible use +
+ Three files importing each other in a circle + Three files importing each other in a circle +
+ Pictured above: three files, `fileA.js`, `fileB.js`, and `fileC.js`, importing each other in a circle. +
+
-- **Bad:** it is inconvenient to write, it is inconvenient to read, the" user " of the feature suffers +These situations are often difficult for bundlers to deal with, and in some cases they might even lead to runtime errors that might be difficult to debug. - ```diff - - import { storeActionUpdateUserDetails } from "features/auth-form" - - dispatch(storeActionUpdateUserDetails(...)) - ``` +Circular imports can occur without index files, but having an index file presents a clear opporutnity to accidentally create a circular import. It often happens when you have two objects exposed in the public API of a slice, for example, `HomePage` and `loadUserStatistics`, and the `HomePage` needs to access `loadUserStatistics`, but it does it like this: -- **Good:** the "user" of the feature gets access to the necessary things iteratively and flexibly +```jsx title="pages/home/ui/HomePage.jsx" +import { loadUserStatistics } from "../"; // importing from pages/home/index.js - ```diff - + import { authFormModel } from "features/auth-form" - + dispatch(authFormModel.effects.updateUserDetails(...)) // redux - + authFormModel.updateUserDetailsFx(...) // effector - ``` +export function HomePage() { /* … */ } +``` -##### Resolution of collisions +```js title="pages/home/index.js" +export { HomePage } from "./ui/HomePage"; +export { loadUserStatistics } from "./api/loadUserStatistics"; +``` -Name collisions should be resolved at the level of the public interface, not the implementation +This situation creates a circular import, because `index.js` imports `ui/HomePage.jsx`, but `ui/HomePage.jsx` imports `index.js`. -- **Bad:** name collisions are resolved at the implementation level +To prevent this issue, consider these two principles. If you have two files, and one imports from the other: +- When they are in the same slice, always use _relative_ imports and write the full import path +- When they are in different slices, always use _absolute_ imports, for example, with an alias - ```ts title="features/auth-form/index.ts" - export { AuthForm } from "./ui" - export { authFormActions, authFormReducer } from "model" - ``` +### Large bundles and broken tree-shaking in Shared {#large-bundles} - ```ts title="features/post-form/index.ts" - export { PostForm } from "./ui" - export { postFormActions, postFormReducer } from "model" - ``` +Some bundlers might have a hard time tree-shaking (removing code that isn't imported) when you have an index file that re-exports everything. -- **Good:** name collisions are resolved at the interface level +Usually this isn't a problem for public APIs, because the contents of a module are usually quite closely related, so you would rarely need to import one thing and tree-shake away the other. However, there are two very common cases when the normal rules of public API in FSD may lead to issues — `shared/ui` and `shared/lib`. - ```ts title="features/auth-form/model.ts" - export { actions, reducer } - ``` +These two folders are both collections of unrelated things that often aren't all needed in one place. For example, `shared/ui` might have modules for every component in the UI library: - ```ts title="features/auth-form/index.ts" - export { Form as AuthForm } from "./ui" - export * as authFormModel from "./model" - ``` +- `📂 shared/ui/` + - `📁 button` + - `📁 text-field` + - `📁 carousel` + - `📁 accordion` - ```ts title="features/post-form/model.ts" - export { actions, reducer } - ``` +This problem is made worse when one of these modules has a heavy dependency, like a syntax highlighter or a drag'n'drop library. You don't want to pull those into every page that uses something from `shared/ui`, for example, a button. - ```ts title="features/post-form/index.ts" - export { Form as PostForm } from "./ui" - export * as postFormModel from "./model" - ``` +If your bundles grow undesirably due to a single public API in `shared/ui` or `shared/lib`, it's recommended to instead have a separate index file for each component or library: -## About re-exports +- `📂 shared/ui/` + - `📂 button` + - `📄 index.js` + - `📂 text-field` + - `📄 index.js` -In JavaScript, the public interface of a module is created by re-exporting entities from inside the module in an `index` file: +Then the consumers of these components can import them directly like this: -```ts title="**/**/index.ts" -export { Form as AuthForm } from "./ui" -export * as authModel from "./model" +```js title="pages/sign-in/ui/SignInPage.jsx" +import { Button } from '@/shared/ui/button'; +import { TextField } from '@/shared/ui/text-field'; ``` -### Disadvantages +### No real protection against side-stepping the public API + +When you create an index file for a slice, you don't actually forbid anyone from not using it and importing directly. This is especially a problem for auto-imports, because there are several places from which an object can be imported, so the IDE has to decide that for you. Sometimes it might choose to import directly, breaking the public API rule on slices. -- In most popular bundlers, due to re-exports, **the code-splitting works worse**, because [tree-shaking](https://webpack.js.org/guides/tree-shaking/) with this approach, it is safe to discard only the entire module, but not part of it. - > For example, importing `authModel` into the page model will cause the `AuthForm` component to get into the chunk of this page, even if this component is not used there. +To catch these issues automatically, we recommend using [Steiger][ext-steiger], an architectural linter with a ruleset for Feature-Sliced Design. -- As a result, initialization of the chunk becomes more expensive, because the browser must process all the modules in it, including those that got into the bundle "for the company" +### Worse performance of bundlers on large projects -### Possible solutions +Having a large amount of index files in a project can slow down the development server, as noted by TkDodo in [his article "Please Stop Using Barrel Files"][ext-please-stop-using-barrel-files]. -- `webpack` allows you to mark re-export files as [**side effects free**](https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free) - this allows `webpack` to use more aggressive optimizations when working with such a file +There are several things you can do to tackle this issue: +1. The same advice as in ["Large bundles and broken tree-shaking in Shared" issue](#large-bundles) — have separate index files for each component/library in `shared/ui` and `shared/lib` instead of one big one +2. Avoid having index files in segments on layers that have slices. + For example, if you have an index for the feature "comments", `📄 features/comments/index.js`, there's no reason to have another index for the `ui` segment of that feature, `📄 features/comments/ui/index.js`. +3. If you have a very big project, there's a good chance that your application can be split into several big chunks. + For example, Google Docs has very different responsibilities for the document editor and for the file browser. You can create a monorepo setup where each package is a separate FSD root, with its own set of layers. Some packages can only have the Shared and Entities layers, others might only have Pages and App, others still might include their own small Shared, but still use the big one from another package too. -## See also + -- [(Discussion) Public Abstraction API][disc-src] -- [Principles **SOLID**][ext-solid] -- [Patterns **GRASP**][ext-grasp] + -[disc-src]: https://github.com/feature-sliced/documentation/discussions/41 -[ext-solid]: https://ru.wikipedia.org/wiki/SOLID -[ext-grasp]: https://ru.wikipedia.org/wiki/GRASP +[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers +[ext-steiger]: https://github.com/feature-sliced/steiger +[ext-please-stop-using-barrel-files]: https://tkdodo.eu/blog/please-stop-using-barrel-files diff --git a/i18n/en/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx b/i18n/en/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx index 01aeb65e24..faa27f9d82 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx @@ -8,50 +8,64 @@ pagination_next: reference/public-api ## Slices -Slices are the second level in the organizational hierarchy of Feature-Sliced Design. Their main purpose is to group code by its meaning for the product, business or just the application. +Slices are the second level in the organizational hierarchy of Feature-Sliced Design. Their main purpose is to group code by its meaning for the product, business, or just the application. -The names of slices are not standardized because they are directly determined by the business domain of your application. For example, a photo gallery might have slices `photo`, `create-album`, `gallery-page`. A social network would require different slices, for example, `post`, `add-user-to-friends`, `news-feed`. +The names of slices are not standardized because they are directly determined by the business domain of your application. For example, a photo gallery might have slices `photo`, `effects`, `gallery-page`. A social network would require different slices, for example, `post`, `comments`, `news-feed`. -Closely related slices can be structurally grouped in a directory, but they should exercise the same isolation rules as other slices — there should be **no code sharing** in that directory. +The layers Shared and App don't contain slices. That is because Shared should contain no business logic at all, hence has no meaning for the product, and App should contain only code that concerns the entire application, so no splitting is necessary. -![Features "compose", "like" and "delete" grouped in a directory "post". In that directory there is also a file "some-shared-code.ts" that is crossed out to imply that it's not allowed.](/img/graphic-nested-slices.svg) +### Zero coupling and high cohesion {#zero-coupling-high-cohesion} -The layers Shared and App don't contain slices. That is because Shared should contain no business logic at all, hence has no meaning for the product, and App should contain only code that concerns the entire application, so no splitting is necessary. +Slices are meant to be independent and highly cohesive groups of code files. The graphic below might help to visualize the tricky concepts of _cohesion_ and _coupling_: + +
+ + +
+ Image inspired by https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/ +
+
+ +An ideal slice is independent from other slices on its layer (zero coupling) and contains most of the code related to its primary goal (high cohesion). + +The independence of slices is enforced by the [import rule on layers][layers--import-rule]: + +> _A module (file) in a slice can only import other slices when they are located on layers strictly below._ ### Public API rule on slices -Inside a slice, the code could be organized very liberally, and that doesn't pose any issues as long as the slice provides a good public API. This is enforced with the **public API rule on slices**: +Inside a slice, the code could be organized in any way that you want. That doesn't pose any issues as long as the slice provides a good public API for other slices to use it. This is enforced with the **public API rule on slices**: > _Every slice (and segment on layers that don't have slices) must contain a public API definition._ > > _Modules outside of this slice/segment can only reference the public API, not the internal file structure of the slice/segment._ -Read more about the rationale of public APIs and the best practices on creating one in the [Public API reference][ref--public-api]. +Read more about the rationale of public APIs and the best practices on creating one in the [Public API reference][ref-public-api]. + +### Slice groups + +Closely related slices can be structurally grouped in a folder, but they should exercise the same isolation rules as other slices — there should be **no code sharing** in that folder. + +![Features "compose", "like" and "delete" grouped in a folder "post". In that folder there is also a file "some-shared-code.ts" that is crossed out to imply that it's not allowed.](/img/graphic-nested-slices.svg) ## Segments Segments are the third and final level in the organizational hierarchy, and their purpose is to group code by its technical nature. There a few standardized segment names: -* `ui` — UI components, data formatting functions -* `model` — business logic and data storage, as well as functions to manipulate this data -* `lib` — auxiliary and infrastructural code -* `api` — communication with external APIs, backend API methods -Custom segments are permitted, but should be created sparingly. The most common places for custom segments are the App layer and the Shared layer, where slices don't make sense. +- `ui` — everything related to UI display: UI components, date formatters, styles, etc. +- `api` — backend interactions: request functions, data types, mappers, etc. +- `model` — the data model: schemas, interfaces, stores, and business logic. +- `lib` — library code that other modules on this slice need. +- `config` — configuration files and feature flags. -### Examples +See the [Layers page][layers--layer-definitions] for examples of what each of these segments might be used for on different layers. -| Layer | `ui` | `model` | `lib` | `api` | -| :------- | :----------- | :----------- | :----------- | :----------- | -| Shared | UI kit | Usually not used | Utility modules of several related files.
If you need to use individual helpers, consider using utility libraries such as [`lodash-es`][ext--lodash]. | Rudimentary API client with additional features like authentication or caching. | -| Entities | Skeleton of a business entity with slots for interactive elements | Data storage of instances of this entity as well as functions for manipulating that data.
This segment is most fit for storing server-side data. If you use [TanStack Query][ext--tanstack-query] or other methods of implicit storage, you may choose to omit this segment. | Functions for manipulating instances of this entity that aren't related to storage | API methods using the API client from Shared for easy communication with the backend | -| Features | Interactive elements that enable users to use this feature | Business logic and infrastructure data storage, if needed (e.g., current app theme). This is the code that actually produces value for the user. | Infrastructural code that helps to concisely describe the business logic in the `model` segment | API methods that represent this feature on the backend.
May compose API methods from Entities. | -| Widgets | Composition of Entities and Features into self-contained UI blocks.
Can also contain error boundaries and loading states. | Infrastructure data storage, if needed | Non-business interactions (e.g., gestures) and other necessary code for the block to function on a page | Usually not used, but can contain data loaders in nested routing contexts (e.g., [Remix][ext--remix]) | -| Pages | Composition of Entities, Features and Widgets into complete pages.
Can also contain error boundaries and loading states. | Usually not used | Non-business interactions (e.g., gestures) and other necessary code for the page to deliver a complete user experience | Data loaders for SSR-oriented frameworks | +You can also create custom segments. The most common places for custom segments are the App layer and the Shared layer, where slices don't make sense. -[ref--public-api]: /docs/reference/public-api +Make sure that the name of these segments describes the purpose of the content, not its essence. For example, `components`, `hooks`, and `types` are bad segment names because they aren't that helpful when you're looking for code. -[ext--lodash]: https://www.npmjs.com/package/lodash-es -[ext--tanstack-query]: https://tanstack.com/query/latest -[ext--remix]: https://remix.run +[layers--layer-definitions]: /docs/reference/layers#layer-definitions +[layers--import-rule]: /docs/reference/layers#import-rule-on-layers +[ref-public-api]: /docs/reference/public-api diff --git a/i18n/ja/docusaurus-plugin-content-docs/current.json b/i18n/ja/docusaurus-plugin-content-docs/current.json index d991f18054..7585aa991d 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current.json +++ b/i18n/ja/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "v2.0.0 🍰", + "message": "v2.1", "description": "現在のバージョンのラベル" }, "sidebar.getstartedSidebar.category.🚀 Get Started": { diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md index 062f018fed..8d24ada9e0 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/faq.md @@ -13,7 +13,7 @@ pagination_next: guides/index ### ツールキットやリンターはありますか? {#is-there-a-toolkit-or-a-linter} -公式のESLintコンフィグ — [@feature-sliced/eslint-config][eslint-config-official]、およびコミュニティメンバーのアレクサンドル・ベロウスによって作成されたESLintプラグイン — [@conarti/eslint-plugin-feature-sliced][eslint-plugin-conarti]があります。これらのプロジェクトへの貢献や独自のツールの作成を歓迎します! +はい!CLI または IDE を通じてプロジェクトのアーキテクチャと [フォルダー ジェネレーター][ext-tools] をチェックするための [Steiger][ext-steiger] というリンターがあります。 ### ページのレイアウト/テンプレートはどこに保存すればよいですか? {#where-to-store-the-layouttemplate-of-pages} @@ -58,10 +58,10 @@ FSDは、プロジェクトの主要な価値を提供するコンポーネン [こちら](/docs/guides/examples/auth)で回答しています。 +[ext-steiger]: https://github.com/feature-sliced/steiger +[ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools [import-rule-layers]: /docs/reference/layers#import-rule-on-layers [reference-entities]: /docs/reference/layers#entities -[eslint-config-official]: https://github.com/feature-sliced/eslint-config -[eslint-plugin-conarti]: https://github.com/conarti/eslint-plugin-feature-sliced [motivation]: /docs/about/motivation [telegram]: https://t.me/feature_sliced [discord]: https://discord.gg/S8MzWTUsmp diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md index 4387ebba47..d6003f47d2 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md @@ -144,7 +144,7 @@ v2では、**ロジックの複雑さと強い結合の問題を解消するた - [React Berlin Talk - Oleg Isonen "Feature Driven Architecture"][ext-kof-fdd] -[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion +[refs-low-coupling]: /docs/reference/slices-segments#zero-coupling-high-cohesion [refs-adaptability]: /docs/about/understanding/naming [ext-fdd]: https://github.com/feature-sliced/documentation/tree/rc/feature-driven diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx index 86d8f4b2c1..577abbd725 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/index.mdx @@ -24,15 +24,9 @@ FSDの重要な概念に関するセクション to="/docs/reference/slices-segments" Icon={AppstoreOutlined} /> - \ No newline at end of file +/> diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md index 7b6be93160..ff23863bcd 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md @@ -18,7 +18,7 @@ FSDでは、以下の方法で達成されます。 * アプリケーションを層とスライスに分割する - 特定の機能を実現するモジュール。 * 各モジュールには、[公開API][refs-public-api]を提供することが求められます。 -* モジュール間の[相互作用][refs-isolation]に特別な制限を設ける - 各モジュールは「下位」のモジュールにのみ依存でき、同じ層またはそれ以上の層のモジュールには依存できません。 +* モジュール間の相互作用に特別な制限を設ける - 各モジュールは「下位」のモジュールにのみ依存でき、同じ層またはそれ以上の層のモジュールには依存できません。 ## コンポーネントの構成(UIレベル) {#components-composition-ui-level} @@ -144,4 +144,3 @@ export const { sendMessage, attachFile } = createMessageInput({ * [(プレゼンテーション) 設計原則について(低結合と高凝集を含む)](https://www.slideshare.net/cristalngo/software-design-principles-57388843) [refs-public-api]: /docs/reference/public-api -[refs-isolation]: /docs/reference/isolation diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md index 70de1bb20d..cb6c499f85 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md @@ -54,10 +54,8 @@ TODO 方法論の経験を積んだ後、このセクションをより詳細に ## 参照 {#see-also} -- [(ガイド) 低い結合性の達成について][refs-low-coupling] - [(ディスカッション) 方法論におけるエンティティとその結合性](https://github.com/feature-sliced/documentation/discussions/49) - [(ディスカッション) クロスインポートと依存関係の分析について](https://github.com/feature-sliced/documentation/discussions/65#discussioncomment-480822) - [パターン **GRASP**](https://ru.wikipedia.org/wiki/GRASP) [refs-public-api]: /docs/reference/public-api -[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion \ No newline at end of file diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md index c244282277..4b1d8468f4 100644 --- a/i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md +++ b/i18n/kr/docusaurus-plugin-content-docs/current/get-started/faq.md @@ -13,7 +13,7 @@ pagination_next: guides/index ### toolkit이나 linter가 있나요? -공식 ESLint 설정인 [@feature-sliced/eslint-config][eslint-config-official]와 커뮤니티 멤버인 Aleksandr Belous가 만든 ESLint 플러그인 [@conarti/eslint-plugin-feature-sliced][eslint-plugin-conarti]가 있습니다. 이 프로젝트들에 기여하거나 여러분만의 프로젝트를 시작해보세요! +네! 우리는 CLI 또는 IDE를 통해 프로젝트의 아키텍처와 [폴더 생성기][ext-tools]를 확인하기 위한 [Steiger][ext-steiger]라는 linter를 가지고 있습니다. ### Where to store the layout/template of pages? @@ -59,10 +59,10 @@ pagination_next: guides/index [여기](/docs/guides/examples/auth)에서 답변했습니다. +[ext-steiger]: https://github.com/feature-sliced/steiger +[ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools [import-rule-layers]: /docs/reference/layers#import-rule-on-layers [reference-entities]: /docs/reference/layers#entities -[eslint-config-official]: https://github.com/feature-sliced/eslint-config -[eslint-plugin-conarti]: https://github.com/conarti/eslint-plugin-feature-sliced [motivation]: /docs/about/motivation [telegram]: https://t.me/feature_sliced [discord]: https://discord.gg/S8MzWTUsmp diff --git a/i18n/ru/docusaurus-plugin-content-docs/current.json b/i18n/ru/docusaurus-plugin-content-docs/current.json index 6487d3a7d4..0ecd0d7164 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current.json +++ b/i18n/ru/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "v2.0.0 🍰", + "message": "v2.1", "description": "The label for version current" }, "sidebar.getstartedSidebar.category.🚀 Get Started": { diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/faq.md b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/faq.md index f5ea8d3154..1a51f0c1d8 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/faq.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/faq.md @@ -13,7 +13,7 @@ pagination_next: guides/index ### Существует ли тулкит или линтер? {#is-there-a-toolkit-or-a-linter} -Есть официальный конфиг для ESLint — [@feature-sliced/eslint-config][eslint-config-official], и плагин для ESLint — [@conarti/eslint-plugin-feature-sliced][eslint-plugin-conarti], созданный участником сообщества Александром Белоусом. Мы будем рады вашим вкладам в эти проекты или созданию своих! +Да! У нас есть линтер [Steiger][ext-steiger] для проверки архитектуры вашего проекта и [генераторы папок][ext-tools] через CLI или IDE. ### Где хранить layout/template страниц? {#where-to-store-the-layouttemplate-of-pages} @@ -58,10 +58,10 @@ _Entity_ — это понятие из реальной жизни, с кото Ответили [здесь](/docs/guides/examples/auth) +[ext-steiger]: https://github.com/feature-sliced/steiger +[ext-tools]: https://github.com/feature-sliced/awesome?tab=readme-ov-file#tools [import-rule-layers]: /docs/reference/layers#import-rule-on-layers [reference-entities]: /docs/reference/layers#entities -[eslint-config-official]: https://github.com/feature-sliced/eslint-config -[eslint-plugin-conarti]: https://github.com/conarti/eslint-plugin-feature-sliced [motivation]: /docs/about/motivation [telegram]: https://t.me/feature_sliced [discord]: https://discord.gg/S8MzWTUsmp diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md index 5063269dee..6638f7d837 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -39,7 +39,7 @@ sidebar_position: 2 Ключевое отличие Feature-Sliced Design от произвольной структуры кода заключается в том, что страницы не могут зависеть друг от друга. То есть одна страница не может импортировать код с другой страницы. Это связано с **правилом импорта для слоёв**: -*Модуль в слайсе может импортировать другие слайсы только в том случае, если они расположены на слоях строго ниже.* +*Модуль (файл) в слайсе может импортировать другие слайсы только в том случае, если они расположены на слоях строго ниже.* В этом случае страница является слайсом, поэтому модули (файлы) внутри этой страницы могут импортировать код только из слоев ниже, а не из других страниц. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/auth.md b/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/auth.md index 1b09d12279..1807b69aed 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/auth.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/auth.md @@ -189,7 +189,7 @@ export function login({ email, password }: { email: string, password: string }) Поскольку API-клиент обычно размещается в `shared/api` или распределяется между сущностями, главной проблемой этого подхода является обеспечение доступа к токену для других запросов, не нарушая при этом [правило импортов для слоёв][import-rule-on-layers]: -> Модуль в слайсе может импортировать другие слайсы только в том случае, если они расположены на слоях строго ниже. +> Модуль (файл) в слайсе может импортировать другие слайсы только в том случае, если они расположены на слоях строго ниже. Есть несколько решений этой проблемы: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md index 917e7466b3..a348c40303 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 1 sidebar_label: С кастомной архитектуры --- diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md index f7b3d77f9d..5613ab5d27 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 2 --- # Миграция с v1 @@ -157,7 +157,7 @@ sidebar_position: 4 - [Новые идеи v2 с пояснениями (atomicdesign-chat)][ext-tg-v2-draft] - [Обсуждение абстракций и нейминга для новой версии методологии (v2)](https://github.com/feature-sliced/documentation/discussions/31) -[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion +[refs-low-coupling]: /docs/reference/slices-segments#zero-coupling-high-cohesion [refs-adaptability]: /docs/about/understanding/naming [ext-v1]: https://feature-sliced.github.io/featureslices.dev/v1.0.html diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md new file mode 100644 index 0000000000..371843d981 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 3 +--- + +# Миграция с v2.0 на v2.1 + +Основным изменением в v2.1 является новая ментальная модель разложения интерфейса — сначала страницы. + +В версии FSD 2.0 рекомендовалось найти сущности и фичи в вашем интерфейсе, рассматривая даже малейшие части представления сущностей и интерактивность как кандидаты на декомпозицию. Затем вы бы могли строить виджеты и страницы из сущностей и фич. В этой модели декомпозиции большая часть логики находилась в сущностях и фичах, а страницы были просто композиционными слоями, которые сами по себе не имели большого значения. + +В версии FSD 2.1 мы рекомендуем начинать со страниц, и возможно даже на них и остановиться. Большинство людей уже знают, как разделить приложение на страницы, и страницы также часто являются отправной точкой при попытке найти компонент в кодовой базе. В новой модели декомпозиции вы храните большую часть интерфейса и логики в каждой отдельной странице, а повторно используемый фундамент — в Shared. Если возникнет необходимость переиспользования бизнес-логики на нескольких страницах, вы можете переместить её на слой ниже. + +Другим нововведением в Feature-Sliced Design 2.1 является стандартизация кросс-импортов между сущностями с помощью `@x`-нотации. + +## Как мигрировать {#how-to-migrate} + +В версии 2.1 нет ломающих изменений, что означает, что проект, написанный с использованием FSD v2.0, также является валидным проектом в FSD v2.1. Однако мы считаем, что новая ментальная модель более полезна для команд и особенно для обучения новых разработчиков, поэтому рекомендуем внести небольшие изменения в вашу декомпозицию. + +### Соедините слайсы + +Простой способ начать — запустить на проекте наш линтер, [Steiger][steiger]. Steiger построен с новой ментальной моделью, и наиболее полезные правила будут: + +- [`insignificant-slice`][insignificant-slice] — если сущность или фича используется только на одной странице, это правило предложит целиком переместить код этой сущности или фичи прямо в эту страницу. +- [`excessive-slicing`][excessive-slicing] — если у слоя слишком много слайсов, это обычно означает, что декомпозиция слишком мелкая. Это правило предложит объединить или сгруппировать некоторые слайсы, чтобы помочь в навигации по проекту. + +```bash +npx steiger src +``` + +Это поможет вам определить, какие слайсы используются только один раз, чтобы вы могли ещё раз подумать, действительно ли они необходимы. Помните, что слой формирует своего рода глобальное пространство имен для всех слайсов внутри него. Точно так же, как вы не захотите загрязнять глобальное пространство имен переменными, которые используются только один раз, вы должны относиться к месту в пространстве имен слоя как к ценному месту, которое следует использовать сдержанно. + +### Стандартизируйте кросс-импорты + +Если у вас были кросс-импорты в вашем проекте до этого (мы не осуждаем!), вы теперь можете воспользоваться новой нотацией для кросс-импортов в Feature-Sliced Design — `@x`-нотацией. Она выглядит так: + +```ts title="entities/B/some/file.ts" +import type { EntityA } from "entities/A/@x/B"; +``` + +Чтоб узнать больше об этом, обратитесь к разделу [Публичный API для кросс-импортов][public-api-for-cross-imports] в разделе справочника. + +[insignificant-slice]: https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/insignificant-slice +[steiger]: https://github.com/feature-sliced/steiger +[excessive-slicing]: https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/excessive-slicing +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx index 6312615359..10f8ffcda4 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/reference/index.mdx @@ -24,15 +24,9 @@ import { ApiOutlined, GroupOutlined, AppstoreOutlined, NodeIndexOutlined } from to="/docs/reference/slices-segments" Icon={AppstoreOutlined} /> - diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml b/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml deleted file mode 100644 index 2baf3c4c0a..0000000000 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml +++ /dev/null @@ -1 +0,0 @@ -label: Изоляция diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md b/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md deleted file mode 100644 index 62cac23dcd..0000000000 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Low Coupling & High Cohesion - -Модули приложения должны проектироваться как обладающие **сильной связностью** (направленные на решение одной четкой задачи) и **слабой зацепленностью** (как можно менее зависимые от других модулей) - -
- - -
- Иллюстрация вдохновлена статьей https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/ -
-
- -В рамках методологии это достигается через: - -* Разбиение приложения на слои и слайсы - модули, реализующие конкретную функциональность. -* Требование к каждому модулю - предоставлять [публичный интерфейс доступа][refs-public-api] -* Введение специальных ограничений на [взаимодействие модулей между собой][refs-isolation] - каждый модуль может зависеть только от "нижележащих" модулей, но не от модулей с того же или более высокого слоя. - -## Композиция компонентов (UI level) {#components-composition-ui-level} - -Абсолютное большинство современных UI-фреймворков и библиотек предоставляют компонентную модель, в которой каждый компонент может иметь собственные свойства, собственное состояние и дочерние компоненты, а также, зачастую, слоты. - -Такая модель позволяет собирать интерфейс как **композицию различных, напрямую не связанных между собой компонентов** и, тем самым, достигать **слабой зацепленности** компонентов интерфейса - -### Пример {#example} - -Рассмотрим такую композицию на примере **списка с хедером:** - -#### Закладываем расширяемость {#laying-the-extensibility} - -Компонент списка не будет сам определять вид и структуру компонентов хедера и элементов списка, вместо этого будет принимать их в качестве параметров - -```tsx -interface ListProps { - Header: React.ReactNode; - Items: React.ReactNode; -} - -const List: Component = ({ Header, Items }) => ( -
- {Header} -
    - {Items} -
-
-) - -``` - -#### Используем композицию {#using-the-composition} - -Это позволяет **переиспользовать и независимо изменять** компоненты различных версий хедера и элементов списка. Компоненты хедера и элементов списка могут иметь как свое локальное состояние, так и свою привязку к любым частям общего состояния приложения - компонент списка не будет ничего про это знать, а следовательно, не будет от этого зависеть - -```tsx -} Items={} /> - -} /> - -} Items={} /> - -``` - -## Композиция слоев (APP level) {#layer-composition-app-level} - -Методология предлагает разделять ценную для пользователя функциональность на отдельные модули - **фичи (features)**, а логику, относящуюся к бизнес сущностям - в **сущности (entities)**. И фичи, и сущности **должны проектироваться как высоко-связные модули**, т.е. направленные на решение **одной конкретной задачи** или сконцентрированные вокруг **одной конкретной сущности.** - -Все взаимодействия между такими модулями, аналогично UI-компонентам из примера выше, должны быть организованы как **композиция различных модулей.** - -### Пример {#example} - -На примере приложения-чата с такими возможностями - -* можно открыть список контактов и выбрать друга -* можно открыть переписку с выбранным другом - -В рамках методологии, это может быть представлено примерно так: - -Entities - -* Пользователь (содержит состояние пользователя) -* Контакт (состояние списка контактов, инструменты для работы с отдельным контактом) -* Переписка (состояние текущей переписки и работа с ней) - -Features - -* Форма отправки сообщения -* Меню выбора переписки - -#### Свяжем все это вместе {#lets-tie-it-all-together} - -В приложении, для начала, будет одна страница, интерфейс будет основан на слегка модифицированном компоненте из первого примера - -```tsx title="page/main/ui.tsx" -} - Items={} - Footer={} -/> -``` - -#### Модель данных {#data-model} - -Модель данных страницы будет организована как **композиция фич и сущностей**. В рамках этого примера фичи будут реализованы как фабрики и получать доступ к интерфейсу сущностей через параметры этих фабрик. - -> Однако, реализация в виде фабрики необязательна - фича может зависеть от нижележащих слоев и напрямую - -```ts title="pages/main/model.ts" -import { userModel } from "entitites/user" -import { conversationModel } from "entities/conversation" -import { contactModel } from "entities/contact" - -import { createMessageInput } from "features/message-input" -import { createConversationSwitch } from "features/conversation-switch" - -import { beautifiy } from "shared/lib/beautify-text" - -export const { allConversations, setConversation } = createConversationSwitch({ - contacts: contactModel.allContacts, - setConversation: conversationModel.setConversation, - currentConversation: conversationModel.conversation, - currentUser: userModel.currentUser -}) - -export const { sendMessage, attachFile } = createMessageInput({ - author: userModel.currentUser - send: conversationModel.sendMessage, - formatMessage: beautify -}) -``` - -## Итого {#summary} - -1. Модули должны обладать **сильной связностью** (иметь одну ответственность, решать одну конкретную задачу) и предоставлять [**публичный интерфейс**][refs-public-api] доступа -2. **Слабая зацепленность** достигается через композицию элементов - компонентов UI, фич и сущностей -3. Также, для снижения зацепленности, модули **должны зависеть друг от друга только через публичные интерфейсы** - так достигается независимость модулей от внутренней реализации друг друга - -## См. также {#see-also} - -* [(Статья) Про Low Coupling и High Cohesion наглядно](https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/) - * *Схема в начале вдохновлена именно этой статьей* -* [(Статья) Low Coupling и High Cohesion. Закон Деметры](https://medium.com/german-gorelkin/low-coupling-high-cohesion-d36369fb1be9) -* [(Презентация) Про принципы проектирования (включая Low Coupling & High Cohesion)](https://www.slideshare.net/cristalngo/software-design-principles-57388843) - -[refs-public-api]: /docs/reference/public-api -[refs-isolation]: /docs/reference/isolation diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx deleted file mode 100644 index 46b2c1e093..0000000000 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -sidebar_position: 2 -sidebar_class_name: sidebar-item--wip ---- - -import WIP from '@site/src/shared/ui/wip/tmpl.mdx' - -# Decouple entities - - - -> Про кросс-импорты типов, адаптеры и про то - как явно выстраивать связи между сущностями - -> Также про мифические absolutely-decoupled entities - -## См. также {#see-also} - -- [(Тред) Памятка про декомпозицию по сущностям и выстраивание явных связей между ними](https://t.me/feature_sliced/3633) -- [(Тред) Пример декомпозиции для "связных сущностей" (users/pets/friends)](https://t.me/feature_sliced/3316) -- [(Тред) Про кросс-импорты типов/адаптеров в сущностях](https://t.me/feature_sliced/4276) -- [(Тред) Про границы сущностей и фич](https://t.me/feature_sliced/4521) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/index.md deleted file mode 100644 index 4281508ba9..0000000000 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/isolation/index.md +++ /dev/null @@ -1,63 +0,0 @@ -# Изоляция модулей - -В рамках методологии все модули распределены по зонам ответственности (layer, slice, segment) - -Слои, в свою очередь, организованы вертикально: - -- "Внизу" находятся переиспользуемые модули (ui-kit, внутренние библиотеки проекта), как наиболее абстрактные -- А по мере продвижения "вверх" располагаются более специфичные модули. - -Независимо от принадлежности к какому-либо слайсу, каждый модуль [**обязан предоставлять публичный интерфейс доступа**][refs-public-api]. - -## Требования {#requirements} - -Взаимодействие каждого модуля с остальным приложением проектируется с учетом ряда требований: - -1. **Слабое зацепление** с другими модулями - - *Изменение в одном модуле должно слабо и предсказуемо влиять на другие* -1. **Высокая связность** - обязанности каждого модуля "сфокусированы" на одной задаче - - *Если модуль имеет слишком много ответственностей (начинает "делать слишком много") - это должно быть замечено как можно раньше* -1. **Отсутствие циклических зависимостей** на масштабе всего приложения - - *Часто приводят к неожиданному, нежелательному поведению, лучше избегать их совсем* - -## Правило {#rule} - -Для выполнения этих требований, в рамках методологии, необходимо соблюдать базовое правило: - -:::info Важно - -Модуль может зависеть только от "нижележащих" модулей, но не от модулей с того же или более высокого слоя - -::: - -- `features/auth` **не может** зависеть от `features/filters` **и наоборот** -- `features/auth` **может** зависеть от `shared/ui/button`, **но не наоборот** - -Следование этому правилу позволяет поддерживать зависимости **"однонаправленными"** - что автоматически **исключает циклические импорты** и значительно **упрощает отслеживание зависимостей** между модулями в приложении. - -## Выявление проблем {#identifying-problems} - - -Нарушение этого правила является сигналом проблем: - -1. Модуль имеет **импорт из другого модуля** со своего слоя - - Возможно, модуль был **излишне раздроблен** или имеет **лишнюю ответственность.** - - Следует **объединить** его с импортируемым модулем или **вынести его (частично или целиком) на слой ниже** или перенести логику связей в модули на вышестоящих слоях. -1. Модуль **импортируется многими модулями** со своего слоя - - Возможно, модуль имеет **лишнюю ответственность.** - - Следует **вынести его (частично или целиком) на слой ниже**, либо перенести логику связей в модули на вышестоящих слоях. -1. Модуль **имеет импорты из множества модулей** со своего слоя - - Возможно, модуль принадлежит к **другой области ответственности.** - - Следует **вынести его (частично или целиком) на слой выше**. - -## См. также {#see-also} - -- [(Гайд) Про достижение низкой связанности][refs-low-coupling] -- [(Обсуждение) Entities в методологии и их связность](https://github.com/feature-sliced/documentation/discussions/49) -- [(Обсуждение) Про cross-импорты и анализ зависимостей](https://github.com/feature-sliced/documentation/discussions/65#discussioncomment-480822) -- [Паттерны **GRASP**](https://ru.wikipedia.org/wiki/GRASP) - -[refs-public-api]: /docs/reference/public-api -[refs-low-coupling]: /docs/reference/isolation/coupling-cohesion diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/layers.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/reference/layers.mdx index e22758155f..c8703abcfb 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/layers.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/reference/layers.mdx @@ -5,155 +5,120 @@ pagination_next: reference/slices-segments # Слои -Слои - это первый уровень организационной иерархии в Feature-Sliced Design. Их цель - разделить код на основе того, сколько ответственности ему требуется и от скольких других модулей в приложении он зависит. +Слои - это первый уровень организационной иерархии в Feature-Sliced Design. Их цель - разделить код на основе того, сколько ответственности ему требуется и от скольких других модулей в приложении он зависит. Каждый слой несет особое семантическое значение, чтобы помочь вам определить, сколько ответственности следует выделить вашему коду. -:::note +Всего существует **7 слоев**, расположенных от наибольшей ответственности и зависимости к наименьшей: -На этой странице _модуль_ означает внутренний модуль в приложении - файл или каталог с индексным файлом. Не путать с npm-пакетами. +Дерево файловой системы с одной корневой папкой под названием src и семью подпапками: app, processes, pages, widgets, features, entities, shared. Папка processes слегка выцвечена. +Дерево файловой системы с одной корневой папкой под названием src и семью подпапками: app, processes, pages, widgets, features, entities, shared. Папка processes слегка выцвечена. -::: - -Каждый слой несет в себе особый семантический смысл, помогающий определить, какую ответственность следует возложить на модуль в вашем коде. Названия и значения слоёв стандартизированы для всех проектов, построенных с использованием Feature-Sliced Design. - -Всего существует **7 слоёв**, расположенных от наибольшей ответственности и зависимости к наименьшей: - -Дерево файловой системы с одной корневой папкой src и семью подпапками: app, processes, pages, widgets, features, entities, shared. Папка processes отображена немного тускло. -Дерево файловой системы с одной корневой папкой src и семью подпапками: app, processes, pages, widgets, features, entities, shared. Папка processes отображена немного тускло. - -1. App (Приложение) +1. App (Эпп) 2. Processes (Процессы, устаревший слой) 2. Pages (Страницы) 3. Widgets (Виджеты) 4. Features (Фичи/функции) 5. Entities (Сущности) -6. Shared (Общий) +6. Shared (Шэред) -Вы не обязаны использовать все слои в своем проекте - добавляйте только те, что приносят пользу вашему проекту. +Вы не обязаны использовать все слои в своем проекте - добавляйте только те, что приносят пользу вашему проекту. Как правило, в большинстве фронтенд-проектов будут как минимум слои Shared, Pages и App. -## Правило импортов для слоёв {#import-rule-on-layers} +На практике слои представляют собой папки с названиями в нижнем регистре (например, `📁 shared`, `📁 pages`, `📁 app`). Добавление новых слоев _не рекомендуется_, так как их семантика стандартизирована. -Слои состоят из _слайсов_ — сильно сцепленных групп модулей. Feature-Sliced Design поддерживает низкую связанность, поэтому зависимости между слайсами регулируются **правилом импортов для слоёв**: +## Правило импорта слоев -> _Модуль в слайсе может импортировать другие слайсы только в том случае, если они расположены на слоях строго ниже._ +Слои состоят из _слайсов_ — высокосвязанных групп модулей. Зависимости между слайсами регулируются **правилом импорта слоев**: -Например, в `~/features/aaa`, слайсом является `aaa`, поэтому файл `~/features/aaa/api/request.ts` не может импортировать код ни из какого модуля в папку из `~/features/bbb`, но может импортировать код из `~/entities` и `~/shared`, а также из соседних модулей в `~/features/aaa`. +> _Модуль (файл) в слайсе может импортировать другие слайсы только если они находятся на слоях строго ниже._ + +Например, папка `📁 ~/features/aaa` является слайсом с именем "aaa". Файл внутри нее, `~/features/aaa/api/request.ts`, не может импортировать код из любого файла в `📁 ~/features/bbb`, но может импортировать код из `📁 ~/entities` и `📁 ~/shared`, а также любой код из `📁 ~/features/aaa`, например, `~/features/aaa/lib/cache.ts`. + +Слои App и Shared являются **исключениями** из этого правила — они одновременно являются и слоем, и слайсом. Слайсы разделяют код по бизнес-доменам, и эти два слоя являются исключениями, потому что в Shared нет бизнес-доменов, а App объединяет все бизнес-домены. + +На практике это означает, что слои App и Shared состоят из сегментов, и сегменты могут свободно импортировать друг друга. ## Определения слоёв +В этом разделе описывается семантическое значение каждого слоя, чтобы создать интуитивное представление о том, какой код в нём будет лежать. + ### Shared -Изолированные модули, компоненты и абстракции, отдельные от специфики проекта или бизнеса. -Внимание: не следует использовать этот слой как [свалку утилит][ext--sova-utility-dump]! +Этот слой формирует фундамент для остальной части приложения. Это место для создания связей с внешним миром, например, бэкенды, сторонние библиотеки, среда выполнения приложения (environment). Также это место для ваших собственных библиотек, сконцентрированных на конкретной задаче. -Этот слой, в отличие от других, состоит не из слайсов, а непосредственно из сегментов. +Этот слой, как и слой App, _не содержит слайсов_. Слайсы предназначены для разделения слоя на предметные области, но предметные области не существуют в Shared. Это означает, что все файлы в Shared могут ссылаться и импортировать друг друга. -**Примеры содержимого**: +Вот сегменты, которые вы обычно можете найти в этом слое: -* UI-библиотека -* API-клиент -* Код, работающий с API браузера +- `📁 api` — API-клиент и, возможно, функции для выполнения запросов к конкретным эндпоинтам бэкенда. +- `📁 ui` — UI-кит приложения. + Компоненты на этом слое не должны содержать бизнес-логику, но могут быть тематически связаны с бизнесом. Например, здесь можно разместить логотип компании и макет страницы. Компоненты с UI-логикой также допустимы (например, автозаполнение или строка поиска). +- `📁 lib` — коллекция внутренних библиотек. + Эта папка не должна рассматриваться как хелперы или утилиты ([прочитайте здесь, почему эти папки часто превращаются в свалку][ext-sova-utility-dump]). Вместо этого каждая библиотека в этой папке должна иметь одну область фокуса, например, даты, цвета, манипуляции с текстом и т.д. Эта область фокуса должна быть задокументирована в файле README. Разработчики в вашей команде должны знать, что можно и что нельзя добавлять в эти библиотеки. +- `📁 config` — переменные окружения, глобальные фиче-флаги и другая глобальная конфигурация для вашего приложения. +- `📁 routes` — константы маршрутов или шаблоны для сопоставления маршрутов. +- `📁 i18n` — код, настраивающий систему переводов, а также глобальные строки перевода. + +Вы можете добавлять ещё сегментов, но убедитесь, что название этих сегментов описывает цель содержимого, а не его суть. Например, `components`, `hooks` и `types` — плохие имена сегментов, поскольку они не очень полезны при поиске кода. ### Entities -Понятия из реального мира, которые вместе образуют суть проекта. Как правило, это термины, которые бизнес использует для описания продукта. +Слайсы на этом слое представляют концепции из реального мира, с которыми работает проект. Обычно это термины, которые бизнес использует для описания продукта. Например, социальная сеть может работать с бизнес-сущностями, такими как Пользователь, Публикация и Группа. -Каждый слайс этого слоя содержит статические элементы пользовательского интерфейса, хранилища данных и операции CRUD (создание-чтение-изменение-удаление). +Слайс сущности может содержать хранилище данных (`📁 model`), схемы валидации данных (`📁 model`), функции запросов API, связанные с сущностями (`📁 api`), а также визуальное представление этой сущности в интерфейсе (`📁 ui`). Это визуальное представление не обязательно должно создавать полный блок пользовательского интерфейса — оно в первую очередь предназначено для переиспользования одного и того же внешнего вида на нескольких страницах приложения, и к нему может быть присоединена различная бизнес-логика через пропы или слоты. -**Примеры слайсов**: +#### Связи между сущностями - - -
Для социальной сети Для Git-фронтенда (например, GitHub)
    -
  • Пользователь
  • -
  • Публикация
  • -
  • Группа
  • -
    -
  • Репозиторий
  • -
  • Файл
  • -
  • Коммит
  • -
+Сущности в FSD являются слайсами, и по умолчанию слайсы не могут знать друг о друге. Однако в реальной жизни сущности часто взаимодействуют друг с другом, и иногда одна сущность владеет или содержит другие сущности. Из-за этого бизнес-логику этих взаимодействий лучше всего хранить на более высоких уровнях, таких как Features или Pages. +Когда объект данных одной сущности содержит другие объекты данных, обычно хорошей идеей является сделать связь между сущностями явной и обойти изоляцию слайсов, создав API для кросс-ссылок через `@x`-нотацию. Причина в том, что связанные сущности должны рефакториться вместе, поэтому лучше сделать так, чтоб связь было невозможно не заметить. -:::tip +Например: -Вы можете заметить в примере фронтенда для Git, что _репозиторий_ содержит _файлы_. Это делает репозиторий сущностью более высокого уровня, внутри которой вложены другие сущности. Это частая ситуация с сущностями, и иногда трудно иметь такие сущности высокого уровня, не нарушая правило импортов для слоёв. +```ts title="entities/artist/model/artist.ts" +import type { Song } from "entities/song/@x/artist"; -Вот несколько предложений по решению этой проблемы: -* UI сущностей должен содержать слоты для мест, куда будут вставляться сущности нижнего уровня -* Бизнес-логика, связанная с взаимодействием сущностей, должна быть размещена в Features (в большинстве случаев) -* Интерфейсы сущностей из базы данных могут быть извлечены в слой Shared, рядом с API-клиентом +export interface Artist { + name: string; + songs: Array; +} +``` -::: +```ts title="entities/song/@x/artist.ts" +export type { Song } from "../model/song.ts"; +``` + +Вы можете узнать больше о `@x`-нотации в разделе [Публичный API для кросс-импортов][public-api-for-cross-imports]. ### Features -Действия, которые пользователь может совершать в приложении для взаимодействия с бизнес-сущностями, чтоб достичь ценного для себя результата. Сюда также входят действия, которые приложение выполняет от имени пользователя, чтобы создать для него ценность. +Этот слой предназначен для основных взаимодействий в вашем приложении, действий, которые важны вашим пользователям. Эти взаимодействия часто затрагивают бизнес-сущности, поскольку сущности — это то, о чём ваше приложение. -Слайс на этом слое может содержать _интерактивные_ элементы пользовательского интерфейса, внутреннее состояние и запросы к API, которые позволяют выполнять действия, создающие ценность. +Важный принцип эффективного использования слоя Features: **не все должно быть фичей**. Хорошим показателем того, что что-то должно быть фичей, является тот факт, что оно переиспользуется. Например, если в приложении есть несколько редакторов, и у всех них есть комментарии, то комментарии являются переиспользуемой фичей. Помните, что слайсы — это механизм для быстрого поиска кода, и если фич слишком много, важные фичи теряются. -**Примеры слайсов**: +В идеале, когда вы приходите в новый проект, вы узнаёте о его функциональности, просматривая страницы и фичи. Принимая решение о том, что должно быть функцией, оптимизируйте опыт новичка в проекте, который/ая хочет быстро обнаружить большие важные области кода. - - -
Для социальной сети Для Git-фронтенда (например, GitHub) Действия от имени пользователя
    -
  • Авторизоваться
  • -
  • Создать публикацию
  • -
  • Вступить в группу
  • -
    -
  • Изменить файл
  • -
  • Оставить комментарий
  • -
  • Слить ветки
  • -
    -
  • Автоматически включить тёмную тему
  • -
  • Выполнить вычисления в фоне
  • -
  • Действия на основе User-Agent
  • -
+Слайс фичи может содержать UI для выполнения действия, например, форму (`📁 ui`), вызовы API, необходимые для выполнения действия (`📁 api`), валидацию и внутреннее состояние (`📁 model`), фиче-флаги (`📁 config`). ### Widgets -Самодостаточные блоки пользовательского интерфейса возникли из композиции единиц более низкого уровня, таких как сущности и функции. +Слой Widgets предназначен для больших самодостаточных блоков интерфейса. Виджеты наиболее полезны, когда они используются на нескольких страницах или когда страница, к которой они принадлежат, имеет несколько больших независимых блоков, и это один из них. -Этот слой предоставляет возможность заполнить слоты, оставленные в интерфейсе сущностей, другими сущностями и интерактивными элементами из фич. Поэтому обычно на этом слое не размещается бизнес-логика, вместо этого она хранится в фичах. Каждый слайс на этом слое содержит готовые к использованию компоненты пользовательского интерфейса и иногда не-бизнес-логику, например, жесты, взаимодействие с клавиатурой и т.д. +Если блок интерфейса составляет бо́льшую часть интересного контента на странице и никогда не используется повторно, он **не должен быть виджетом**, и вместо этого его следует разместить непосредственно на этой странице. -Иногда удобнее разместить бизнес-логику на этом слое. Зачастую, это происходит тогда, когда виджет имеет довольно много интерактивности (например, интерактивные таблицы) и бизнес-логика в нём не переиспользуется. - -**Примеры слайсов**: +:::tip - - -
Для социальной сети Для Git-фронтенда (например, GitHub)
    -
  • Карточка публикации
  • -
  • Шапка профиля пользователя (с действиями)
  • -
    -
  • Список файлов в репозитории (с действиями)
  • -
  • Комментарий в ветке комментариев
  • -
  • Карточка репозитория
  • -
+Если вы используете систему вложенного роутинга (например, роутер [Remix][ext-remix]), может быть полезно использовать слой Widgets так же, как плоская система роутинга использует слой Pages — для создания полных блоков роутинга, включая связанные запросы данных, состояния загрузки и границы ошибок. -:::tip +Таким же образом, вы можете хранить лейауты страниц на этом слое. -Если вы используете вложенную систему маршрутизации (например, роутер [Remix][ext--remix]), может быть полезно использовать слой Widgets аналогично слою Pages в плоской системе маршрутизации - для создания полноценных интерфейсных блоков с получением соответствующих данных с бэкенда, состояниями загрузки и ограничителями ошибок. Также здесь можно разместить лейауты для слоя Pages. ::: ### Pages -Полноценные страницы для страничных приложений (например, веб-сайтов) или экраны/активности для экранных приложений (например, мобильных приложений). - -По своей композиционной природе этот слой похож на Widgets, хоть и в большем масштабе. Каждый слайс на этом слое содержит компоненты пользовательского интерфейса, готовые к подключению к роутеру, а также может содержать логику получения данных и обработки ошибок. +Страницы — это то, из чего состоят веб-сайты и приложения (также называются "экраны" или "активности"). Одна страница обычно соответствует одному слайсу, однако, если есть несколько очень похожих страниц, их можно сгруппировать в один слайс, например, формы регистрации и входа. -**Примеры слайсов**: +Нет никаких ограничений на количество кода, которое можно разместить в слайсе страницы, по крайней мере, до тех пор, пока вашей команде не станет сложно ориентироваться в ней. Если блок интерфейса со страницы не переиспользуется на других страницах, вполне допустимо оставить его внутри слайса страницы. - - -
Для социальной сети Для Git-фронтенда (например, GitHub)
    -
  • Лента новостей
  • -
  • Страница сообщества
  • -
  • Публичный профиль пользователя
  • -
    -
  • Страница репозитория
  • -
  • Репозитории пользователя
  • -
  • Ветки в репозитории
  • -
+В слайсе страницы вы обычно найдете интерфейс страницы, а также состояния загрузки и границы ошибок (`📁 ui`). Также вы можете найти там запросы на получение и изменение данных (`📁 api`). Обычно у страницы нет выделенной модели данных, и небольшие части состояния могут храниться в самих компонентах. ### Processes @@ -165,20 +130,21 @@ pagination_next: reference/slices-segments Выход из ситуаций, когда требуется сложное многостраничное взаимодействие. -Этот уровень намеренно оставлен не очень определенным. Большинству приложений этот слой не пригодится, логику на уровне роутера и сервера следует оставить на уровне App. Рассмотрите возможность использования этого слоя только тогда, когда слой App вырастет настолько, что станет неподдерживаемым и потребует разгрузки. +Этот уровень намеренно оставлен не очень определенным. Большинству приложений этот слой не пригодится, логику на уровне роутера и сервера следует оставить на уровне App. Используйте этот слой только тогда, когда слой App вырастет настолько, что станет неподдерживаемым и потребует разгрузки. ### App -Всё, что касается всего приложения, как в техническом смысле (например, провайдеры контекста), так и в бизнес-смысле (например, аналитика). +Всё, что касается приложения целиком, как в техническом смысле (например, провайдеры контекста), так и в бизнес-смысле (например, аналитика). -Этот слой обычно не содержит слайсов, как и Shared, вместо этого он содержит непосредственно сегменты. +Этот слой обычно не содержит слайсов, как и Shared, и вместо этого внутри него сразу находятся сегменты. -**Примеры содержимого**: +Вот сегменты, которые вы обычно можете найти в этом слое: -* Стили -* Роутер -* Хранилища данных и прочие провайдеры контекста -* Инициализация аналитики +- `📁 routes` — конфигурация роутера +- `📁 store` — глобальная конфигурация хранилища +- `📁 styles` — глобальные стили +- `📁 entrypoint` — точка входа в код приложения, специфичная для вашего фреймворка -[ext--remix]: https://remix.run -[ext--sova-utility-dump]: https://sergeysova.com/ru/why-utils-and-helpers-is-a-dump/ +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports +[ext-remix]: https://remix.run +[ext-sova-utility-dump]: https://sergeysova.com/ru/why-utils-and-helpers-is-a-dump/ diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/public-api.md b/i18n/ru/docusaurus-plugin-content-docs/current/reference/public-api.md index fdf59a71ad..66ed9cfb5f 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/public-api.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/reference/public-api.md @@ -1,218 +1,154 @@ --- sidebar_position: 3 -sidebar_label: Public API -pagination_next: about/index --- -# Публичное API модуля приложения +# Публичный API -Каждая сущность методологии проектируется как **удобный в использовании и интеграции модуль.** +Публичный API — это _контракт_ между группой модулей, например, слайсом, и кодом, который его использует. Он также действует как ворота, разрешая доступ только к определенным объектам и только через этот публичный API. -## Цели {#goals} +На практике это обычно реализуется как индексный файл с реэкспортами: -Удобство использования и интеграции модуля достигается через выполнение *ряда целей*: - -1. Приложение должно быть **защищено от изменений** внутренней структуры отдельных модулей -1. Переработка внутренней структуры модуля **не должна затрагивать** другие модули -1. Существенные изменения поведения модуля должны быть **легко определяемы** - > **Существенные изменения поведения модуля** - изменения, ломающие ожидания сущностей-пользователей модуля. - -Достичь этих целей позволяет введение публичного интерфейса (Public API), представляющего собой единую точку доступа к возможностям модуля и определяющего "контракт" взаимодействия модуля с внешним миром. - -:::info Важно - -Структура сущности должна иметь единую точку входа, предоставляющую публичный интерфейс - -::: - -```sh -└── features/                        #  - └── auth-form/                  # Внутренняя структура фичи - ├── ui/                    # - ├── model/                 # - ├── {...}/                 # - └── index.ts               # Энтрипоинт фичи с ее публичным API +```js title="pages/auth/index.js" +export { LoginPage } from "./ui/LoginPage"; +export { RegisterPage } from "./ui/RegisterPage"; ``` -```ts title="**/**/index.ts" -export { Form as AuthForm } from "./ui" -export * as authFormModel from "./model" -``` - -## Требования к публичному API {#requirements-for-the-public-api} - -Выполнение этих требований позволяет свести взаимодействие с модулем к **выполнению публичного интерфейса-контракта** и, тем самым, достичь надежности и удобства в использовании модуля. - -### 1. Контроль доступа {#1-access-control} - -Public API должен осуществлять **контроль доступа** к содержимому модуля - -- Другие части приложения могут использовать **только те сущности модуля, которые представлены в публичном интерфейсе** -- Внутренняя часть модуля за пределами публичного интерфейса **доступны только самому модулю**. - -#### Примеры {#examples} +## Что делает публичный API хорошим? -##### Отстранение от приватных импортов {#suspension-from-private-imports} +Хороший публичный API делает использование и интеграцию слайса в другой код удобным и надежным. Этого можно достичь, поставив три цели: -- **Плохо**: Идет обращение напрямую к внутренним частям модуля, минуя публичный интерфейс доступа - опасно, особенно при рефакторинге модуля +1. Остальная часть приложения должна быть защищена от структурных изменений в слайсе, таких как рефакторинг. +2. Значительные изменения в поведении слайса, которые нарушают предыдущие ожидания, должны вызывать изменения в публичном API. +3. Только необходимые части слайса должны быть доступны. - ```diff - - import { Form } from "features/auth-form/components/view/form" - ``` +Последняя цель имеет важные практические последствия. Может возникнуть соблазн создать слепые реэкспорты всего, особенно на ранних этапах разработки слайса, потому что любые новые объекты, которые вы экспортируете из своих файлов, также автоматически экспортируются из слайса: -- **Хорошо:** API заранее экспортирует только нужное и разрешенное, разработчику модуля теперь нужно думать только о том, чтобы не ломать Public API при рефакторинге - - ```diff - + import { AuthForm } from "features/auth-form" - ``` - -### 2. Устойчивость к изменениям {#2-sustainability-for-changes} - -Public API должен быть **устойчивым к изменениям** внутри модуля - -- Изменения, ломающие поведения модуля, должны отражаться в изменении Public API - -#### Примеры {#examples} - -##### Абстрагирование от реализации {#abstracting-from-the-implementation} +```js title="Плохая практика, features/comments/index.js" +// ❌ НИЖЕ ПЛОХОЙ КОД, НЕ ДЕЛАЙТЕ ТАК +export * from "./ui/Comment"; // 👎 не пытайтесь повторить дома +export * from "./model/comments"; // 💩 это плохая практика +``` -Изменение внутренней структуры не должно приводить к изменению Public API +Это ухудшает понимаемость слайса беглым взглядом, потому что вы не можете легко определить, каков интерфейс этого слайса. Не зная интерфейс, вам придется глубоко погружаться в код слайса, чтобы понять, как его интегрировать. Еще одна проблема заключается в том, что вы можете случайно раскрыть внутренние модули, что усложнит рефакторинг, если кто-то начнет от них зависеть. -- **Плохо:** перемещение или переименование этого компонента внутри фичи приведет к необходимости рефакторить импорты во всех местах использования компонента. +## Публичный API для кросс-импортов {#public-api-for-cross-imports} - ```diff - - import { Form } from "features/auth-form/ui/form" - ``` +Кросс-импорты — это ситуация, когда один слайс импортирует из другого слайса на том же слое. Обычно это запрещено [правилом импорта для слоёв][import-rule-on-layers], но часто есть реальные причины, чтоб сделать кросс-импорт. Например, в реальном мире бизнес-сущности часто ссылаются друг на друга, и лучше отразить эти отношения в коде, а не пытаться избавиться от них. -- **Хорошо:** интерфейс фичи не отображает её внутреннюю структуру, внешние "пользователи" фичи не пострадают от перемещения или переименования компонента внутри фичи +Для этой цели существует особый вид публичного API, также известный как `@x`-нотация. Если у вас есть сущности A и B, и сущность B должна импортировать из сущности A, то сущность A может объявить отдельный публичный API только для сущности B. - ```diff - + import { AuthForm } from "features/auth-form" - ``` +- `📂 entities` + - `📂 A` + - `📂 @x` + - `📄 B.ts` — специальный публичный API только для кода внутри `entities/B/` + - `📄 index.ts` — обычный публичный API -### 3. Интегрируемость {#3-integrability} +Затем код внутри `entities/B/` может импортировать из `entities/A/@x/B`: -Public API должен способствовать **легкой и гибкой интеграции** +```ts +import type { EntityA } from "entities/A/@x/B"; +``` -- Должен быть удобен для использования остальными частями приложения, в частности, решать проблему коллизии имен +Нотацию `A/@x/B` следует читать как "пересечение A и B". -#### Примеры {#examples} +:::note -##### Коллизия имен {#name-collision} +Старайтесь свести кросс-импорты к минимуму и **используйте эту нотацию только на уровне Entities**, где устранение кросс-импортов часто неразумно. -- **Плохо:** будет коллизия имен +::: - ```ts title="features/auth-form/index.ts" - export { Form } from "./ui" - export * as model from "./model" - ``` +## Проблемы с индексными файлами - ```ts title="features/post-form/index.ts" - export { Form } from "./ui" - export * as model from "./model" - ``` +Индексные файлы, такие как `index.js`, также известные как barrel-файлы (файлы-бочки), являются самым распространенным способом определения публичного API. Их легко создать, но они иногда вызывают проблемы с некоторыми сборщиками и фреймворками. - ```diff - - import { Form, model } from "features/auth-form" - - import { Form, model } from "features/post-form" - ``` +### Циклические импорты -- **Хорошо:** коллизия решена на уровне интерфейса +Циклический импорт — это когда два или более файла импортируют друг друга по кругу. - ```ts title="features/auth-form/index.ts" - export { Form as AuthForm } from "./ui" - export * as authFormModel from "./model" - ``` + - ```ts title="features/post-form/index.ts" - export { Form as PostForm } from "./ui" - export * as postFormModel from "./model" - ``` +
+ Три файла, импортирующие друг друга по кругу + Три файла, импортирующие друг друга по кругу +
+ На изображении выше: три файла, `fileA.js`, `fileB.js` и `fileC.js`, импортирующие друг друга по кругу. +
+
- ```diff - + import { AuthForm, authFormModel } from "features/auth-form" - + import { PostForm, postFormModel } from "features/post-form" - ``` +Эти ситуации часто трудно обрабатывать сборщикам, и в некоторых случаях они могут даже привести к ошибкам во время выполнения кода, которые может быть трудно отладить. -##### Гибкое использование {#flexible-use} +Циклические импорты могут возникать и без индексных файлов, но наличие индексного файла создает явную возможность случайно создать циклический импорт. Это часто происходит, когда у вас есть два объекта, доступных в публичном API слайса, например, `HomePage` и `loadUserStatistics`, и `HomePage` нужно получить доступ к `loadUserStatistics`, но он делает это следующим образом: -- **Плохо:** неудобно писать, неудобно читать, "пользователь" фичи страдает +```jsx title="pages/home/ui/HomePage.jsx" +import { loadUserStatistics } from "../"; // импортируем из pages/home/index.js - ```diff - - import { storeActionUpdateUserDetails } from "features/auth-form" - - dispatch(storeActionUpdateUserDetails(...)) - ``` +export function HomePage() { /* … */ } +``` -- **Хорошо:** "пользователь" фичи получает доступ к нужным вещам итеративно и гибко +```js title="pages/home/index.js" +export { HomePage } from "./ui/HomePage"; +export { loadUserStatistics } from "./api/loadUserStatistics"; +``` - ```diff - + import { authFormModel } from "features/auth-form" - + dispatch(authFormModel.effects.updateUserDetails(...)) // redux - + authFormModel.updateUserDetailsFx(...) // effector - ``` +Эта ситуация создает циклический импорт, потому что `index.js` импортирует `ui/HomePage.jsx`, но `ui/HomePage.jsx` тоже импортирует `index.js`. -##### Разрешение коллизий {#resolution-of-collisions} +Чтобы предотвратить эту проблему, воспользуйтесь этими принципами. Если у вас есть два файла, и один импортирует из другого: +- Если они находятся в одном слайсе, всегда используйте _относительные_ импорты и пишите полный путь импорта +- Если они находятся в разных слайсах, всегда используйте _абсолютные_ импорты, например, через алиас -Коллизия имен должна решаться на уровне публичного интерфейса, а не реализации +### Большие бандлы и неработающий tree-shaking в Shared {#large-bundles} -- **Плохо:** коллизия имен решается на уровне реализации +Некоторым сборщикам может быть трудно выполнять tree-shaking (удаление неимпортированного кода), когда у вас есть индексный файл, который реэкспортирует все. - ```ts title="features/auth-form/index.ts" - export { AuthForm } from "./ui" - export { authFormActions, authFormReducer } from "model" - ``` +Обычно это не проблема для публичных API, потому что содержимое модуля обычно довольно тесно связано, поэтому вам редко нужно импортировать одну вещь, но удалить другую. Однако есть два очень распространенных случая, когда обычные правила публичного API в FSD могут привести к проблемам — `shared/ui` и `shared/lib`. - ```ts title="features/post-form/index.ts" - export { PostForm } from "./ui" - export { postFormActions, postFormReducer } from "model" - ``` +Эти две папки являются коллекциями несвязанных вещей, которые часто не нужны все в одном месте. Например, в `shared/ui` могут быть модули для каждого компонента в библиотеке UI: -- **Хорошо:** коллизия имен решается на уровне интерфейса +- `📂 shared/ui/` + - `📁 button` + - `📁 text-field` + - `📁 carousel` + - `📁 accordion` - ```ts title="features/auth-form/model.ts" - export { actions, reducer } - ``` +Эта проблема усугубляется, когда один из этих модулей имеет тяжелую зависимость, такую как подсветка синтаксиса или библиотека drag'n'drop. Вы не хотите подтягивать их на каждую страницу, которая использует что-то из `shared/ui`, например, кнопку. - ```ts title="features/auth-form/index.ts" - export { Form as AuthForm } from "./ui" - export * as authFormModel from "./model" - ``` +Если ваши бандлы нежелательно растут из-за единого публичного API в `shared/ui` или `shared/lib`, рекомендуется вместо этого иметь отдельный индексный файл для каждого компонента или библиотеки: - ```ts title="features/post-form/model.ts" - export { actions, reducer } - ``` +- `📂 shared/ui/` + - `📂 button` + - `📄 index.js` + - `📂 text-field` + - `📄 index.js` - ```ts title="features/post-form/index.ts" - export { Form as PostForm } from "./ui" - export * as postFormModel from "./model" - ``` +Тогда потребители этих компонентов могут импортировать их напрямую, как показано ниже: -## О реэкспортах {#about-re-exports} +```js title="pages/sign-in/ui/SignInPage.jsx" +import { Button } from '@/shared/ui/button'; +import { TextField } from '@/shared/ui/text-field'; +``` -В JavaScript публичный интерфейс модуля создается с помощью реэкспорта сущностей изнутри модуля в `index` файле: +### Нет реальной защиты от обхода публичного API -```ts title="**/**/index.ts" -export { Form as AuthForm } from "./ui" -export * as authModel from "./model" -``` +Когда вы создаете индексный файл для слайса, ничто не мешает другим не использовать его и импортировать напрямую. Это особенно заметно с автоимпортами, потому что существует несколько мест, откуда объект может быть импортирован, поэтому IDE должна решить за вас. Иногда она может выбрать прямой импорт, нарушая правило публичного API для слайсов. -### Недостатки {#disadvantages} +Чтобы автоматически выявлять эти проблемы, мы рекомендуем использовать [Steiger][ext-steiger], архитектурный линтер с набором правил для Feature-Sliced Design. -- В большинстве популярных бандлеров из-за реэкспортов **хуже работает код-сплиттинг**, т.к. [tree-shaking](https://webpack.js.org/guides/tree-shaking/) при таком подходе может безопасно отбросить только модуль целиком, но не его часть. - > Например, импорт `authModel` в модели страницы приведет к попаданию компонента `AuthForm` в чанк этой страницы, даже если этот компонент там не используется. +### Худшая производительность сборщиков на больших проектах -- Как следствие, инициализация чанка становится дороже, т.к. браузер должен обработать все модули в нем, в том числе и те, что попали в бандл "за компанию" +Наличие большого количества индексных файлов в проекте может замедлить работу сервера разработки, как отметил TkDodo в [своей статье "Please Stop Using Barrel Files"][ext-please-stop-using-barrel-files]. -### Возможные пути решения {#possible-solutions} +Есть несколько вещей, которые вы можете сделать, чтобы справиться с этой проблемой: -- `webpack` позволяет отметить файлы-реэкспорты как [**side effects free**](https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free) - это разрешает `webpack` использовать более агрессивные оптимизации при работе с таким файлом +1. То же самое, что и в разделе "Большие бандлы и неработающий tree-shaking в Shared" — создайте отдельные индексные файлы для каждого компонента/библиотеки в shared/ui и shared/lib вместо одного большого +2. Избегайте наличия индексных файлов в сегментах на слоях, которые имеют слайсы. + Например, если у вас есть индекс для фичи "comments", `📄 features/comments/index.js`, нет смысла иметь еще один индекс для `ui` сегмента этой фичи, `📄 features/comments/ui/index.js`. +3. Если у вас очень большой проект, есть большая вероятность, что ваше приложение можно разделить на несколько больших кусков. + Например, у Google Docs очень разные обязанности для редактора документов и для файлового браузера. Вы можете создать монорепозиторий, где каждый пакет является отдельным корнем FSD со своим набором слоев. Некоторые пакеты могут иметь только слои Shared и Entities, другие могут иметь только Pages и App, а некоторые могут включать свой небольшой Shared, но при этом использовать большой Shared из другого пакета. -## См. также {#see-also} + -- [(Обсуждение) Public API абстракции][disc-src] -- [Принципы **SOLID**][ext-solid] -- [Паттерны **GRASP**][ext-grasp] + -[disc-src]: https://github.com/feature-sliced/documentation/discussions/41 -[ext-solid]: https://ru.wikipedia.org/wiki/SOLID -[ext-grasp]: https://ru.wikipedia.org/wiki/GRASP +[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers +[ext-steiger]: https://github.com/feature-sliced/steiger +[ext-please-stop-using-barrel-files]: https://tkdodo.eu/blog/please-stop-using-barrel-files diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx index a0b81db38f..6ea0746798 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/reference/slices-segments.mdx @@ -8,50 +8,64 @@ pagination_next: reference/public-api ## Слайсы -Слайсы - это второй уровень в организационной иерархии Feature-Sliced Design. Их основное назначение - группировать код по его значению для продукта, бизнеса или просто приложения. +Слайсы — это второй уровень в организационной иерархии Feature-Sliced Design. Их основное назначение — группировать код по его значению для продукта, бизнеса или просто приложения. -Имена слайсов не стандартизированы, поскольку они напрямую определяются бизнес-областью вашего приложения. Например, фотогалерея может иметь слайсы `photo`, `create-album`, `gallery-page`. Для социальной сети потребуются другие слайсы, например, `post`, `add-user-to-friends`, `news-feed`. +Имена слайсов не стандартизированы, поскольку они напрямую определяются бизнес-областью вашего приложения. Например, фотогалерея может иметь слайсы `photo`, `effects`, `gallery-page`. Для социальной сети потребуются другие слайсы, например, `post`, `comments`, `news-feed`. -Близко связанные слайсы могут быть структурно сгруппированы в одной папке, но они должны соблюдать те же правила изоляции, что и другие слайсы - в этом каталоге не должно быть **никакого кода для совместного использования несколькими слайсами**. +Слои Shared и App не содержат слайсов. Это потому, что Shared не должен содержать никакой бизнес-логики, следовательно, не имеет продуктового значения, а App должен содержать только код, касающийся всего приложения, поэтому разделение не требуется. -![Фичи "compose" (написать), "like" (отметить как понравившееся) и "delete" (удалить), сгруппированные в папку "post" (публикация). В этой папке также есть файл "some-shared-code.ts" (какой-то общий код), название которого перечеркнуто, что означает, что этот файл не должен там быть.](/img/graphic-nested-slices.svg) +### Нулевая сцепленность и высокая связность {#zero-coupling-high-cohesion} -Слои Shared и App не содержат слайсов. Это связано с тем, что Shared не должен содержать никакой бизнес-логики, следовательно, не имеет значения для продукта, а App должен содержать только код, относящийся ко всему приложению, поэтому в разбиении нет необходимости. +Слайсы задуманы как независимые и сильно связанные группы файлов кода. Картинка ниже может помочь визуализировать такие сложные концепции как _связность_ (cohesion) и _сцепленность_ (coupling): + +
+ + +
+ Картинка вдохновлена https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/ +
+
+ +Идеальный слайс независим от других слайсов на своем уровне (нулевая сцепленность) и содержит бо́льшую часть кода, связанного с его основной целью (высокая связность). + +Независимость слайсов обеспечивается [правилом импорта для слоёв][layers--import-rule]: + +> _Модуль (файл) в слайсе может импортировать другие слайсы только если они находятся на слоях строго ниже._ ### Правило публичного API для слайсов -Внутри слайса код может быть организован как угодно, и это не создаст никаких проблем до тех пор, пока срез имеет качественный публичный API. В этом суть правила **публичного API для слайсов**: +Внутри слайса код может быть организован как угодно, и это не создаст никаких проблем до тех пор, пока слайс имеет качественный публичный API. В этом суть правила **публичного API для слайсов**: > _Каждый слайс (и сегмент на слоях, не имеющих слайсов) должен содержать определение публичного API._ > > _Модули вне этого слайса/сегмента могут ссылаться только на публичный API, а не на внутреннюю файловую структуру этого слайса/сегмента._ -Подробнее о причинах требования публичных API и лучших практиках их создания читайте в [справочнике о публичных API][ref--public-api]. +Подробнее о причинах требования публичных API и лучших практиках их создания читайте в [справочнике о публичных API][ref-public-api]. + +### Группы слайсов + +Тесно связанные слайсы могут быть структурно сгруппированы в папку, но они должны соблюдать те же правила изоляции, что и другие слайсы — **никакого совместного использования кода** в этой папке быть не должно. + +![Функции "compose", "like" и "delete" сгруппированы в папку "post". В этой папке также есть файл "some-shared-code.ts", который зачеркнут, чтобы показать, что это запрещено.](/img/graphic-nested-slices.svg) ## Сегменты -Сегменты - это третий и последний уровень в организационной иерархии, их цель - группировать код по его технической природе. +Сегменты — это третий и последний уровень в организационной иерархии, их цель — группировать код по его техническому назначению. Существует несколько стандартизированных названий сегментов: -* `ui` - компоненты пользовательского интерфейса, функции форматирования данных -* `model` - бизнес-логика и хранилища данных, функции для обработки этих данных -* `lib` - вспомогательный инфраструктурный код -* `api` - взаимодействие с внешними API, API-методы бэкенда -Другие сегменты допускаются, но должны создаваться только по необходимости. Наиболее распространенными местами для других сегментов являются слои App и Shared, где срезы не имеют смысла. +- `ui` — все, что связано с отображением UI: UI-компоненты, форматтеры дат, стили и т.д. +- `api` — взаимодействие с бэкендом: функции запросов, типы данных, мапперы и т.д. +- `model` — модель данных: схемы, интерфейсы, хранилища и бизнес-логика. +- `lib` — библиотечный код, необходимый другим модулям в этом слайсе. +- `config` — конфигурационные файлы и фиче-флаги. -### Примеры +На [странице про Слои][layers--layer-definitions] есть примеры того, как каждый из этих сегментов может использоваться на разных слоях. -| Layer | `ui` | `model` | `lib` | `api` | -| :------- | :----------- | :----------- | :----------- | :----------- | -| Shared | UI-библиотека | Обычно не используется | Утилитарные модули из нескольких связанных файлов.
Если вам нужны индивидуальные вспомогательные функции, обратите внимание на библиотеки утилит, например, [`lodash-es`][ext--lodash]. | Примитивный API-клиент с дополнительными функциями, такими как аутентификация или кэширование. | -| Entities | Скелет бизнес-сущности со слотами для интерактивных элементов | Хранилище объектов этой сущности, а также функции для обработки этих объектов.
Этот сегмент лучше всего подходит для хранения данных с сервера. Если вы используете [TanStack Query][ext--tanstack-query] или другие методы неявного хранения, вы можете опустить этот сегмент. | Функции над объектами этой сущности, не связанные с хранением данных | API-методы, использующие API-клиент из Shared для упрощения коммуникации с бэкендом | -| Features | Интерактивные элементы, позволяющие пользователям использовать эту функцию | Бизнес-логика и хранилище инфраструктурных данных, если требуется (например, текущая тема приложения). Здесь лежит код, который непосредственно создает пользу для пользователя | Инфраструктурный код, который позволяет сегменту `model` более кратко описать бизнес-логику | API-методы, представляющие эту функцию на бэкенде.
Может объединять API-методы из Entities. -| Widgets | Композиция Entities и Features в самодостаточные блоки интерфейса.
Также может содержать ограничители ошибок и состояния загрузки. | Хранилище инфраструктурных данных, если требуется | Не-бизнес-взаимодействия (например, жесты) и прочий код, необходимый для функционирования этого блока на странице | Обычно не используется, но может содержать загрузчики данных в контексте вложенного роутинга (например, [Remix][ext--remix]) | -| Pages | Композиция Entities, Features и Widgets в полноценные страницы.
Также может содержать ограничители ошибок и состояния загрузки. | Обычно не используется | Не-бизнес-взаимодействия (например, жесты) и прочий код, необходимый для создания полноценного пользовательского опыта на этой странице | Загрузчики данных для фреймворков, ориентированных на SSR (рендеринг на сервере) | +Вы также можете создавать свои собственные сегменты. Наиболее распространенные места для кастомных сегментов — это слои App и Shared, где слайсы не имеют смысла. -[ref--public-api]: /docs/reference/public-api +Убедитесь, что название этих сегментов описывает, для чего нужно его содержимое, а не чем оно является. Например, `components`, `hooks` и `types` — плохие названия сегментов, потому что они не так полезны, когда вы ищете код. -[ext--lodash]: https://www.npmjs.com/package/lodash-es -[ext--tanstack-query]: https://tanstack.com/query/latest -[ext--remix]: https://remix.run +[layers--layer-definitions]: /docs/reference/layers#layer-definitions +[layers--import-rule]: /docs/reference/layers#import-rule-on-layers +[ref-public-api]: /docs/reference/public-api diff --git a/i18n/uz/docusaurus-plugin-content-docs/current.json b/i18n/uz/docusaurus-plugin-content-docs/current.json index 6e1b91b131..e8aeebd580 100644 --- a/i18n/uz/docusaurus-plugin-content-docs/current.json +++ b/i18n/uz/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "v2.0.0 🍰", + "message": "v2.1", "description": "The label for version current" }, "sidebar.getstartedSidebar.category.Tutorials": { diff --git a/i18n/uz/docusaurus-plugin-content-docs/current/reference/index.mdx b/i18n/uz/docusaurus-plugin-content-docs/current/reference/index.mdx index fd3743f114..9bc362620a 100644 --- a/i18n/uz/docusaurus-plugin-content-docs/current/reference/index.mdx +++ b/i18n/uz/docusaurus-plugin-content-docs/current/reference/index.mdx @@ -25,12 +25,6 @@ import { ApiOutlined, GroupOutlined, AppstoreOutlined, NodeIndexOutlined } from to="/docs/reference/slices-segments" Icon={AppstoreOutlined} /> - -

- Feature-Sliced Design v2.0.0 (Current) -

+

Feature-Sliced Design v2.1 (Current)

{translate({ id: "pages.versions.current" })}

+
@@ -46,6 +44,11 @@ function Version() { Migration from v1 + + Migration from v2.0 + +
diff --git a/static/img/circular-import-dark.svg b/static/img/circular-import-dark.svg new file mode 100644 index 0000000000..14630e1882 --- /dev/null +++ b/static/img/circular-import-dark.svg @@ -0,0 +1 @@ +📄 fileA.js📄 fileB.js📄 fileC.js \ No newline at end of file diff --git a/static/img/circular-import-light.svg b/static/img/circular-import-light.svg new file mode 100644 index 0000000000..1c302f119b --- /dev/null +++ b/static/img/circular-import-light.svg @@ -0,0 +1 @@ +📄 fileA.js📄 fileB.js📄 fileC.js \ No newline at end of file From fb190877b7b071731d55b753856a5636f583003b Mon Sep 17 00:00:00 2001 From: Minsu <52266597+Gaic4o@users.noreply.github.com> Date: Mon, 18 Nov 2024 06:25:33 +0900 Subject: [PATCH 17/29] docs: with-nextjs page translated into Korean (#745) --- .../current/guides/tech/with-nextjs.mdx | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx b/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx new file mode 100644 index 0000000000..1a31af2b7e --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-nextjs.mdx @@ -0,0 +1,117 @@ +--- +sidebar_position: 10 +--- +# NextJS와 함께 사용하기 + +NextJS에서도 FSD(Feature-Sliced Design) 아키텍처를 구현할 수 있지만, 두 가지 점에서 NextJS의 프로젝트 구조 요구사항과 FSD 구조 간에 충돌이 발생합니다: + +- `pages` 폴더와의 라우팅 방식 차이 +- NextJS에서 `app` 폴더의 충돌 문제 또는 부재 + +## FSD와 NextJS의 `페이지` 레이어 간 충돌 {#pages-conflict} + +NextJS는 애플리케이션 라우트를 정의하기 위해 `pages` 폴더를 사용하며, `pages` 폴더 내의 파일이 URL과 매핑되도록 설정합니다. +하지만 이 방식은 FSD(Folder Slice Design) `개념에 맞지는 않습니다`. 특히, NextJS의 라우팅 방식으로는 FSD의 슬라이스 구조를 평평하게 유지하기 어려운 점이 있습니다. + +### NextJS의 `pages` 폴더를 프로젝트 루트 폴더로 이동하기 (권장) + +프로젝트 루트에 `pages` 폴더를 배치하고, FSD 구조에 맞춘 페이지들을 NextJS의 `pages` 폴더로 옮깁니다. +이렇게 하면 `src` 폴더 내에서 FSD 구조를 유지할 수 있습니다. + +```sh +├── pages # NextJS 페이지 폴더 +├── src +│ ├── app +│ ├── entities +│ ├── features +│ ├── pages # FSD 페이지 폴더 +│ ├── shared +│ ├── widgets +``` + +### FSD 구조 내 `pages` 폴더 이름 변경하기 + +다른 방법으로는 FSD 구조 내에서 `pages` 폴더의 이름을 변경하여 NextJS의 `pages` 폴더와 충돌을 피할 수도 있습니다. +예를 들어, `pages` 폴더를 `views`로 이름을 변경하면 `src` 폴더 내의 FSD 구조를 유지하면서도 NextJS의 요구 사항과 충돌하지 않게 됩니다. + +```sh +├── app +├── entities +├── features +├── pages # NextJS 페이지 폴더 +├── views # 이름이 변경된 FSD 페이지 폴더 +├── shared +├── widgets +``` + +이름을 변경하는 경우, 이를 프로젝트의 README나 내부 문서에 명확히 기록하여 변경 사항이 잘 전달되도록 하는 것이 좋습니다. 이러한 변경은 ["프로젝트 지식"][project-knowledge]의 일부로 문서화하는 것이 중요합니다. + +## NextJS에서 `app` 폴더 부재 문제 {#app-absence} + +NextJS 13버전 이하에서는 명시적인 `app` 폴더가 없으며, +대신 `_app.tsx` 파일이 모든 페이지를 감싸는 컴포넌트 역할을 합니다. + +### `pages/_app.tsx` 파일에 app 기능 가져오기 + +NextJS 구조에서 `app` 폴더가 없는 문제를 해결하려면, `app` 폴더 내에 `App` 컴포넌트를 생성하고, 이를 `pages/_app.tsx`에 가져와 NextJS가 사용할 수 있도록 설정하면 됩니다. 예를 들어: + +```tsx +// app/providers/index.tsx + +const App = ({ Component, pageProps }: AppProps) => { + return ( + + + + + + + + ); +}; + +export default App; +``` + +그 다음 `pages/_app.tsx` 파일에서 `App` 컴포넌트와 프로젝트 전역 스타일을 다음과 같이 가져올 수 있습니다: + +```tsx +// pages/_app.tsx + +import 'app/styles/index.scss' + +export { default } from 'app/providers'; +``` + +## App Router 사용하기 {#app-router} + +NextJS 13.4 버전에서는 App Router가 안정화되었습니다. App Router를 사용하면 `pages` 폴더 대신 `app` 폴더를 통해 라우팅을 처리할 수 있습니다. +FSD 원칙을 준수하기 위해, NextJS의 `app` 폴더도 `pages` 폴더와의 충돌 문제를 해결한 것과 동일한 방식으로 다루어야 합니다. + +이를 위해 NextJS의 `app` 폴더를 프로젝트 루트로 이동하고, FSD 페이지들을 `app` 폴더로 옮기는 방식을 사용합니다. +이렇게 하면 `src` 폴더 내에서 FSD 프로젝트 구조를 유지할 수 있습니다. +또한, App Router와 Pages Router가 호환되므로 `pages` 폴더를 프로젝트 루트에 추가하는 것이 필요합니다. + +``` +├── app # NextJS app 폴더 +├── pages # NextJS pages 폴더 +│ ├── README.md # 해당 폴더의 목적과 역할에 대한 설명 +├── src +│ ├── app # FSD app 폴더 +│ ├── entities +│ ├── features +│ ├── pages # FSD pages 폴더 +│ ├── shared +│ ├── widgets +``` + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)][ext-app-router-stackblitz] + +## 관련 항목 {#see-also} + +- [(스레드) NextJS의 pages 디렉토리에 대한 토론](https://t.me/feature_sliced/3623) + +[project-knowledge]: /docs/about/understanding/knowledge-types +[ext-app-router-stackblitz]: https://stackblitz.com/edit/stackblitz-starters-aiez55?file=README.md + + From 79ec652b1d556d4abf1cb92f55476ca3a85e7aff Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Tue, 19 Nov 2024 01:03:12 +0100 Subject: [PATCH 18/29] chore: use Docusaurus Faster and upgrade deps (#761) * chore: use Docusaurus Faster and upgrade deps * Fix Stylelint configuration --- .stylelintrc.js | 3 +- babel.config.js | 3 - docusaurus.config.js | 3 + package.json | 49 +- pnpm-lock.yaml | 5273 +++++++++++++++++++++++++++++++---------- src/app/doc-item.scss | 2 +- src/app/index.scss | 10 +- src/app/navbar.scss | 2 +- src/app/scroll.scss | 2 +- 9 files changed, 4120 insertions(+), 1227 deletions(-) delete mode 100644 babel.config.js diff --git a/.stylelintrc.js b/.stylelintrc.js index 1b8c30867e..a2d6caeb49 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -1,12 +1,11 @@ module.exports = { extends: [ - "stylelint-config-standard-scss", "stylelint-config-recommended", + "stylelint-config-standard-scss", "stylelint-config-recess-order", ], rules: { "color-hex-length": "long", - "at-rule-no-unknown": true, "selector-class-pattern": null, }, }; diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index dd249ac168..0000000000 --- a/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [require.resolve("@docusaurus/core/lib/babel/preset")], -}; diff --git a/docusaurus.config.js b/docusaurus.config.js index 798c2ddb50..20c3d1fb16 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -57,6 +57,9 @@ module.exports = { darkTheme: prismThemes.oneDark, }, }, + future: { + experimental_faster: true, + }, }; // Remove configs if there are not secrets passed diff --git a/package.json b/package.json index cd02b48444..96fc632b76 100644 --- a/package.json +++ b/package.json @@ -28,24 +28,25 @@ }, "dependencies": { "@ant-design/icons": "^5.5.1", - "@docusaurus/core": "^3.5.2", - "@docusaurus/plugin-client-redirects": "^3.5.2", - "@docusaurus/plugin-content-docs": "^3.5.2", - "@docusaurus/plugin-ideal-image": "^3.5.2", - "@docusaurus/preset-classic": "^3.5.2", - "@fontsource-variable/overpass": "^5.1.0", - "@mdx-js/react": "^3.0.1", + "@docusaurus/core": "^3.6.1", + "@docusaurus/faster": "^3.6.1", + "@docusaurus/plugin-client-redirects": "^3.6.1", + "@docusaurus/plugin-content-docs": "^3.6.1", + "@docusaurus/plugin-ideal-image": "^3.6.1", + "@docusaurus/preset-classic": "^3.6.1", + "@fontsource-variable/overpass": "^5.1.1", + "@mdx-js/react": "^3.1.0", "@svgr/webpack": "^8.1.0", "@types/lodash-es": "^4.17.12", "clsx": "^2.1.1", "dotenv": "^16.4.5", "file-loader": "^6.2.0", "lodash-es": "^4.17.21", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "plugin-image-zoom": "^1.2.0", "prism-react-renderer": "^2.4.0", - "pushfeedback": "^0.1.44", - "pushfeedback-react": "^0.1.44", + "pushfeedback": "^0.1.49", + "pushfeedback-react": "^0.1.50", "react": "^18.3.1", "react-dom": "^18.3.1", "react-fast-marquee": "^1.6.5", @@ -69,16 +70,16 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.25.1", - "@docusaurus/module-type-aliases": "^3.5.2", - "@docusaurus/theme-classic": "^3.5.2", - "@docusaurus/tsconfig": "^3.5.2", - "@docusaurus/types": "^3.5.2", + "@docusaurus/module-type-aliases": "^3.6.1", + "@docusaurus/theme-classic": "^3.6.1", + "@docusaurus/tsconfig": "^3.6.1", + "@docusaurus/types": "^3.6.1", "@eslint-kit/eslint-config-base": "4.1.0", "@eslint-kit/eslint-config-patch": "^1.0.0", "@eslint-kit/eslint-config-react": "^3.0.0", - "@types/node": "^22.7.4", - "@types/react": "^18.3.10", - "@types/react-dom": "^18.3.0", + "@types/node": "^22.9.0", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "all-contributors-cli": "^6.26.1", @@ -87,12 +88,12 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "1.1.2", "prettier": "^3.3.3", - "sass": "^1.79.3", - "stylelint": "^15.11.0", - "stylelint-config-recess-order": "^4.6.0", - "stylelint-config-recommended": "^13.0.0", - "stylelint-config-standard-scss": "^11.1.0", - "typescript": "^5.6.2" + "sass": "^1.81.0", + "stylelint": "^16.10.0", + "stylelint-config-recess-order": "^5.1.1", + "stylelint-config-recommended": "^14.0.1", + "stylelint-config-standard-scss": "^13.1.0", + "typescript": "^5.6.3" }, - "packageManager": "pnpm@9.6.0" + "packageManager": "pnpm@9.13.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c344337132..df444d6124 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,29 +12,32 @@ importers: specifier: ^5.5.1 version: 5.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/core': - specifier: ^3.5.2 - version: 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + specifier: ^3.6.1 + version: 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/faster': + specifier: ^3.6.1 + version: 3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/plugin-client-redirects': - specifier: ^3.5.2 - version: 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + specifier: ^3.6.1 + version: 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/plugin-content-docs': - specifier: ^3.5.2 - version: 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + specifier: ^3.6.1 + version: 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/plugin-ideal-image': - specifier: ^3.5.2 - version: 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + specifier: ^3.6.1 + version: 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/preset-classic': - specifier: ^3.5.2 - version: 3.5.2(@algolia/client-search@4.24.0)(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2) + specifier: ^3.6.1 + version: 3.6.1(@algolia/client-search@5.14.2)(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(@types/react@18.3.12)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.3) '@fontsource-variable/overpass': - specifier: ^5.1.0 - version: 5.1.0 + specifier: ^5.1.1 + version: 5.1.1 '@mdx-js/react': - specifier: ^3.0.1 - version: 3.0.1(@types/react@18.3.10)(react@18.3.1) + specifier: ^3.1.0 + version: 3.1.0(@types/react@18.3.12)(react@18.3.1) '@svgr/webpack': specifier: ^8.1.0 - version: 8.1.0(typescript@5.6.2) + version: 8.1.0(typescript@5.6.3) '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 @@ -46,13 +49,13 @@ importers: version: 16.4.5 file-loader: specifier: ^6.2.0 - version: 6.2.0(webpack@5.93.0) + version: 6.2.0(webpack@5.93.0(@swc/core@1.9.2)) lodash-es: specifier: ^4.17.21 version: 4.17.21 picocolors: - specifier: ^1.1.0 - version: 1.1.0 + specifier: ^1.1.1 + version: 1.1.1 plugin-image-zoom: specifier: ^1.2.0 version: 1.2.0 @@ -60,11 +63,11 @@ importers: specifier: ^2.4.0 version: 2.4.0(react@18.3.1) pushfeedback: - specifier: ^0.1.44 - version: 0.1.44 + specifier: ^0.1.49 + version: 0.1.49 pushfeedback-react: - specifier: ^0.1.44 - version: 0.1.44 + specifier: ^0.1.50 + version: 0.1.50 react: specifier: ^18.3.1 version: 18.3.1 @@ -88,26 +91,26 @@ importers: version: 3.1.5 url-loader: specifier: ^4.1.1 - version: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0) + version: 4.1.1(file-loader@6.2.0(webpack@5.93.0(@swc/core@1.9.2)))(webpack@5.93.0(@swc/core@1.9.2)) devDependencies: '@babel/eslint-parser': specifier: ^7.25.1 version: 7.25.1(@babel/core@7.25.2)(eslint@7.32.0) '@docusaurus/module-type-aliases': - specifier: ^3.5.2 - version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^3.6.1 + version: 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/theme-classic': - specifier: ^3.5.2 - version: 3.5.2(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + specifier: ^3.6.1 + version: 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(@types/react@18.3.12)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/tsconfig': - specifier: ^3.5.2 - version: 3.5.2 + specifier: ^3.6.1 + version: 3.6.1 '@docusaurus/types': - specifier: ^3.5.2 - version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^3.6.1 + version: 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@eslint-kit/eslint-config-base': specifier: 4.1.0 - version: 4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0) + version: 4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0) '@eslint-kit/eslint-config-patch': specifier: ^1.0.0 version: 1.0.0(eslint@7.32.0) @@ -115,26 +118,26 @@ importers: specifier: ^3.0.0 version: 3.0.0(eslint@7.32.0) '@types/node': - specifier: ^22.7.4 - version: 22.7.4 + specifier: ^22.9.0 + version: 22.9.0 '@types/react': - specifier: ^18.3.10 - version: 18.3.10 + specifier: ^18.3.12 + version: 18.3.12 '@types/react-dom': - specifier: ^18.3.0 - version: 18.3.0 + specifier: ^18.3.1 + version: 18.3.1 '@typescript-eslint/eslint-plugin': specifier: ^6.21.0 - version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)(typescript@5.6.2) + version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^6.21.0 - version: 6.21.0(eslint@7.32.0)(typescript@5.6.2) + version: 6.21.0(eslint@7.32.0)(typescript@5.6.3) all-contributors-cli: specifier: ^6.26.1 version: 6.26.1 docusaurus-plugin-sass: specifier: ^0.2.5 - version: 0.2.5(@docusaurus/core@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(sass@1.79.3)(webpack@5.93.0) + version: 0.2.5(@docusaurus/core@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(sass@1.81.0)(webpack@5.93.0(@swc/core@1.9.2)) eslint: specifier: ^7.32.0 version: 7.32.0 @@ -143,47 +146,47 @@ importers: version: 9.1.0(eslint@7.32.0) eslint-import-resolver-alias: specifier: 1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)) prettier: specifier: ^3.3.3 version: 3.3.3 sass: - specifier: ^1.79.3 - version: 1.79.3 + specifier: ^1.81.0 + version: 1.81.0 stylelint: - specifier: ^15.11.0 - version: 15.11.0(typescript@5.6.2) + specifier: ^16.10.0 + version: 16.10.0(typescript@5.6.3) stylelint-config-recess-order: - specifier: ^4.6.0 - version: 4.6.0(stylelint@15.11.0(typescript@5.6.2)) + specifier: ^5.1.1 + version: 5.1.1(stylelint@16.10.0(typescript@5.6.3)) stylelint-config-recommended: - specifier: ^13.0.0 - version: 13.0.0(stylelint@15.11.0(typescript@5.6.2)) + specifier: ^14.0.1 + version: 14.0.1(stylelint@16.10.0(typescript@5.6.3)) stylelint-config-standard-scss: - specifier: ^11.1.0 - version: 11.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)) + specifier: ^13.1.0 + version: 13.1.0(postcss@8.4.49)(stylelint@16.10.0(typescript@5.6.3)) typescript: - specifier: ^5.6.2 - version: 5.6.2 + specifier: ^5.6.3 + version: 5.6.3 packages: - '@algolia/autocomplete-core@1.9.3': - resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==} + '@algolia/autocomplete-core@1.17.7': + resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==} - '@algolia/autocomplete-plugin-algolia-insights@1.9.3': - resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==} + '@algolia/autocomplete-plugin-algolia-insights@1.17.7': + resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==} peerDependencies: search-insights: '>= 1 < 3' - '@algolia/autocomplete-preset-algolia@1.9.3': - resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==} + '@algolia/autocomplete-preset-algolia@1.17.7': + resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==} peerDependencies: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' - '@algolia/autocomplete-shared@1.9.3': - resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==} + '@algolia/autocomplete-shared@1.17.7': + resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==} peerDependencies: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' @@ -197,42 +200,94 @@ packages: '@algolia/cache-in-memory@4.24.0': resolution: {integrity: sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==} + '@algolia/client-abtesting@5.14.2': + resolution: {integrity: sha512-7fq1tWIy1aNJEaNHxWy3EwDkuo4k22+NBnxq9QlYVSLLXtr6HqmAm6bQgNNzGT3vm21iKqWO9efk+HIhEM1SzQ==} + engines: {node: '>= 14.0.0'} + '@algolia/client-account@4.24.0': resolution: {integrity: sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==} '@algolia/client-analytics@4.24.0': resolution: {integrity: sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==} + '@algolia/client-analytics@5.14.2': + resolution: {integrity: sha512-5Nm5cOOyAGcY+hKNJVmR2jgoGn1nvoANS8W5EfB8yAaUqUxL3lFNUHSkFafAMTCOcVKNDkZQYjUDbOOfdYJLqw==} + engines: {node: '>= 14.0.0'} + '@algolia/client-common@4.24.0': resolution: {integrity: sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==} + '@algolia/client-common@5.14.2': + resolution: {integrity: sha512-BW1Qzhh9tMKEsWSQQsiOEcHAd6g7zxq9RpPVmyxbDO/O4eA4vyN+Qz5Jzo686kuYdIQKqIPCEtob/JM89tk57g==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-insights@5.14.2': + resolution: {integrity: sha512-17zg6pqifKORvvrMIqW6HhwUry9RKRXLgADrgFjZ6PZvGB4oVs12dwRG2/HMrIlpxd9cjeQfdlEgHj6lbAf6QA==} + engines: {node: '>= 14.0.0'} + '@algolia/client-personalization@4.24.0': resolution: {integrity: sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==} + '@algolia/client-personalization@5.14.2': + resolution: {integrity: sha512-5IYt8vbmTA52xyuaZKFwiRoDPeh7hiOC9aBZqqp9fVs6BU01djI/T8pGJXawvwczltCPYzNsdbllV3rqiDbxmQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-query-suggestions@5.14.2': + resolution: {integrity: sha512-gvCX/cczU76Bu1sGcxxTdoIwxe+FnuC1IlW9SF/gzxd3ZzsgzBpzD2puIJqt9fHQsjLxVGkJqKev2FtExnJYZg==} + engines: {node: '>= 14.0.0'} + '@algolia/client-search@4.24.0': resolution: {integrity: sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==} + '@algolia/client-search@5.14.2': + resolution: {integrity: sha512-0imdBZDjqxrshw0+eyJUgnkRAbS2W93UQ3BVj8VjN4xQylIMf0fWs72W7MZFdHlH78JJYydevgzqvGMcV0Z1CA==} + engines: {node: '>= 14.0.0'} + '@algolia/events@4.0.1': resolution: {integrity: sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==} + '@algolia/ingestion@1.14.2': + resolution: {integrity: sha512-/p4rBNkW0fgCpCwrwre+jHfzlFQsLemgaAQqyui8NPxw95Wgf3p+DKxYzcmh8dygT7ub7FwztTW+uURLX1uqIQ==} + engines: {node: '>= 14.0.0'} + '@algolia/logger-common@4.24.0': resolution: {integrity: sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==} '@algolia/logger-console@4.24.0': resolution: {integrity: sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==} + '@algolia/monitoring@1.14.2': + resolution: {integrity: sha512-81R57Y/mS0uNhWpu6cNEfkbkADLW4bP0BNjuPpxAypobv7WzYycUnbMvv1YkN6OsociB4+3M7HfsVzj4Nc09vA==} + engines: {node: '>= 14.0.0'} + '@algolia/recommend@4.24.0': resolution: {integrity: sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==} + '@algolia/recommend@5.14.2': + resolution: {integrity: sha512-OwELnAZxCUyfjYjqsrFmC7Vfa12kqwbDdLUV0oi4j+4pxDsfPgkiZ6iCH2uPw6X8VK88Hl3InPt+RPaZvcrCWg==} + engines: {node: '>= 14.0.0'} + '@algolia/requester-browser-xhr@4.24.0': resolution: {integrity: sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==} + '@algolia/requester-browser-xhr@5.14.2': + resolution: {integrity: sha512-irUvkK+TGBhyivtNCIIbVgNUgbUoHOSk8m/kFX4ddto/PUPmLFRRNNnMHtJ1+OzrJ/uD3Am4FUK2Yt+xgQr05w==} + engines: {node: '>= 14.0.0'} + '@algolia/requester-common@4.24.0': resolution: {integrity: sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==} + '@algolia/requester-fetch@5.14.2': + resolution: {integrity: sha512-UNBg5mM4MIYdxPuVjyDL22BC6P87g7WuM91Z1Ky0J19aEGvCSF+oR+9autthROFXdRnAa1rACOjuqn95iBbKpw==} + engines: {node: '>= 14.0.0'} + '@algolia/requester-node-http@4.24.0': resolution: {integrity: sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==} + '@algolia/requester-node-http@5.14.2': + resolution: {integrity: sha512-CTFA03YiLcnpP+JoLRqjHt5pqDHuKWJpLsIBY/60Gmw8pjALZ3TwvbAquRX4Vy+yrin178NxMuU+ilZ54f2IrQ==} + engines: {node: '>= 14.0.0'} + '@algolia/transporter@4.24.0': resolution: {integrity: sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==} @@ -260,14 +315,26 @@ packages: resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.25.2': resolution: {integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.26.2': + resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + engines: {node: '>=6.9.0'} + '@babel/core@7.25.2': resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} engines: {node: '>=6.9.0'} + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + '@babel/eslint-parser@7.25.1': resolution: {integrity: sha512-Y956ghgTT4j7rKesabkh5WeqgSFZVFwaPR0IWFm7KFHFmmJ4afbG49SmfW4S+GyRPx0Dy5jxEWA5t0rpxfElWg==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} @@ -279,97 +346,192 @@ packages: resolution: {integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.26.2': + resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.24.7': resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + engines: {node: '>=6.9.0'} + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.7': resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==} engines: {node: '>=6.9.0'} + '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': + resolution: {integrity: sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.25.2': resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.25.9': + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-create-class-features-plugin@7.25.0': resolution: {integrity: sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-create-class-features-plugin@7.25.9': + resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-create-regexp-features-plugin@7.25.2': resolution: {integrity: sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-create-regexp-features-plugin@7.25.9': + resolution: {integrity: sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-define-polyfill-provider@0.6.2': resolution: {integrity: sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/helper-define-polyfill-provider@0.6.3': + resolution: {integrity: sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/helper-member-expression-to-functions@7.24.8': resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==} engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.24.7': resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.25.2': resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-optimise-call-expression@7.24.7': resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.24.8': resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.25.9': + resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + engines: {node: '>=6.9.0'} + '@babel/helper-remap-async-to-generator@7.25.0': resolution: {integrity: sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-remap-async-to-generator@7.25.9': + resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-replace-supers@7.25.0': resolution: {integrity: sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-replace-supers@7.25.9': + resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-simple-access@7.24.7': resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} + '@babel/helper-simple-access@7.25.9': + resolution: {integrity: sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-skip-transparent-expression-wrappers@7.24.7': resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} engines: {node: '>=6.9.0'} + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.24.8': resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.24.7': resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.24.8': resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + '@babel/helper-wrap-function@7.25.0': resolution: {integrity: sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==} engines: {node: '>=6.9.0'} + '@babel/helper-wrap-function@7.25.9': + resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} + engines: {node: '>=6.9.0'} + '@babel/helpers@7.25.0': resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + '@babel/highlight@7.24.7': resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} @@ -379,36 +541,71 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.26.2': + resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3': resolution: {integrity: sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': + resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0': resolution: {integrity: sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9': + resolution: {integrity: sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0': resolution: {integrity: sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9': + resolution: {integrity: sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7': resolution: {integrity: sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9': + resolution: {integrity: sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0': resolution: {integrity: sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9': + resolution: {integrity: sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} @@ -447,12 +644,24 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-assertions@7.26.0': + resolution: {integrity: sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-attributes@7.24.7': resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-meta@7.10.4': resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: @@ -469,6 +678,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: @@ -517,6 +732,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} @@ -529,228 +750,456 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-arrow-functions@7.25.9': + resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-generator-functions@7.25.0': resolution: {integrity: sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-generator-functions@7.25.9': + resolution: {integrity: sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-to-generator@7.24.7': resolution: {integrity: sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-to-generator@7.25.9': + resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoped-functions@7.24.7': resolution: {integrity: sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoped-functions@7.25.9': + resolution: {integrity: sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoping@7.25.0': resolution: {integrity: sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoping@7.25.9': + resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-properties@7.24.7': resolution: {integrity: sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-properties@7.25.9': + resolution: {integrity: sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-static-block@7.24.7': resolution: {integrity: sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 + '@babel/plugin-transform-class-static-block@7.26.0': + resolution: {integrity: sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + '@babel/plugin-transform-classes@7.25.0': resolution: {integrity: sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-classes@7.25.9': + resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-computed-properties@7.24.7': resolution: {integrity: sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-computed-properties@7.25.9': + resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-destructuring@7.24.8': resolution: {integrity: sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-destructuring@7.25.9': + resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-dotall-regex@7.24.7': resolution: {integrity: sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-dotall-regex@7.25.9': + resolution: {integrity: sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-duplicate-keys@7.24.7': resolution: {integrity: sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-duplicate-keys@7.25.9': + resolution: {integrity: sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0': resolution: {integrity: sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-transform-dynamic-import@7.24.7': resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-dynamic-import@7.25.9': + resolution: {integrity: sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-exponentiation-operator@7.24.7': resolution: {integrity: sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-exponentiation-operator@7.25.9': + resolution: {integrity: sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-export-namespace-from@7.24.7': resolution: {integrity: sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-export-namespace-from@7.25.9': + resolution: {integrity: sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-for-of@7.24.7': resolution: {integrity: sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-for-of@7.25.9': + resolution: {integrity: sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-function-name@7.25.1': resolution: {integrity: sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-function-name@7.25.9': + resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-json-strings@7.24.7': resolution: {integrity: sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-json-strings@7.25.9': + resolution: {integrity: sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-literals@7.25.2': resolution: {integrity: sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-literals@7.25.9': + resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-logical-assignment-operators@7.24.7': resolution: {integrity: sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-logical-assignment-operators@7.25.9': + resolution: {integrity: sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-member-expression-literals@7.24.7': resolution: {integrity: sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-member-expression-literals@7.25.9': + resolution: {integrity: sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-amd@7.24.7': resolution: {integrity: sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-amd@7.25.9': + resolution: {integrity: sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-commonjs@7.24.8': resolution: {integrity: sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-commonjs@7.25.9': + resolution: {integrity: sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-systemjs@7.25.0': resolution: {integrity: sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-systemjs@7.25.9': + resolution: {integrity: sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-umd@7.24.7': resolution: {integrity: sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-umd@7.25.9': + resolution: {integrity: sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-named-capturing-groups-regex@7.24.7': resolution: {integrity: sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-transform-new-target@7.24.7': resolution: {integrity: sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-new-target@7.25.9': + resolution: {integrity: sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-nullish-coalescing-operator@7.24.7': resolution: {integrity: sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-nullish-coalescing-operator@7.25.9': + resolution: {integrity: sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-numeric-separator@7.24.7': resolution: {integrity: sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-numeric-separator@7.25.9': + resolution: {integrity: sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-rest-spread@7.24.7': resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-rest-spread@7.25.9': + resolution: {integrity: sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-super@7.24.7': resolution: {integrity: sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-super@7.25.9': + resolution: {integrity: sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-catch-binding@7.24.7': resolution: {integrity: sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-catch-binding@7.25.9': + resolution: {integrity: sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-chaining@7.24.8': resolution: {integrity: sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-chaining@7.25.9': + resolution: {integrity: sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-parameters@7.24.7': resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-parameters@7.25.9': + resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-methods@7.24.7': resolution: {integrity: sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-methods@7.25.9': + resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-property-in-object@7.24.7': resolution: {integrity: sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-property-in-object@7.25.9': + resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-property-literals@7.24.7': resolution: {integrity: sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-property-literals@7.25.9': + resolution: {integrity: sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-constant-elements@7.25.1': resolution: {integrity: sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ==} engines: {node: '>=6.9.0'} @@ -763,38 +1212,80 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-display-name@7.25.9': + resolution: {integrity: sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-development@7.24.7': resolution: {integrity: sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-development@7.25.9': + resolution: {integrity: sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx@7.25.2': resolution: {integrity: sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx@7.25.9': + resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-pure-annotations@7.24.7': resolution: {integrity: sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-pure-annotations@7.25.9': + resolution: {integrity: sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-regenerator@7.24.7': resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-regenerator@7.25.9': + resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.26.0': + resolution: {integrity: sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-transform-reserved-words@7.24.7': resolution: {integrity: sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.24.7': - resolution: {integrity: sha512-YqXjrk4C+a1kZjewqt+Mmu2UuV1s07y8kqcUf4qYLnoqemhR4gRQikhdAhSVJioMjVTu6Mo6pAbaypEA3jY6fw==} + '@babel/plugin-transform-reserved-words@7.25.9': + resolution: {integrity: sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-runtime@7.25.9': + resolution: {integrity: sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -805,66 +1296,132 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-shorthand-properties@7.25.9': + resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-spread@7.24.7': resolution: {integrity: sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-spread@7.25.9': + resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-sticky-regex@7.24.7': resolution: {integrity: sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-sticky-regex@7.25.9': + resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-template-literals@7.24.7': resolution: {integrity: sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-template-literals@7.25.9': + resolution: {integrity: sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typeof-symbol@7.24.8': resolution: {integrity: sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typeof-symbol@7.25.9': + resolution: {integrity: sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.25.2': resolution: {integrity: sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.25.9': + resolution: {integrity: sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-escapes@7.24.7': resolution: {integrity: sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-escapes@7.25.9': + resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-property-regex@7.24.7': resolution: {integrity: sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-property-regex@7.25.9': + resolution: {integrity: sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-regex@7.24.7': resolution: {integrity: sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-regex@7.25.9': + resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-sets-regex@7.24.7': resolution: {integrity: sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-transform-unicode-sets-regex@7.25.9': + resolution: {integrity: sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/preset-env@7.25.3': resolution: {integrity: sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/preset-env@7.26.0': + resolution: {integrity: sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/preset-modules@0.1.6-no-external-plugins': resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: @@ -876,61 +1433,89 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/preset-react@7.25.9': + resolution: {integrity: sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/preset-typescript@7.24.7': resolution: {integrity: sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/preset-typescript@7.26.0': + resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/regjsgen@0.8.0': resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - '@babel/runtime-corejs3@7.25.0': - resolution: {integrity: sha512-BOehWE7MgQ8W8Qn0CQnMtg2tHPHPulcS/5AVpFvs2KCK1ET+0WqZqPvnpRpFN81gYoFopdIEJX9Sgjw3ZBccPg==} + '@babel/runtime-corejs3@7.26.0': + resolution: {integrity: sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==} engines: {node: '>=6.9.0'} '@babel/runtime@7.25.0': resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.26.0': + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.25.0': resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} engines: {node: '>=6.9.0'} + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.25.3': resolution: {integrity: sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.25.9': + resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + engines: {node: '>=6.9.0'} + '@babel/types@7.25.2': resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.26.0': + resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + engines: {node: '>=6.9.0'} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@csstools/css-parser-algorithms@2.7.1': - resolution: {integrity: sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==} - engines: {node: ^14 || ^16 || >=18} + '@csstools/css-parser-algorithms@3.0.4': + resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==} + engines: {node: '>=18'} peerDependencies: - '@csstools/css-tokenizer': ^2.4.1 + '@csstools/css-tokenizer': ^3.0.3 - '@csstools/css-tokenizer@2.4.1': - resolution: {integrity: sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==} - engines: {node: ^14 || ^16 || >=18} + '@csstools/css-tokenizer@3.0.3': + resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} + engines: {node: '>=18'} - '@csstools/media-query-list-parser@2.1.13': - resolution: {integrity: sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==} - engines: {node: ^14 || ^16 || >=18} + '@csstools/media-query-list-parser@3.0.1': + resolution: {integrity: sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==} + engines: {node: '>=18'} peerDependencies: - '@csstools/css-parser-algorithms': ^2.7.1 - '@csstools/css-tokenizer': ^2.4.1 + '@csstools/css-parser-algorithms': ^3.0.1 + '@csstools/css-tokenizer': ^3.0.1 - '@csstools/selector-specificity@3.1.1': - resolution: {integrity: sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==} - engines: {node: ^14 || ^16 || >=18} + '@csstools/selector-specificity@4.0.0': + resolution: {integrity: sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==} + engines: {node: '>=18'} peerDependencies: - postcss-selector-parser: ^6.0.13 + postcss-selector-parser: ^6.1.0 '@ctrl/tinycolor@3.6.1': resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} @@ -940,11 +1525,11 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@docsearch/css@3.6.2': - resolution: {integrity: sha512-vKNZepO2j7MrYBTZIGXvlUOIR+v9KRf70FApRgovWrj3GTs1EITz/Xb0AOlm1xsQBp16clVZj1SY/qaOJbQtZw==} + '@docsearch/css@3.8.0': + resolution: {integrity: sha512-pieeipSOW4sQ0+bE5UFC51AOZp9NGxg89wAlZ1BAQFaiRAGK1IKUaPQ0UGZeNctJXyqZ1UvBtOQh2HH+U5GtmA==} - '@docsearch/react@3.6.2': - resolution: {integrity: sha512-rtZce46OOkVflCQH71IdbXSFK+S8iJZlUF56XBW5rIgx/eG5qoomC7Ag3anZson1bBac/JFQn7XOBfved/IMRA==} + '@docsearch/react@3.8.0': + resolution: {integrity: sha512-WnFK720+iwTVt94CxY3u+FgX6exb3BfN5kE9xUY6uuAH/9W/UFboBZFLlrw/zxFRHoHZCOXRtOylsXF+6LHI+Q==} peerDependencies: '@types/react': '>= 16.8.0 < 19.0.0' react: '>= 16.8.0 < 19.0.0' @@ -960,8 +1545,21 @@ packages: search-insights: optional: true - '@docusaurus/core@3.5.2': - resolution: {integrity: sha512-4Z1WkhCSkX4KO0Fw5m/Vuc7Q3NxBG53NE5u59Rs96fWkMPZVSrzEPP16/Nk6cWb/shK7xXPndTmalJtw7twL/w==} + '@docusaurus/babel@3.6.1': + resolution: {integrity: sha512-JcKaunW8Ml2nTnfnvFc55T00Y+aCpNWnf1KY/gG+wWxHYDH0IdXOOz+k6NAlEAerW8+VYLfUqRIqHZ7N/DVXvQ==} + engines: {node: '>=18.0'} + + '@docusaurus/bundler@3.6.1': + resolution: {integrity: sha512-vHSEx8Ku9x/gfIC6k4xb8J2nTxagLia0KvZkPZhxfkD1+n8i+Dj4BZPWTmv+kCA17RbgAvECG0XRZ0/ZEspQBQ==} + engines: {node: '>=18.0'} + peerDependencies: + '@docusaurus/faster': '*' + peerDependenciesMeta: + '@docusaurus/faster': + optional: true + + '@docusaurus/core@3.6.1': + resolution: {integrity: sha512-cDKxPihiM2z7G+4QtpTczS7uxNfNG6naSqM65OmAJET0CFRHbc9mDlLFtQF0lsVES91SHqfcGaaLZmi2FjdwWA==} engines: {node: '>=18.0'} hasBin: true peerDependencies: @@ -969,90 +1567,94 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/cssnano-preset@3.5.2': - resolution: {integrity: sha512-D3KiQXOMA8+O0tqORBrTOEQyQxNIfPm9jEaJoALjjSjc2M/ZAWcUfPQEnwr2JB2TadHw2gqWgpZckQmrVWkytA==} + '@docusaurus/cssnano-preset@3.6.1': + resolution: {integrity: sha512-ZxYUmNeyQHW2w4/PJ7d07jQDuxzmKr9uPAQ6IVe5dTkeIeV0mDBB3jOLeJkNoI42Ru9JKEqQ9aVDtM9ct6QHnw==} + engines: {node: '>=18.0'} + + '@docusaurus/faster@3.6.1': + resolution: {integrity: sha512-W3a9m7Q/fEeOpOw9/XktLCHRtp1sV2AdZWMCjH3kP1jY1TDyLFFiHJ0+1uwVpOw4/oPJqZSTRKP+IdW4+65NgQ==} engines: {node: '>=18.0'} - '@docusaurus/logger@3.5.2': - resolution: {integrity: sha512-LHC540SGkeLfyT3RHK3gAMK6aS5TRqOD4R72BEU/DE2M/TY8WwEUAMY576UUc/oNJXv8pGhBmQB6N9p3pt8LQw==} + '@docusaurus/logger@3.6.1': + resolution: {integrity: sha512-OvetI/nnOMBSqCkUzKAQhnIjhxduECK4qTu3tq/8/h/qqvLsvKURojm04WPE54L+Uy+UXMas0hnbBJd8zDlEOw==} engines: {node: '>=18.0'} - '@docusaurus/lqip-loader@3.5.2': - resolution: {integrity: sha512-yUD90PgwbGciCHHiQTWXZvpLv9nVTpXrX8Ilz5Sl6oJ1bwnLgGsbl7h+EseVbwBnKhVCoujW/EKRU6+3HqeeXQ==} + '@docusaurus/lqip-loader@3.6.1': + resolution: {integrity: sha512-H/VVvnvFupFhQ81FuTyA/XHxEZPKh99T6Wg6KgN+/yvcn7869RdgrlDhKDnXZ7j2u80eFsVNjAcPfW1cSAtK6A==} engines: {node: '>=18.0'} - '@docusaurus/mdx-loader@3.5.2': - resolution: {integrity: sha512-ku3xO9vZdwpiMIVd8BzWV0DCqGEbCP5zs1iHfKX50vw6jX8vQo0ylYo1YJMZyz6e+JFJ17HYHT5FzVidz2IflA==} + '@docusaurus/mdx-loader@3.6.1': + resolution: {integrity: sha512-KPIsYi0S3X3/rNrW3V1fgOu5t6ahYWc31zTHHod8pacFxdmk9Uf6uuw+Jd6Cly1ilgal+41Ku+s0gmMuqKqiqg==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/module-type-aliases@3.5.2': - resolution: {integrity: sha512-Z+Xu3+2rvKef/YKTMxZHsEXp1y92ac0ngjDiExRdqGTmEKtCUpkbNYH8v5eXo5Ls+dnW88n6WTa+Q54kLOkwPg==} + '@docusaurus/module-type-aliases@3.6.1': + resolution: {integrity: sha512-J+q1jgm7TnEfVIUZImSFeLA1rghb6nwtoB9siHdcgKpDqFJ9/S7xhQL2aEKE7iZMZYzpu+2F390E9A7GkdEJNA==} peerDependencies: react: '*' react-dom: '*' - '@docusaurus/plugin-client-redirects@3.5.2': - resolution: {integrity: sha512-GMU0ZNoVG1DEsZlBbwLPdh0iwibrVZiRfmdppvX17SnByCVP74mb/Nne7Ss7ALgxQLtM4IHbXi8ij90VVjAJ+Q==} + '@docusaurus/plugin-client-redirects@3.6.1': + resolution: {integrity: sha512-gY1LEQw4zSLSPNVxZk9mDj5ct+sJNux0SiY1PbMiI9sK8xXqkTC7QuRyrxRPelSZX9K4nyhK8PjYbVXAN+GUWQ==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-content-blog@3.5.2': - resolution: {integrity: sha512-R7ghWnMvjSf+aeNDH0K4fjyQnt5L0KzUEnUhmf1e3jZrv3wogeytZNN6n7X8yHcMsuZHPOrctQhXWnmxu+IRRg==} + '@docusaurus/plugin-content-blog@3.6.1': + resolution: {integrity: sha512-FUmsn3xg/XD/K/4FQd8XHrs92aQdZO5LUtpHnRvO1/6DY87SMz6B6ERAN9IGQQld//M2/LVTHkZy8oVhQZQHIQ==} engines: {node: '>=18.0'} peerDependencies: '@docusaurus/plugin-content-docs': '*' react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-content-docs@3.5.2': - resolution: {integrity: sha512-Bt+OXn/CPtVqM3Di44vHjE7rPCEsRCB/DMo2qoOuozB9f7+lsdrHvD0QCHdBs0uhz6deYJDppAr2VgqybKPlVQ==} + '@docusaurus/plugin-content-docs@3.6.1': + resolution: {integrity: sha512-Uq8kyn5DYCDmkUlB9sWChhWghS4lUFNiQU+RXcAXJ3qCVXsBpPsh6RF+npQG1N+j4wAbjydM1iLLJJzp+x3eMQ==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-content-pages@3.5.2': - resolution: {integrity: sha512-WzhHjNpoQAUz/ueO10cnundRz+VUtkjFhhaQ9jApyv1a46FPURO4cef89pyNIOMny1fjDz/NUN2z6Yi+5WUrCw==} + '@docusaurus/plugin-content-pages@3.6.1': + resolution: {integrity: sha512-TZtL+2zq20gqGalzoIT2rEF1T4YCZ26jTvlCJXs78+incIajfdHtmdOq7rQW0oV7oqTjpGllbp788nY/vY9jgw==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-debug@3.5.2': - resolution: {integrity: sha512-kBK6GlN0itCkrmHuCS6aX1wmoWc5wpd5KJlqQ1FyrF0cLDnvsYSnh7+ftdwzt7G6lGBho8lrVwkkL9/iQvaSOA==} + '@docusaurus/plugin-debug@3.6.1': + resolution: {integrity: sha512-DeKPZtoVExDSYCbzoz7y5Dhc6+YPqRWfVGwEEUyKopSyQYefp0OV8hvASmbJCn2WyThRgspOUhog3FSEhz+agw==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-google-analytics@3.5.2': - resolution: {integrity: sha512-rjEkJH/tJ8OXRE9bwhV2mb/WP93V441rD6XnM6MIluu7rk8qg38iSxS43ga2V2Q/2ib53PcqbDEJDG/yWQRJhQ==} + '@docusaurus/plugin-google-analytics@3.6.1': + resolution: {integrity: sha512-ZEoERiDHxSfhaEeT35ukQ892NzGHWiUvfxUsnPiRuGEhMoQlxMSp60shBuSZ1sUKuZlndoEl5qAXJg09Wls/Sg==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-google-gtag@3.5.2': - resolution: {integrity: sha512-lm8XL3xLkTPHFKKjLjEEAHUrW0SZBSHBE1I+i/tmYMBsjCcUB5UJ52geS5PSiOCFVR74tbPGcPHEV/gaaxFeSA==} + '@docusaurus/plugin-google-gtag@3.6.1': + resolution: {integrity: sha512-u/E9vXUsZxYaV6Brvfee8NiH/iR0cMml9P/ifz4EpH/Jfxdbw8rbCT0Nm/h7EFgEY48Uqkl5huSbIvFB9n8aTQ==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-google-tag-manager@3.5.2': - resolution: {integrity: sha512-QkpX68PMOMu10Mvgvr5CfZAzZQFx8WLlOiUQ/Qmmcl6mjGK6H21WLT5x7xDmcpCoKA/3CegsqIqBR+nA137lQg==} + '@docusaurus/plugin-google-tag-manager@3.6.1': + resolution: {integrity: sha512-By+NKkGYV8tSo8/RyS1OXikOtqsko5jJZ/uioJfBjsBGgSbiMJ+Y/HogFBke0mgSvf7NPGKZTbYm5+FJ8YUtPQ==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/plugin-ideal-image@3.5.2': - resolution: {integrity: sha512-FnHi3a5DjYRvjN1XbXRe1Cmiqfc+tAI2VmThN1Mr9teLB0ibuRi++P98q6+KyamBWKrJmuskWLMdr71acwHM8Q==} + '@docusaurus/plugin-ideal-image@3.6.1': + resolution: {integrity: sha512-hiGRPPlsM02aEOPlQc9rVnrckbVR6HswG7yDpZOtBEhw+ysXFsl/8gzAxFBL4ogKjN28WrlMCn/6IIkxY/EyOQ==} engines: {node: '>=18.0'} peerDependencies: jimp: '*' @@ -1062,15 +1664,15 @@ packages: jimp: optional: true - '@docusaurus/plugin-sitemap@3.5.2': - resolution: {integrity: sha512-DnlqYyRAdQ4NHY28TfHuVk414ft2uruP4QWCH//jzpHjqvKyXjj2fmDtI8RPUBh9K8iZKFMHRnLtzJKySPWvFA==} + '@docusaurus/plugin-sitemap@3.6.1': + resolution: {integrity: sha512-i8R/GTKew4Cufb+7YQTwfPcNOhKTJzZ1VZ5OqQwI9c3pZK2TltQyhqKDVN94KCTbSSKvOYYytYfRAB2uPnH1/A==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/preset-classic@3.5.2': - resolution: {integrity: sha512-3ihfXQ95aOHiLB5uCu+9PRy2gZCeSZoDcqpnDvf3B+sTrMvMTr8qRUzBvWkoIqc82yG5prCboRjk1SVILKx6sg==} + '@docusaurus/preset-classic@3.6.1': + resolution: {integrity: sha512-b90Y1XRH9e+oa/E3NmiFEFOwgYUd+knFcZUy81nM3FJs038WbEA0T55NQsuPW0s7nOsCShQ7dVFyKxV+Wp31Nw==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 @@ -1093,62 +1695,55 @@ packages: sharp: optional: true - '@docusaurus/theme-classic@3.5.2': - resolution: {integrity: sha512-XRpinSix3NBv95Rk7xeMF9k4safMkwnpSgThn0UNQNumKvmcIYjfkwfh2BhwYh/BxMXQHJ/PdmNh22TQFpIaYg==} + '@docusaurus/theme-classic@3.6.1': + resolution: {integrity: sha512-5lVUmIXk7zp+n9Ki2lYWrmhbd6mssOlKCnnDJvY4QDi3EgjRisIu5g4yKXoWTIbiqE7m7q/dS9cbeShEtfkKng==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/theme-common@3.5.2': - resolution: {integrity: sha512-QXqlm9S6x9Ibwjs7I2yEDgsCocp708DrCrgHgKwg2n2AY0YQ6IjU0gAK35lHRLOvAoJUfCKpQAwUykB0R7+Eew==} + '@docusaurus/theme-common@3.6.1': + resolution: {integrity: sha512-18iEYNpMvarGfq9gVRpGowSZD24vZ39Iz4acqaj64180i54V9el8tVnhNr/wRvrUm1FY30A1NHLqnMnDz4rYEQ==} engines: {node: '>=18.0'} peerDependencies: '@docusaurus/plugin-content-docs': '*' react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/theme-search-algolia@3.5.2': - resolution: {integrity: sha512-qW53kp3VzMnEqZGjakaV90sst3iN1o32PH+nawv1uepROO8aEGxptcq2R5rsv7aBShSRbZwIobdvSYKsZ5pqvA==} + '@docusaurus/theme-search-algolia@3.6.1': + resolution: {integrity: sha512-BjmuiFRpQP1WEm8Mzu1Bb0Wdas6G65VHXDDNr7XTKgbstxalE6vuxt0ioXTDFS2YVep5748aVhKvnxR9gm2Liw==} engines: {node: '>=18.0'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/theme-translations@3.5.2': - resolution: {integrity: sha512-GPZLcu4aT1EmqSTmbdpVrDENGR2yObFEX8ssEFYTCiAIVc0EihNSdOIBTazUvgNqwvnoU1A8vIs1xyzc3LITTw==} + '@docusaurus/theme-translations@3.6.1': + resolution: {integrity: sha512-bNm5G6sueUezvyhsBegA1wwM38yW0BnqpZTE9KHO2yKnkERNMaV5x/yPJ/DNCOHjJtCcJ5Uz55g2AS75Go31xA==} engines: {node: '>=18.0'} - '@docusaurus/tsconfig@3.5.2': - resolution: {integrity: sha512-rQ7toURCFnWAIn8ubcquDs0ewhPwviMzxh6WpRjBW7sJVCXb6yzwUaY3HMNa0VXCFw+qkIbFywrMTf+Pb4uHWQ==} + '@docusaurus/tsconfig@3.6.1': + resolution: {integrity: sha512-RvjMG9M9YK8N/I5oudqJed8jjfWGI7csr4XCkGXBToNkkoi2QgkTz2DxH+obKdfLejQaASdIMynYaE5Lv7Qw9Q==} - '@docusaurus/types@3.5.2': - resolution: {integrity: sha512-N6GntLXoLVUwkZw7zCxwy9QiuEXIcTVzA9AkmNw16oc0AP3SXLrMmDMMBIfgqwuKWa6Ox6epHol9kMtJqekACw==} + '@docusaurus/types@3.6.1': + resolution: {integrity: sha512-hCB1hj9DYutVYBisnPNobz9SzEmCcf1EetJv09O49Cov3BqOkm+vnnjB3d957YJMtpLGQoKBeN/FF1DZ830JwQ==} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - '@docusaurus/utils-common@3.5.2': - resolution: {integrity: sha512-i0AZjHiRgJU6d7faQngIhuHKNrszpL/SHQPgF1zH4H+Ij6E9NBYGy6pkcGWToIv7IVPbs+pQLh1P3whn0gWXVg==} + '@docusaurus/utils-common@3.6.1': + resolution: {integrity: sha512-LX1qiTiC0aS8c92uZ+Wj2iNCNJyYZJIKY8/nZDKNMBfo759VYVS3RX3fKP3DznB+16sYp7++MyCz/T6fOGaRfw==} engines: {node: '>=18.0'} - peerDependencies: - '@docusaurus/types': '*' - peerDependenciesMeta: - '@docusaurus/types': - optional: true - '@docusaurus/utils-validation@3.5.2': - resolution: {integrity: sha512-m+Foq7augzXqB6HufdS139PFxDC5d5q2QKZy8q0qYYvGdI6nnlNsGH4cIGsgBnV7smz+mopl3g4asbSDvMV0jA==} + '@docusaurus/utils-validation@3.6.1': + resolution: {integrity: sha512-+iMd6zRl5cJQm7nUP+7pSO/oAXsN79eHO34ME7l2YJt4GEAr70l5kkD58u2jEPpp+wSXT70c7x2A2lzJI1E8jw==} engines: {node: '>=18.0'} - '@docusaurus/utils@3.5.2': - resolution: {integrity: sha512-33QvcNFh+Gv+C2dP9Y9xWEzMgf3JzrpL2nW9PopidiohS1nDcyknKRx2DWaFvyVTTYIkkABVSr073VTj/NITNA==} + '@docusaurus/utils@3.6.1': + resolution: {integrity: sha512-nS3WCvepwrnBEgSG5vQu40XG95lC9Jeh/odV5u5IhU1eQFEGDst9xBi6IK5yZdsGvbuaXBZLZtOqWYtuuFa/rQ==} engines: {node: '>=18.0'} - peerDependencies: - '@docusaurus/types': '*' - peerDependenciesMeta: - '@docusaurus/types': - optional: true + + '@dual-bundle/import-meta-resolve@4.1.0': + resolution: {integrity: sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==} '@emnapi/runtime@1.2.0': resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} @@ -1182,8 +1777,8 @@ packages: resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} engines: {node: ^10.12.0 || >=12.0.0} - '@fontsource-variable/overpass@5.1.0': - resolution: {integrity: sha512-Fz7+ZTNSW6YeoTGHvUvDsydiW6bXt0pAbhUaL23FCnRZaRv5qqH+JNkkQdtj4R5qqrTwi5iAZn9r3dCJm+sDfw==} + '@fontsource-variable/overpass@5.1.1': + resolution: {integrity: sha512-/H4NQK3TsImPu+hyfm1oWwotxqErd2OpVtPlIchFsCRLHq0n637gwRV9J2WOeksvuG77tFTvBetubWhAAtqN7w==} '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} @@ -1340,12 +1935,27 @@ packages: '@mdx-js/mdx@3.0.1': resolution: {integrity: sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==} - '@mdx-js/react@3.0.1': - resolution: {integrity: sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==} + '@mdx-js/mdx@3.1.0': + resolution: {integrity: sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==} + + '@mdx-js/react@3.1.0': + resolution: {integrity: sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==} peerDependencies: '@types/react': '>=16' react: '>=16' + '@module-federation/runtime-tools@0.5.1': + resolution: {integrity: sha512-nfBedkoZ3/SWyO0hnmaxuz0R0iGPSikHZOAZ0N/dVSQaIzlffUo35B5nlC2wgWIc0JdMZfkwkjZRrnuuDIJbzg==} + + '@module-federation/runtime@0.5.1': + resolution: {integrity: sha512-xgiMUWwGLWDrvZc9JibuEbXIbhXg6z2oUkemogSvQ4LKvrl/n0kbqP1Blk669mXzyWbqtSp6PpvNdwaE1aN5xQ==} + + '@module-federation/sdk@0.5.1': + resolution: {integrity: sha512-exvchtjNURJJkpqjQ3/opdbfeT2wPKvrbnGnyRkrwW5o3FH1LaST1tkiNviT6OXTexGaVc2DahbdniQHVtQ7pA==} + + '@module-federation/webpack-bundler-runtime@0.5.1': + resolution: {integrity: sha512-mMhRFH0k2VjwHt3Jol9JkUsmI/4XlrAoBG3E0o7HoyoPYv1UFOWyqAflfANcUPgbYpvqmyLzDcO+3IT36LXnrA==} + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} @@ -1361,6 +1971,88 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@parcel/watcher-android-arm64@2.5.0': + resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.0': + resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.0': + resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.0': + resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.0': + resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.0': + resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.0': + resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.0': + resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.0': + resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.0': + resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.0': + resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.0': + resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.0': + resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} + engines: {node: '>= 10.0.0'} + '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} @@ -1376,6 +2068,67 @@ packages: '@polka/url@1.0.0-next.25': resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + '@rspack/binding-darwin-arm64@1.1.1': + resolution: {integrity: sha512-BnvGPWObGZ2ZVnxe4K3NKwAWxYubOJvfwporXWD3NgkzeV5xJqGBFWRDnr/nfsFpgCTI8goxK5db/wb7NVzLqg==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@1.1.1': + resolution: {integrity: sha512-aiwJRkPGAg99vCrG/C9I87Fh9TShOAkzpf2yeJEZL4gwTj9A8wrc/xlrCFn1BDkbPnGYz62oCR7z6JLIDgYLuA==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@1.1.1': + resolution: {integrity: sha512-2Z8YxH4+V0MiNhVQ2IFELDIFtykIdKgmOmGr/PuRQMHMxSn8AKo5uqBD30sZqe0+gryplZwK3hyrBETHOmSltQ==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-arm64-musl@1.1.1': + resolution: {integrity: sha512-l+cJd3wAxBt523Min7qN+G5s3SU0rif9Yq2AFWWl+R6IvmnMlMq6sAAyiyogUidFmJ5XIKSJJBTBnvLF3g4ezg==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-x64-gnu@1.1.1': + resolution: {integrity: sha512-goaDDrXNulR7FcvUfj8AjhF3g7IXUttjQ4QsfY2xz7s20tDETlq5HpcM2A8GEI6lqkPAv/ITU0AynLK7bfyr4A==} + cpu: [x64] + os: [linux] + + '@rspack/binding-linux-x64-musl@1.1.1': + resolution: {integrity: sha512-T4RRn9ycxUHAfZJpfNRy+DdfevTXIZqox+NNg/N3d+Pqj5QS3zqpHBfPLC2mIIN1dw55BoshRIP2C1hUG0Fk6g==} + cpu: [x64] + os: [linux] + + '@rspack/binding-win32-arm64-msvc@1.1.1': + resolution: {integrity: sha512-FHIPpueFc/+vWdZeVWRYWW0Z0IsDIHy+WhWxITeLjOVGsUN4rhaztYOausD7WsOlOhmR0SddeOYtRs/BR35wig==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@1.1.1': + resolution: {integrity: sha512-pgXE45ATK/Iil/oXlqaGoWZ0x3SoQk4dAjJGK7TzQuek6UEoJbLQL+W1ufe/iUxz67ICAmUvq5NH2ftOhEE2SA==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@1.1.1': + resolution: {integrity: sha512-z/kdbB+uhMi+H4podjTE7bfUpahACUuPOZPUtAAA6PMgRyiigBTK5UFYN35D30MONwZP4yNiLvPjurwiLw7EpA==} + cpu: [x64] + os: [win32] + + '@rspack/binding@1.1.1': + resolution: {integrity: sha512-BRFliHbErqWrUo9X9bdik9WTRi6EgrJSQbbUiVeIYgW4gzYdfHUohgTkWo2Byu36LZolKrEjq/Uq2A8q/tc0YA==} + + '@rspack/core@1.1.1': + resolution: {integrity: sha512-khYNAho2evyc7N5mYk4K6B587ou/dN1CDCqWrSDeZZNFFQHtuEp5T3kL1ntsKY7agObQhI60osCYaxFUPs0yww==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@rspack/lite-tapable@1.0.1': + resolution: {integrity: sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==} + engines: {node: '>=16.0.0'} + '@rushstack/eslint-patch@1.0.6': resolution: {integrity: sha512-Myxw//kzromB9yWgS8qYGuGVf91oBUUJpNvy5eM50sqvmKLbKjwLxohJnkWGTeeI9v9IBMtPLxz5Gc60FIfvCA==} @@ -1493,6 +2246,145 @@ packages: resolution: {integrity: sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==} engines: {node: '>=14'} + '@swc/core-darwin-arm64@1.9.2': + resolution: {integrity: sha512-nETmsCoY29krTF2PtspEgicb3tqw7Ci5sInTI03EU5zpqYbPjoPH99BVTjj0OsF53jP5MxwnLI5Hm21lUn1d6A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.9.2': + resolution: {integrity: sha512-9gD+bwBz8ZByjP6nZTXe/hzd0tySIAjpDHgkFiUrc+5zGF+rdTwhcNrzxNHJmy6mw+PW38jqII4uspFHUqqxuQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.9.2': + resolution: {integrity: sha512-kYq8ief1Qrn+WmsTWAYo4r+Coul4dXN6cLFjiPZ29Cv5pyU+GFvSPAB4bEdMzwy99rCR0u2P10UExaeCjurjvg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.9.2': + resolution: {integrity: sha512-n0W4XiXlmEIVqxt+rD3ZpkogsEWUk1jJ+i5bQNgB+1JuWh0fBE8c/blDgTQXa0GB5lTPVDZQussgdNOCnAZwiA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.9.2': + resolution: {integrity: sha512-8xzrOmsyCC1zrx2Wzx/h8dVsdewO1oMCwBTLc1gSJ/YllZYTb04pNm6NsVbzUX2tKddJVRgSJXV10j/NECLwpA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.9.2': + resolution: {integrity: sha512-kZrNz/PjRQKcchWF6W292jk3K44EoVu1ad5w+zbS4jekIAxsM8WwQ1kd+yjUlN9jFcF8XBat5NKIs9WphJCVXg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.9.2': + resolution: {integrity: sha512-TTIpR4rjMkhX1lnFR+PSXpaL83TrQzp9znRdp2TzYrODlUd/R20zOwSo9vFLCyH6ZoD47bccY7QeGZDYT3nlRg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.9.2': + resolution: {integrity: sha512-+Eg2d4icItKC0PMjZxH7cSYFLWk0aIp94LNmOw6tPq0e69ax6oh10upeq0D1fjWsKLmOJAWEvnXlayZcijEXDw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.9.2': + resolution: {integrity: sha512-nLWBi4vZDdM/LkiQmPCakof8Dh1/t5EM7eudue04V1lIcqx9YHVRS3KMwEaCoHLGg0c312Wm4YgrWQd9vwZ5zQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.9.2': + resolution: {integrity: sha512-ik/k+JjRJBFkXARukdU82tSVx0CbExFQoQ78qTO682esbYXzjdB5eLVkoUbwen299pnfr88Kn4kyIqFPTje8Xw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.9.2': + resolution: {integrity: sha512-dYyEkO6mRYtZFpnOsnYzv9rY69fHAHoawYOjGOEcxk9WYtaJhowMdP/w6NcOKnz2G7GlZaenjkzkMa6ZeQeMsg==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/html-darwin-arm64@1.9.2': + resolution: {integrity: sha512-ZUdSXezeJrYgzrUv5alsjBI5wPMks/DyskHypOD6XwFJq1rFYRlFkiiwgf1U/uVSZnseIoXezBURnPliWpkrHQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/html-darwin-x64@1.9.2': + resolution: {integrity: sha512-5/8xDeP10VjEP5MhMAe83EDeh3rlB+BHbZB6mVFxP1NuEfY1DlW+z3+wPKp0qsvkPcK+82nZu43hystTkCXHhQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/html-linux-arm-gnueabihf@1.9.2': + resolution: {integrity: sha512-AJQ8FpbVC2hx0upqe15b/i8PUpye5B8W0sEw8bOz/PAV7Ub+P+qFXBPmu1qFz+GLtIE+yAvhA8GRrReXJvALQQ==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/html-linux-arm64-gnu@1.9.2': + resolution: {integrity: sha512-rhTeDQjXo9gYK8OPGTsgXl1a0pKPnXLHeF2DfRGpAdOqChRdS3GEOX2Qawl7+fRjJ5UGs0/lOXo+BWwVcPyrSw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/html-linux-arm64-musl@1.9.2': + resolution: {integrity: sha512-zJGhfYARjVaQ1bJ0NBsmoG7GYqXx/Qi5WnDEvq+jK5Ue9u6++Xeit5X9vVx67+B20w0ecngM5RqD9Yoc34MT4g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/html-linux-x64-gnu@1.9.2': + resolution: {integrity: sha512-acbKaR7/dnYJ8g0GeQGEmWTmMuEMr3+8blJJ/ksxHjIopsWjNplLaKNCM8GfvF7vjIr9zgtLgP3NB+e3OLagKg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/html-linux-x64-musl@1.9.2': + resolution: {integrity: sha512-wuNhqpkN1ZZWj/4RGHH+Cz1tjs7NfEu53en13YzDjwfPxsIfnbksQ0UD/uEVp8l8alsniJ9EokzXgfenmjDvlQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/html-win32-arm64-msvc@1.9.2': + resolution: {integrity: sha512-x2H2aWZX4HbU09rDWsf6W7fS0ApJwNBlthBDlMZj6gGzTgkRQtNwD/gpg3eRZmu5DxsnmBZ2a/rxxiU1IMv5mA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/html-win32-ia32-msvc@1.9.2': + resolution: {integrity: sha512-4bMY6HHAEVtX8buJm69XVs5sucxce9gyEzcNCXy2rfXAG9kxClE/ZbMWhXl3z6nYRWKBuoPoaL2eio1dEAvyTQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/html-win32-x64-msvc@1.9.2': + resolution: {integrity: sha512-HbxGfXT3KzSlo8uvoiQL8Q9ZnWzxHGYoe2emwFS5FeQuR01LMF0MWB3r2NhAYGx+DlD2h/3BR/hSM1qiDjl9VQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/html@1.9.2': + resolution: {integrity: sha512-HoRqmYbxribu9thQ8vDshh6mgVcs2MSF0lEdoRBUBGcXbLwOMdCQMncbJoVguy0ehmmOzBwt+9qnP58IY+RWbg==} + engines: {node: '>=14'} + + '@swc/types@0.1.15': + resolution: {integrity: sha512-XKaZ+dzDIQ9Ot9o89oJQ/aluI17+VvUnIpYJTcZtvv1iYX6MzHh3Ik2CSR7MdPKpPwfZXHBeCingb2b4PoDVdw==} + '@szmarczak/http-timer@5.0.1': resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} @@ -1591,9 +2483,6 @@ packages: '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/minimist@1.2.5': - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} @@ -1603,8 +2492,8 @@ packages: '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} - '@types/node@22.7.4': - resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} + '@types/node@22.9.0': + resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1624,8 +2513,8 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react-dom@18.3.0': - resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + '@types/react-dom@18.3.1': + resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==} '@types/react-router-config@5.0.11': resolution: {integrity: sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==} @@ -1636,8 +2525,8 @@ packages: '@types/react-router@5.1.20': resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} - '@types/react@18.3.10': - resolution: {integrity: sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==} + '@types/react@18.3.12': + resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} @@ -1742,48 +2631,93 @@ packages: '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + '@webassemblyjs/floating-point-hex-parser@1.11.6': resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + '@webassemblyjs/helper-api-error@1.11.6': resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + '@webassemblyjs/helper-buffer@1.12.1': resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + '@webassemblyjs/helper-numbers@1.11.6': resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + '@webassemblyjs/helper-wasm-bytecode@1.11.6': resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + '@webassemblyjs/helper-wasm-section@1.12.1': resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + '@webassemblyjs/ieee754@1.11.6': resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + '@webassemblyjs/leb128@1.11.6': resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + '@webassemblyjs/utf8@1.11.6': resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + '@webassemblyjs/wasm-edit@1.12.1': resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + '@webassemblyjs/wasm-gen@1.12.1': resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + '@webassemblyjs/wasm-opt@1.12.1': resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + '@webassemblyjs/wasm-parser@1.12.1': resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + '@webassemblyjs/wast-printer@1.12.1': resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -1818,6 +2752,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + address@1.2.2: resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} engines: {node: '>= 10.0.0'} @@ -1858,6 +2797,10 @@ packages: algoliasearch@4.24.0: resolution: {integrity: sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==} + algoliasearch@5.14.2: + resolution: {integrity: sha512-aYjI4WLamMxbhdJ2QAA99VbDCJOGzMOdT2agh57bi40n86ufkhZSIAf6mkocr7NmtBLtwCnSHvD5NJ+Ky5elWw==} + engines: {node: '>= 14.0.0'} + all-contributors-cli@6.26.1: resolution: {integrity: sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==} engines: {node: '>=4'} @@ -1943,10 +2886,6 @@ packages: resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} engines: {node: '>= 0.4'} - arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} - astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -1976,8 +2915,8 @@ packages: b4a@1.6.6: resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==} - babel-loader@9.1.3: - resolution: {integrity: sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==} + babel-loader@9.2.1: + resolution: {integrity: sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==} engines: {node: '>= 14.15.0'} peerDependencies: '@babel/core': ^7.12.0 @@ -1991,6 +2930,11 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-corejs2@0.4.12: + resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-corejs3@0.10.6: resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==} peerDependencies: @@ -2001,6 +2945,11 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-regenerator@0.6.3: + resolution: {integrity: sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -2078,8 +3027,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - browserslist@4.24.0: - resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2120,10 +3069,6 @@ packages: camel-case@4.1.2: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} - camelcase-keys@7.0.2: - resolution: {integrity: sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==} - engines: {node: '>=12'} - camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -2142,8 +3087,8 @@ packages: caniuse-lite@1.0.30001651: resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==} - caniuse-lite@1.0.30001664: - resolution: {integrity: sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==} + caniuse-lite@1.0.30001680: + resolution: {integrity: sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2330,8 +3275,9 @@ packages: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} - consola@2.15.3: - resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} + consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} consolidated-events@2.0.2: resolution: {integrity: sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ==} @@ -2375,8 +3321,11 @@ packages: core-js-compat@3.38.0: resolution: {integrity: sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==} - core-js-pure@3.38.0: - resolution: {integrity: sha512-8balb/HAXo06aHP58mZMtXgD8vcnXz9tUDePgqBgJgKdmTlMt+jw3ujqniuBDQXMvTzxnMpxHFeuSM3g1jWQuQ==} + core-js-compat@3.39.0: + resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} + + core-js-pure@3.39.0: + resolution: {integrity: sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==} core-js@3.38.0: resolution: {integrity: sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug==} @@ -2397,6 +3346,15 @@ packages: typescript: optional: true + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2414,8 +3372,8 @@ packages: peerDependencies: postcss: ^8.0.9 - css-functions-list@3.2.2: - resolution: {integrity: sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==} + css-functions-list@3.2.3: + resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} engines: {node: '>=12 || >=16'} css-line-break@2.1.0: @@ -2472,6 +3430,10 @@ packages: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-tree@3.0.1: + resolution: {integrity: sha512-8Fxxv+tGhORlshCdCwnNJytvlvq46sOLSYEx2ZIGurahWvMucSRnyjPA3AmrMq4VPRYbHVpWj5VkiVasrM2H4Q==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -2552,18 +3514,19 @@ packages: supports-color: optional: true - decamelize-keys@1.1.1: - resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} - engines: {node: '>=0.10.0'} - + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - decamelize@5.0.1: - resolution: {integrity: sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==} - engines: {node: '>=10'} - decode-named-character-reference@1.0.2: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} @@ -2622,6 +3585,11 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -2713,12 +3681,12 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.29: - resolution: {integrity: sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==} - electron-to-chromium@1.5.6: resolution: {integrity: sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==} + electron-to-chromium@1.5.63: + resolution: {integrity: sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2757,6 +3725,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -2764,6 +3736,10 @@ packages: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} + es-abstract@1.23.5: + resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} + engines: {node: '>= 0.4'} + es-define-property@1.0.0: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} @@ -2790,6 +3766,12 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -2982,11 +3964,14 @@ packages: estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-util-scope@1.0.0: + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} + estree-util-to-js@2.0.0: resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} - estree-util-value-to-estree@3.1.2: - resolution: {integrity: sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==} + estree-util-value-to-estree@3.2.1: + resolution: {integrity: sha512-Vt2UOjyPbNQQgT5eJh+K5aATti0OjCIAGc9SgMdOFYbohuifsWclR74l0iZTJwePMgWYdX1hlVS+dedH9XV8kw==} estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} @@ -3059,9 +4044,6 @@ packages: fast-uri@3.0.1: resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==} - fast-url-parser@1.1.3: - resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} - fastest-levenshtein@1.0.16: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} @@ -3088,9 +4070,9 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} - file-entry-cache@7.0.2: - resolution: {integrity: sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==} - engines: {node: '>=12.0.0'} + file-entry-cache@9.1.0: + resolution: {integrity: sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==} + engines: {node: '>=18'} file-loader@6.2.0: resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==} @@ -3138,6 +4120,10 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@5.0.0: + resolution: {integrity: sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==} + engines: {node: '>=18'} + flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true @@ -3145,6 +4131,9 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} @@ -3331,10 +4320,6 @@ packages: handle-thing@2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} - hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -3379,8 +4364,8 @@ packages: hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - hast-util-raw@9.0.4: - resolution: {integrity: sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==} + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} hast-util-to-estree@3.1.0: resolution: {integrity: sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==} @@ -3388,6 +4373,9 @@ packages: hast-util-to-jsx-runtime@2.3.0: resolution: {integrity: sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==} + hast-util-to-jsx-runtime@2.3.2: + resolution: {integrity: sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==} + hast-util-to-parse5@8.0.0: resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} @@ -3410,10 +4398,6 @@ packages: hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} - hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} @@ -3521,6 +4505,14 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@6.0.2: + resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==} + engines: {node: '>= 4'} + image-size@1.1.1: resolution: {integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==} engines: {node: '>=16.x'} @@ -3529,8 +4521,8 @@ packages: immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} - immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + immutable@5.0.2: + resolution: {integrity: sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==} import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} @@ -3552,12 +4544,8 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - - infima@0.2.0-alpha.44: - resolution: {integrity: sha512-tuRkUSO/lB3rEhLJk25atwAjgLuzq070+pOW8XcvpHky/YbENnRRdPd85IBkyeTgttmOy5ah+yHYsK1HhUd4lQ==} + infima@0.2.0-alpha.45: + resolution: {integrity: sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==} engines: {node: '>=12'} inflight@1.0.6: @@ -3583,6 +4571,9 @@ packages: inline-style-parser@0.2.3: resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==} + inline-style-parser@0.2.4: + resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + inquirer@7.3.3: resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} engines: {node: '>=8.0.0'} @@ -3724,10 +4715,6 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - is-plain-obj@3.0.0: resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} engines: {node: '>=10'} @@ -3848,6 +4835,11 @@ packages: engines: {node: '>=4'} hasBin: true + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -3901,8 +4893,11 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - known-css-properties@0.29.0: - resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==} + known-css-properties@0.34.0: + resolution: {integrity: sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==} + + known-css-properties@0.35.0: + resolution: {integrity: sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==} latest-version@7.0.0: resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} @@ -3919,6 +4914,70 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lightningcss-darwin-arm64@1.28.1: + resolution: {integrity: sha512-VG3vvzM0m/rguCdm76DdobNeNJnHK+jWcdkNLFWHLh9YCotRvbRIt45JxwcHlIF8TDqWStVLTdghq5NaigVCBQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.28.1: + resolution: {integrity: sha512-O7ORdislvKfMohFl4Iq7fxKqdJOuuxArcglVI3amuFO5DJ0wfV3Gxgi1JRo49slfr7OVzJQEHLG4muTWYM5cTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.28.1: + resolution: {integrity: sha512-b7sF89B31kYYijxVcFO7l5u6UNA862YstNu+3YbLl/IQKzveL4a5cwR5cdpG+OOhErg/c2u9WCmzZoX2I5GBvw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.28.1: + resolution: {integrity: sha512-p61kXwvhUDLLzkWHjzSFfUBW/F0iy3jr3CWi3k8SKULtJEsJXTI9DqRm9EixxMSe2AMBQBt4auTYiQL4B1N51A==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.28.1: + resolution: {integrity: sha512-iO+fN9hOMmzfwqcG2/BgUtMKD48H2JO/SXU44fyIwpY2veb65QF5xiRrQ9l1FwIxbGK3231KBYCtAqv+xf+NsQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.28.1: + resolution: {integrity: sha512-dnMHeXEmCUzHHZjaDpQBYuBKcN9nPC3nPFKl70bcj5Bkn5EmkcgEqm5p035LKOgvAwk1XwLpQCML6pXmCwz0NQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.28.1: + resolution: {integrity: sha512-7vWDISaMUn+oo2TwRdf2hl/BLdPxvywv9JKEqNZB/0K7bXwV4XE9wN/C2sAp1gGuh6QBA8lpjF4JIPt3HNlCHA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.28.1: + resolution: {integrity: sha512-IHCu9tVGP+x5BCpA2rF3D04DBokcBza/a8AuHQU+1AiMKubuMegPwcL7RatBgK4ztFHeYnnD5NdhwhRfYMAtNA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.28.1: + resolution: {integrity: sha512-Erm72kHmMg/3h350PTseskz+eEGBM17Fuu79WW2Qqt0BfWSF1jHHc12lkJCWMYl5jcBHPs5yZdgNHtJ7IJS3Uw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.28.1: + resolution: {integrity: sha512-ZPQtvx+uQBzrSdHH8p4H3M9Alue+x369TPZAA3b4K3d92FPhpZCuBG04+HQzspam9sVeID9mI6f3VRAs2ezaEA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.28.1: + resolution: {integrity: sha512-KRDkHlLlNj3DWh79CDt93fPlRJh2W1AuHV0ZSZAMMuN7lqlsZTV5842idfS1urWG8q9tc17velp1gCXhY7sLnQ==} + engines: {node: '>= 12.0.0'} + lilconfig@3.1.2: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} @@ -4000,24 +5059,15 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - - map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} - markdown-extensions@2.0.0: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} engines: {node: '>=16'} - markdown-table@3.0.3: - resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + markdown-table@2.0.0: + resolution: {integrity: sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} mathml-tag-names@2.1.3: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} @@ -4031,6 +5081,9 @@ packages: mdast-util-from-markdown@2.0.1: resolution: {integrity: sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==} + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-frontmatter@2.0.1: resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} @@ -4055,9 +5108,15 @@ packages: mdast-util-mdx-expression@2.0.0: resolution: {integrity: sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==} + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + mdast-util-mdx-jsx@3.1.2: resolution: {integrity: sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==} + mdast-util-mdx-jsx@3.1.3: + resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + mdast-util-mdx@3.0.0: resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} @@ -4073,6 +5132,9 @@ packages: mdast-util-to-markdown@2.1.0: resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==} + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} @@ -4082,6 +5144,12 @@ packages: mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + mdn-data@2.12.1: + resolution: {integrity: sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q==} + + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -4093,9 +5161,9 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} - meow@10.1.5: - resolution: {integrity: sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} @@ -4114,6 +5182,9 @@ packages: micromark-core-commonmark@2.0.1: resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==} + micromark-core-commonmark@2.0.2: + resolution: {integrity: sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==} + micromark-extension-directive@3.0.2: resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} @@ -4159,9 +5230,15 @@ packages: micromark-factory-destination@2.0.0: resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==} + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + micromark-factory-label@2.0.0: resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==} + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + micromark-factory-mdx-expression@2.0.1: resolution: {integrity: sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==} @@ -4171,72 +5248,122 @@ packages: micromark-factory-space@2.0.0: resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==} + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + micromark-factory-title@2.0.0: resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==} + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + micromark-factory-whitespace@2.0.0: resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==} + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + micromark-util-character@1.2.0: resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==} micromark-util-character@2.1.0: resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==} + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + micromark-util-chunked@2.0.0: resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==} + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + micromark-util-classify-character@2.0.0: resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==} + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + micromark-util-combine-extensions@2.0.0: resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==} + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + micromark-util-decode-numeric-character-reference@2.0.1: resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==} + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + micromark-util-decode-string@2.0.0: resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==} + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + micromark-util-encode@2.0.0: resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + micromark-util-events-to-acorn@2.0.2: resolution: {integrity: sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==} micromark-util-html-tag-name@2.0.0: resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==} + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + micromark-util-normalize-identifier@2.0.0: resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==} + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + micromark-util-resolve-all@2.0.0: resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==} + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + micromark-util-sanitize-uri@2.0.0: resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + micromark-util-subtokenize@2.0.1: resolution: {integrity: sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==} + micromark-util-subtokenize@2.0.2: + resolution: {integrity: sha512-xKxhkB62vwHUuuxHe9Xqty3UaAsizV2YKq5OV344u3hFBbf8zIYrhYOWhAQb94MtMPkjTOzzjJ/hid9/dR5vFA==} + micromark-util-symbol@1.1.0: resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==} micromark-util-symbol@2.0.0: resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + micromark-util-types@1.1.0: resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==} micromark-util-types@2.0.0: resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} + micromark-util-types@2.0.1: + resolution: {integrity: sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==} + micromark@4.0.0: resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==} - micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} - engines: {node: '>=8.6'} + micromark@4.0.1: + resolution: {integrity: sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==} micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} @@ -4279,12 +5406,8 @@ packages: resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - - mini-css-extract-plugin@2.9.0: - resolution: {integrity: sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==} + mini-css-extract-plugin@2.9.2: + resolution: {integrity: sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==} engines: {node: '>= 12.13.0'} peerDependencies: webpack: ^5.0.0 @@ -4299,10 +5422,6 @@ packages: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} - minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -4360,6 +5479,9 @@ packages: node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-emoji@2.1.3: resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} engines: {node: '>=18'} @@ -4383,10 +5505,6 @@ packages: normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - normalize-package-data@3.0.3: - resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} - engines: {node: '>=10'} - normalize-path@2.1.1: resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} engines: {node: '>=0.10.0'} @@ -4413,6 +5531,12 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + null-loader@4.0.1: + resolution: {integrity: sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -4421,6 +5545,10 @@ packages: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} + object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -4564,11 +5692,11 @@ packages: parse-numeric-range@1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} - parse5-htmlparser2-tree-adapter@7.0.0: - resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} - parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} @@ -4613,8 +5741,8 @@ packages: path-to-regexp@1.8.0: resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==} - path-to-regexp@2.2.1: - resolution: {integrity: sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==} + path-to-regexp@3.3.0: + resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} @@ -4632,8 +5760,8 @@ packages: periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} - picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -4776,14 +5904,14 @@ packages: peerDependencies: postcss: ^8.1.0 - postcss-modules-local-by-default@4.0.5: - resolution: {integrity: sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==} + postcss-modules-local-by-default@4.1.0: + resolution: {integrity: sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 - postcss-modules-scope@3.2.0: - resolution: {integrity: sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==} + postcss-modules-scope@3.2.1: + resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 @@ -4872,14 +6000,14 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-resolve-nested-selector@0.1.5: - resolution: {integrity: sha512-tum2m18S22ZSNjXatMG0FSk5ZL83pTttymeJx5Gzxg7RU0s1jNDU9rXltro4osQrukjyNormcb07IEjqEyPNaA==} + postcss-resolve-nested-selector@0.1.6: + resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} - postcss-safe-parser@6.0.0: - resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} - engines: {node: '>=12.0'} + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} peerDependencies: - postcss: ^8.3.3 + postcss: ^8.4.31 postcss-scss@4.0.9: resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} @@ -4887,14 +6015,14 @@ packages: peerDependencies: postcss: ^8.4.29 - postcss-selector-parser@6.1.1: - resolution: {integrity: sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==} - engines: {node: '>=4'} - postcss-selector-parser@6.1.2: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} + postcss-selector-parser@7.0.0: + resolution: {integrity: sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==} + engines: {node: '>=4'} + postcss-sort-media-queries@5.2.0: resolution: {integrity: sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==} engines: {node: '>=14.0.0'} @@ -4931,6 +6059,10 @@ packages: resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.2: resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} engines: {node: '>=10'} @@ -4993,9 +6125,6 @@ packages: pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} - punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -5004,11 +6133,11 @@ packages: resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==} engines: {node: '>=12.20'} - pushfeedback-react@0.1.44: - resolution: {integrity: sha512-2ZrySoKPTXr/H0o6DwBsRiGzwUgSzHLODC2iVu7dA8Sl2M7cG5RrDGdabdMDlYu9GwkRD5H1MqjRVb9Wyp4uWQ==} + pushfeedback-react@0.1.50: + resolution: {integrity: sha512-Bvtu/czdrty+ELfBoHMGO/2aqtb8roP4Hq2HImU95ohyr/8sj3jKCam33k51PLZPQ65IQ2Dg+EQtrOOqNKD/Wg==} - pushfeedback@0.1.44: - resolution: {integrity: sha512-eezqumWKeWu348bdL4TIiPCm1NJq6jr457CVCx9lCSQ61TDkOHOb/fUcaQMx4inPD/b4dw5G96NRiWBCe+deZw==} + pushfeedback@0.1.49: + resolution: {integrity: sha512-RbGrWT05MkXpXRCliZwirxkCKxEFtjGdFMq5dioQmYKqsfE9tnSM7CNv0axPC15E5tWfZ1UZMn9eg9cZahV3rQ==} qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} @@ -5142,10 +6271,6 @@ packages: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} - read-pkg-up@8.0.0: - resolution: {integrity: sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==} - engines: {node: '>=12'} - read-pkg@3.0.0: resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} engines: {node: '>=4'} @@ -5154,10 +6279,6 @@ packages: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} engines: {node: '>=8'} - read-pkg@6.0.0: - resolution: {integrity: sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==} - engines: {node: '>=12'} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -5180,18 +6301,30 @@ packages: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.0: + resolution: {integrity: sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q==} + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + recursive-readdir@2.2.3: resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} engines: {node: '>=6.0.0'} - redent@4.0.0: - resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==} - engines: {node: '>=12'} - regenerate-unicode-properties@10.1.1: resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} engines: {node: '>=4'} + regenerate-unicode-properties@10.2.0: + resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} + engines: {node: '>=4'} + regenerate@1.4.2: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} @@ -5209,6 +6342,10 @@ packages: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -5217,6 +6354,10 @@ packages: resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} engines: {node: '>=4'} + regexpu-core@6.1.1: + resolution: {integrity: sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==} + engines: {node: '>=4'} + registry-auth-token@5.0.2: resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} engines: {node: '>=14'} @@ -5225,6 +6366,13 @@ packages: resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} engines: {node: '>=12'} + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.11.2: + resolution: {integrity: sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==} + hasBin: true + regjsparser@0.9.1: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true @@ -5232,6 +6380,9 @@ packages: rehype-raw@7.0.0: resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + relateurl@0.2.7: resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} engines: {node: '>= 0.10'} @@ -5252,12 +6403,18 @@ packages: remark-mdx@3.0.1: resolution: {integrity: sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==} + remark-mdx@3.1.0: + resolution: {integrity: sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==} + remark-parse@11.0.0: resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} remark-rehype@11.1.0: resolution: {integrity: sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==} + remark-rehype@11.1.1: + resolution: {integrity: sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==} + remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} @@ -5267,6 +6424,10 @@ packages: renderkid@3.0.0: resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -5385,8 +6546,8 @@ packages: sass: optional: true - sass@1.79.3: - resolution: {integrity: sha512-m7dZxh0W9EZ3cw50Me5GOuYm/tVAJAn91SUnohLRo9cXBixGUOdvmryN+dXpwR831bhoY3Zv7rEFt85PUwTmzA==} + sass@1.81.0: + resolution: {integrity: sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==} engines: {node: '>=14.0.0'} hasBin: true @@ -5446,8 +6607,8 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - serve-handler@6.1.5: - resolution: {integrity: sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==} + serve-handler@6.1.6: + resolution: {integrity: sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==} serve-index@1.9.1: resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} @@ -5570,6 +6731,10 @@ packages: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -5618,8 +6783,8 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - std-env@3.7.0: - resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} streamx@2.18.0: resolution: {integrity: sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==} @@ -5683,10 +6848,6 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - strip-indent@4.0.0: - resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} - engines: {node: '>=12'} - strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -5695,69 +6856,72 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - style-search@0.1.0: - resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} - style-to-object@0.4.4: resolution: {integrity: sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==} style-to-object@1.0.6: resolution: {integrity: sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==} + style-to-object@1.0.8: + resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==} + stylehacks@6.1.1: resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: postcss: ^8.4.31 - stylelint-config-recess-order@4.6.0: - resolution: {integrity: sha512-V76fhv3YtcNXh/hyAuAdSzi5FmcrG54Mp2AThJ3D/PTMTSYzUPd7GIhP6z9mTqnRhmkk6YTfcu/JWB8h+Yrcaw==} + stylelint-config-recess-order@5.1.1: + resolution: {integrity: sha512-eDAHWVBelzDbMbdMj15pSw0Ycykv5eLeriJdbGCp0zd44yvhgZLI+wyVHegzXp5NrstxTPSxl0fuOVKdMm0XLA==} peerDependencies: - stylelint: '>=15' + stylelint: '>=16' - stylelint-config-recommended-scss@13.1.0: - resolution: {integrity: sha512-8L5nDfd+YH6AOoBGKmhH8pLWF1dpfY816JtGMePcBqqSsLU+Ysawx44fQSlMOJ2xTfI9yTGpup5JU77c17w1Ww==} + stylelint-config-recommended-scss@14.1.0: + resolution: {integrity: sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==} + engines: {node: '>=18.12.0'} peerDependencies: postcss: ^8.3.3 - stylelint: ^15.10.0 + stylelint: ^16.6.1 peerDependenciesMeta: postcss: optional: true - stylelint-config-recommended@13.0.0: - resolution: {integrity: sha512-EH+yRj6h3GAe/fRiyaoO2F9l9Tgg50AOFhaszyfov9v6ayXJ1IkSHwTxd7lB48FmOeSGDPLjatjO11fJpmarkQ==} - engines: {node: ^14.13.1 || >=16.0.0} + stylelint-config-recommended@14.0.1: + resolution: {integrity: sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==} + engines: {node: '>=18.12.0'} peerDependencies: - stylelint: ^15.10.0 + stylelint: ^16.1.0 - stylelint-config-standard-scss@11.1.0: - resolution: {integrity: sha512-5gnBgeNTgRVdchMwiFQPuBOtj9QefYtfXiddrOMJA2pI22zxt6ddI2s+e5Oh7/6QYl7QLJujGnaUR5YyGq72ow==} + stylelint-config-standard-scss@13.1.0: + resolution: {integrity: sha512-Eo5w7/XvwGHWkeGLtdm2FZLOMYoZl1omP2/jgFCXyl2x5yNz7/8vv4Tj6slHvMSSUNTaGoam/GAZ0ZhukvalfA==} + engines: {node: '>=18.12.0'} peerDependencies: postcss: ^8.3.3 - stylelint: ^15.10.0 + stylelint: ^16.3.1 peerDependenciesMeta: postcss: optional: true - stylelint-config-standard@34.0.0: - resolution: {integrity: sha512-u0VSZnVyW9VSryBG2LSO+OQTjN7zF9XJaAJRX/4EwkmU0R2jYwmBSN10acqZisDitS0CLiEiGjX7+Hrq8TAhfQ==} - engines: {node: ^14.13.1 || >=16.0.0} + stylelint-config-standard@36.0.1: + resolution: {integrity: sha512-8aX8mTzJ6cuO8mmD5yon61CWuIM4UD8Q5aBcWKGSf6kg+EC3uhB+iOywpTK4ca6ZL7B49en8yanOFtUW0qNzyw==} + engines: {node: '>=18.12.0'} peerDependencies: - stylelint: ^15.10.0 + stylelint: ^16.1.0 stylelint-order@6.0.4: resolution: {integrity: sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==} peerDependencies: stylelint: ^14.0.0 || ^15.0.0 || ^16.0.1 - stylelint-scss@5.3.2: - resolution: {integrity: sha512-4LzLaayFhFyneJwLo0IUa8knuIvj+zF0vBFueQs4e3tEaAMIQX8q5th8ziKkgOavr6y/y9yoBe+RXN/edwLzsQ==} + stylelint-scss@6.9.0: + resolution: {integrity: sha512-oWOR+g6ccagfrENecImGmorWWjVyWpt2R8bmkhOW8FkNNPGStZPQMqb8QWMW4Lwu9TyPqmyjHkkAsy3weqsnNw==} + engines: {node: '>=18.12.0'} peerDependencies: - stylelint: ^14.5.1 || ^15.0.0 + stylelint: ^16.0.2 - stylelint@15.11.0: - resolution: {integrity: sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==} - engines: {node: ^14.13.1 || >=16.0.0} + stylelint@16.10.0: + resolution: {integrity: sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ==} + engines: {node: '>=18.12.0'} hasBin: true superstruct@1.0.4: @@ -5776,8 +6940,8 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-hyperlinks@3.0.0: - resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + supports-hyperlinks@3.1.0: + resolution: {integrity: sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==} engines: {node: '>=14.18'} supports-preserve-symlinks-flag@1.0.0: @@ -5795,6 +6959,12 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + swc-loader@0.2.6: + resolution: {integrity: sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==} + peerDependencies: + '@swc/core': ^1.2.147 + webpack: '>=2' + table@6.8.2: resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==} engines: {node: '>=10.0.0'} @@ -5841,6 +7011,11 @@ packages: engines: {node: '>=10'} hasBin: true + terser@5.36.0: + resolution: {integrity: sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==} + engines: {node: '>=10'} + hasBin: true + text-decoder@1.1.1: resolution: {integrity: sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==} @@ -5895,10 +7070,6 @@ packages: trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - trim-newlines@4.1.1: - resolution: {integrity: sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==} - engines: {node: '>=12'} - trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} @@ -5917,8 +7088,8 @@ packages: tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} - tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -5974,8 +7145,8 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typescript@5.6.2: - resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true @@ -6001,6 +7172,10 @@ packages: resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} engines: {node: '>=4'} + unicode-match-property-value-ecmascript@2.2.0: + resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} + engines: {node: '>=4'} + unicode-property-aliases-ecmascript@2.1.0: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} @@ -6161,6 +7336,10 @@ packages: resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} engines: {node: '>=10.0.0'} + webpack-merge@6.0.1: + resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==} + engines: {node: '>=18.0.0'} + webpack-sources@3.2.3: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} @@ -6175,8 +7354,8 @@ packages: webpack-cli: optional: true - webpack@5.95.0: - resolution: {integrity: sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==} + webpack@5.96.1: + resolution: {integrity: sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -6185,9 +7364,9 @@ packages: webpack-cli: optional: true - webpackbar@5.0.2: - resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} - engines: {node: '>=12'} + webpackbar@6.0.1: + resolution: {integrity: sha512-TnErZpmuKdwWBdMoexjio3KKX6ZtoKHRVvLIU0A47R0VVBDtx3ZyOJDktgYixhoJokZTYTt1Z37OkO9pnGJa9Q==} + engines: {node: '>=14.21.3'} peerDependencies: webpack: 3 || 4 || 5 @@ -6236,6 +7415,10 @@ packages: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} @@ -6288,9 +7471,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -6299,10 +7479,6 @@ packages: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} - yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} @@ -6320,33 +7496,33 @@ packages: snapshots: - '@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0)': + '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2)(search-insights@2.15.0)': dependencies: - '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0) - '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) + '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2)(search-insights@2.15.0) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - search-insights - '@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0)': + '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2)(search-insights@2.15.0)': dependencies: - '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2) search-insights: 2.15.0 transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - '@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)': + '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2)': dependencies: - '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) - '@algolia/client-search': 4.24.0 - algoliasearch: 4.24.0 + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2) + '@algolia/client-search': 5.14.2 + algoliasearch: 5.14.2 - '@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)': + '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2)': dependencies: - '@algolia/client-search': 4.24.0 - algoliasearch: 4.24.0 + '@algolia/client-search': 5.14.2 + algoliasearch: 5.14.2 '@algolia/cache-browser-local-storage@4.24.0': dependencies: @@ -6358,6 +7534,13 @@ snapshots: dependencies: '@algolia/cache-common': 4.24.0 + '@algolia/client-abtesting@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/client-account@4.24.0': dependencies: '@algolia/client-common': 4.24.0 @@ -6371,31 +7554,82 @@ snapshots: '@algolia/requester-common': 4.24.0 '@algolia/transporter': 4.24.0 + '@algolia/client-analytics@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/client-common@4.24.0': dependencies: '@algolia/requester-common': 4.24.0 '@algolia/transporter': 4.24.0 + '@algolia/client-common@5.14.2': {} + + '@algolia/client-insights@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/client-personalization@4.24.0': dependencies: '@algolia/client-common': 4.24.0 '@algolia/requester-common': 4.24.0 '@algolia/transporter': 4.24.0 + '@algolia/client-personalization@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + + '@algolia/client-query-suggestions@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/client-search@4.24.0': dependencies: '@algolia/client-common': 4.24.0 '@algolia/requester-common': 4.24.0 '@algolia/transporter': 4.24.0 + '@algolia/client-search@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/events@4.0.1': {} + '@algolia/ingestion@1.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/logger-common@4.24.0': {} '@algolia/logger-console@4.24.0': dependencies: '@algolia/logger-common': 4.24.0 + '@algolia/monitoring@1.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/recommend@4.24.0': dependencies: '@algolia/cache-browser-local-storage': 4.24.0 @@ -6410,16 +7644,35 @@ snapshots: '@algolia/requester-node-http': 4.24.0 '@algolia/transporter': 4.24.0 + '@algolia/recommend@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + '@algolia/requester-browser-xhr@4.24.0': dependencies: '@algolia/requester-common': 4.24.0 + '@algolia/requester-browser-xhr@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-common@4.24.0': {} + '@algolia/requester-fetch@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/requester-node-http@4.24.0': dependencies: '@algolia/requester-common': 4.24.0 + '@algolia/requester-node-http@5.14.2': + dependencies: + '@algolia/client-common': 5.14.2 + '@algolia/transporter@4.24.0': dependencies: '@algolia/cache-common': 4.24.0 @@ -6454,10 +7707,18 @@ snapshots: '@babel/code-frame@7.24.7': dependencies: '@babel/highlight': 7.24.7 - picocolors: 1.1.0 + picocolors: 1.1.1 + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 '@babel/compat-data@7.25.2': {} + '@babel/compat-data@7.26.2': {} + '@babel/core@7.25.2': dependencies: '@ampproject/remapping': 2.3.0 @@ -6478,6 +7739,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.26.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/eslint-parser@7.25.1(@babel/core@7.25.2)(eslint@7.32.0)': dependencies: '@babel/core': 7.25.2 @@ -6493,10 +7774,22 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 + '@babel/generator@7.26.2': + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 + '@babel/helper-annotate-as-pure@7.24.7': dependencies: '@babel/types': 7.25.2 + '@babel/helper-annotate-as-pure@7.25.9': + dependencies: + '@babel/types': 7.26.0 + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.7': dependencies: '@babel/traverse': 7.25.3 @@ -6504,6 +7797,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-compilation-targets@7.25.2': dependencies: '@babel/compat-data': 7.25.2 @@ -6512,6 +7812,14 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-compilation-targets@7.25.9': + dependencies: + '@babel/compat-data': 7.26.2 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 + lru-cache: 5.1.1 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6525,6 +7833,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.25.9 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/helper-create-regexp-features-plugin@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6532,12 +7853,48 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.25.2(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + + '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + regexpu-core: 6.1.1 + semver: 6.3.1 + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-compilation-targets': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.6 + debug: 4.3.7 + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.7 + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + debug: 4.3.7 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -6550,6 +7907,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-member-expression-to-functions@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.24.7': dependencies: '@babel/traverse': 7.25.3 @@ -6557,6 +7921,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6567,12 +7938,27 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/helper-optimise-call-expression@7.24.7': dependencies: '@babel/types': 7.25.2 + '@babel/helper-optimise-call-expression@7.25.9': + dependencies: + '@babel/types': 7.26.0 + '@babel/helper-plugin-utils@7.24.8': {} + '@babel/helper-plugin-utils@7.25.9': {} + '@babel/helper-remap-async-to-generator@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6582,6 +7968,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-wrap-function': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/helper-replace-supers@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6591,6 +7986,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-replace-supers@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/helper-simple-access@7.24.7': dependencies: '@babel/traverse': 7.25.3 @@ -6598,6 +8002,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-simple-access@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-skip-transparent-expression-wrappers@7.24.7': dependencies: '@babel/traverse': 7.25.3 @@ -6605,12 +8016,25 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-string-parser@7.24.8': {} + '@babel/helper-string-parser@7.25.9': {} + '@babel/helper-validator-identifier@7.24.7': {} + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-option@7.24.8': {} + '@babel/helper-validator-option@7.25.9': {} + '@babel/helper-wrap-function@7.25.0': dependencies: '@babel/template': 7.25.0 @@ -6619,22 +8043,39 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-wrap-function@7.25.9': + dependencies: + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + '@babel/helpers@7.25.0': dependencies: '@babel/template': 7.25.0 '@babel/types': 7.25.2 + '@babel/helpers@7.26.0': + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + '@babel/highlight@7.24.7': dependencies: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.1.0 + picocolors: 1.1.1 '@babel/parser@7.25.3': dependencies: '@babel/types': 7.25.2 + '@babel/parser@7.26.2': + dependencies: + '@babel/types': 7.26.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6643,16 +8084,34 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6662,6 +8121,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6670,10 +8138,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6694,6 +8174,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6704,11 +8189,21 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6724,6 +8219,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6769,17 +8269,33 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-async-generator-functions@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6790,6 +8306,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-async-generator-functions@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6799,16 +8324,35 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoped-functions@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6817,6 +8361,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6826,6 +8378,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-classes@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6838,40 +8398,85 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + '@babel/traverse': 7.25.9 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/template': 7.25.0 + '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/template': 7.25.9 + '@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6880,12 +8485,25 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-exponentiation-operator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6894,6 +8512,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-function-name@7.25.1(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6903,28 +8529,57 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-literals@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6933,6 +8588,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6942,6 +8605,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-commonjs@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-simple-access': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-systemjs@7.25.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6952,6 +8624,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6960,29 +8642,58 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-nullish-coalescing-operator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6991,6 +8702,13 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -6999,12 +8717,25 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-optional-chaining@7.24.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7014,11 +8745,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7027,6 +8771,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7037,11 +8789,25 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-react-constant-elements@7.25.1(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7052,6 +8818,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-react-jsx-development@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7059,6 +8830,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-react-jsx-development@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7070,31 +8848,65 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-pure-annotations@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-pure-annotations@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 regenerator-transform: 0.15.2 + '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + regenerator-transform: 0.15.2 + + '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-runtime@7.24.7(@babel/core@7.25.2)': + '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2) + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.26.0) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) + babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.26.0) semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -7104,6 +8916,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-spread@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7112,21 +8929,44 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-template-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typeof-symbol@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-typescript@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7138,29 +8978,63 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-typescript@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/preset-env@7.25.3(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.25.2 @@ -7250,6 +9124,81 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/preset-env@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/compat-data': 7.26.2 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0) + '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoped-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-exponentiation-operator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-template-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typeof-symbol': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.0) + babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.26.0) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) + babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.26.0) + core-js-compat: 3.39.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7257,6 +9206,13 @@ snapshots: '@babel/types': 7.25.2 esutils: 2.0.3 + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/types': 7.25.2 + esutils: 2.0.3 + '@babel/preset-react@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7269,6 +9225,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/preset-react@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-pure-annotations': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + '@babel/preset-typescript@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -7280,23 +9248,44 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/preset-typescript@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + '@babel/regjsgen@0.8.0': {} - '@babel/runtime-corejs3@7.25.0': + '@babel/runtime-corejs3@7.26.0': dependencies: - core-js-pure: 3.38.0 + core-js-pure: 3.39.0 regenerator-runtime: 0.14.1 '@babel/runtime@7.25.0': dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.26.0': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/template@7.25.0': dependencies: '@babel/code-frame': 7.24.7 '@babel/parser': 7.25.3 '@babel/types': 7.25.2 + '@babel/template@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@babel/traverse@7.25.3': dependencies: '@babel/code-frame': 7.24.7 @@ -7309,129 +9298,195 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + '@babel/types@7.25.2': dependencies: '@babel/helper-string-parser': 7.24.8 '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@babel/types@7.26.0': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@colors/colors@1.5.0': optional: true - '@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1)': + '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)': dependencies: - '@csstools/css-tokenizer': 2.4.1 + '@csstools/css-tokenizer': 3.0.3 - '@csstools/css-tokenizer@2.4.1': {} + '@csstools/css-tokenizer@3.0.3': {} - '@csstools/media-query-list-parser@2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': + '@csstools/media-query-list-parser@3.0.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': dependencies: - '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) - '@csstools/css-tokenizer': 2.4.1 + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 - '@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.1.1)': + '@csstools/selector-specificity@4.0.0(postcss-selector-parser@6.1.2)': dependencies: - postcss-selector-parser: 6.1.1 + postcss-selector-parser: 6.1.2 '@ctrl/tinycolor@3.6.1': {} '@discoveryjs/json-ext@0.5.7': {} - '@docsearch/css@3.6.2': {} + '@docsearch/css@3.8.0': {} - '@docsearch/react@3.6.2(@algolia/client-search@4.24.0)(@types/react@18.3.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)': + '@docsearch/react@3.8.0(@algolia/client-search@5.14.2)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)': dependencies: - '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0) - '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) - '@docsearch/css': 3.6.2 - algoliasearch: 4.24.0 + '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2)(search-insights@2.15.0) + '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.14.2)(algoliasearch@5.14.2) + '@docsearch/css': 3.8.0 + algoliasearch: 5.14.2 optionalDependencies: - '@types/react': 18.3.10 + '@types/react': 18.3.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) search-insights: 2.15.0 transitivePeerDependencies: - '@algolia/client-search' - '@docusaurus/core@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/generator': 7.25.0 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-runtime': 7.24.7(@babel/core@7.25.2) - '@babel/preset-env': 7.25.3(@babel/core@7.25.2) - '@babel/preset-react': 7.24.7(@babel/core@7.25.2) - '@babel/preset-typescript': 7.24.7(@babel/core@7.25.2) - '@babel/runtime': 7.25.0 - '@babel/runtime-corejs3': 7.25.0 - '@babel/traverse': 7.25.3 - '@docusaurus/cssnano-preset': 3.5.2 - '@docusaurus/logger': 3.5.2 - '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@mdx-js/react': 3.0.1(@types/react@18.3.10)(react@18.3.1) - autoprefixer: 10.4.20(postcss@8.4.41) - babel-loader: 9.1.3(@babel/core@7.25.2)(webpack@5.93.0) + '@docusaurus/babel@3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) + '@babel/preset-env': 7.26.0(@babel/core@7.26.0) + '@babel/preset-react': 7.25.9(@babel/core@7.26.0) + '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) + '@babel/runtime': 7.26.0 + '@babel/runtime-corejs3': 7.26.0 + '@babel/traverse': 7.25.9 + '@docusaurus/logger': 3.6.1 + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) babel-plugin-dynamic-import-node: 2.3.3 + fs-extra: 11.2.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - react + - react-dom + - supports-color + - typescript + - uglify-js + - webpack-cli + + '@docusaurus/bundler@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + dependencies: + '@babel/core': 7.26.0 + '@docusaurus/babel': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/cssnano-preset': 3.6.1 + '@docusaurus/logger': 3.6.1 + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + autoprefixer: 10.4.20(postcss@8.4.49) + babel-loader: 9.2.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.9.2)) + clean-css: 5.3.3 + copy-webpack-plugin: 11.0.0(webpack@5.96.1(@swc/core@1.9.2)) + css-loader: 6.11.0(@rspack/core@1.1.1)(webpack@5.96.1(@swc/core@1.9.2)) + css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.96.1(@swc/core@1.9.2)) + cssnano: 6.1.2(postcss@8.4.49) + file-loader: 6.2.0(webpack@5.96.1(@swc/core@1.9.2)) + html-minifier-terser: 7.2.0 + mini-css-extract-plugin: 2.9.2(webpack@5.96.1(@swc/core@1.9.2)) + null-loader: 4.0.1(webpack@5.96.1(@swc/core@1.9.2)) + postcss: 8.4.49 + postcss-loader: 7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.9.2)) + react-dev-utils: 12.0.1(eslint@7.32.0)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.9.2)) + terser-webpack-plugin: 5.3.10(@swc/core@1.9.2)(webpack@5.96.1(@swc/core@1.9.2)) + tslib: 2.6.3 + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0(@swc/core@1.9.2)))(webpack@5.96.1(@swc/core@1.9.2)) + webpack: 5.96.1(@swc/core@1.9.2) + webpackbar: 6.0.1(webpack@5.96.1(@swc/core@1.9.2)) + optionalDependencies: + '@docusaurus/faster': 3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + transitivePeerDependencies: + - '@parcel/css' + - '@rspack/core' + - '@swc/core' + - '@swc/css' + - csso + - esbuild + - eslint + - lightningcss + - react + - react-dom + - supports-color + - typescript + - uglify-js + - vue-template-compiler + - webpack-cli + + '@docusaurus/core@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + dependencies: + '@docusaurus/babel': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/bundler': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/logger': 3.6.1 + '@docusaurus/mdx-loader': 3.6.1(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@mdx-js/react': 3.1.0(@types/react@18.3.12)(react@18.3.1) boxen: 6.2.1 chalk: 4.1.2 chokidar: 3.6.0 - clean-css: 5.3.3 cli-table3: 0.6.5 combine-promises: 1.2.0 commander: 5.1.0 - copy-webpack-plugin: 11.0.0(webpack@5.93.0) core-js: 3.38.0 - css-loader: 6.11.0(webpack@5.93.0) - css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.93.0) - cssnano: 6.1.2(postcss@8.4.41) del: 6.1.1 detect-port: 1.6.1 escape-html: 1.0.3 eta: 2.2.0 eval: 0.1.8 - file-loader: 6.2.0(webpack@5.93.0) fs-extra: 11.2.0 - html-minifier-terser: 7.2.0 html-tags: 3.3.1 - html-webpack-plugin: 5.6.0(webpack@5.93.0) + html-webpack-plugin: 5.6.0(@rspack/core@1.1.1)(webpack@5.96.1(@swc/core@1.9.2)) leven: 3.1.0 lodash: 4.17.21 - mini-css-extract-plugin: 2.9.0(webpack@5.93.0) p-map: 4.0.0 - postcss: 8.4.41 - postcss-loader: 7.3.4(postcss@8.4.41)(typescript@5.6.2)(webpack@5.93.0) prompts: 2.4.2 react: 18.3.1 - react-dev-utils: 12.0.1(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0) + react-dev-utils: 12.0.1(eslint@7.32.0)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.9.2)) react-dom: 18.3.1(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)' - react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.93.0) + react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.96.1(@swc/core@1.9.2)) react-router: 5.3.4(react@18.3.1) react-router-config: 5.1.1(react-router@5.3.4(react@18.3.1))(react@18.3.1) react-router-dom: 5.3.4(react@18.3.1) rtl-detect: 1.1.2 semver: 7.6.3 - serve-handler: 6.1.5 + serve-handler: 6.1.6 shelljs: 0.8.5 - terser-webpack-plugin: 5.3.10(webpack@5.93.0) tslib: 2.6.3 update-notifier: 6.0.2 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0) - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) webpack-bundle-analyzer: 4.10.2 - webpack-dev-server: 4.15.2(webpack@5.93.0) - webpack-merge: 5.10.0 - webpackbar: 5.0.2(webpack@5.93.0) + webpack-dev-server: 4.15.2(webpack@5.96.1(@swc/core@1.9.2)) + webpack-merge: 6.0.1 transitivePeerDependencies: - - '@docusaurus/types' + - '@docusaurus/faster' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7445,38 +9500,58 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/cssnano-preset@3.5.2': + '@docusaurus/cssnano-preset@3.6.1': dependencies: - cssnano-preset-advanced: 6.1.2(postcss@8.4.41) - postcss: 8.4.41 - postcss-sort-media-queries: 5.2.0(postcss@8.4.41) + cssnano-preset-advanced: 6.1.2(postcss@8.4.49) + postcss: 8.4.49 + postcss-sort-media-queries: 5.2.0(postcss@8.4.49) tslib: 2.6.3 - '@docusaurus/logger@3.5.2': + '@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@rspack/core': 1.1.1 + '@swc/core': 1.9.2 + '@swc/html': 1.9.2 + browserslist: 4.24.2 + lightningcss: 1.28.1 + swc-loader: 0.2.6(@swc/core@1.9.2)(webpack@5.96.1(@swc/core@1.9.2)) + tslib: 2.8.1 + webpack: 5.96.1(@swc/core@1.9.2) + transitivePeerDependencies: + - '@swc/helpers' + - esbuild + - react + - react-dom + - supports-color + - uglify-js + - webpack-cli + + '@docusaurus/logger@3.6.1': dependencies: chalk: 4.1.2 tslib: 2.6.3 - '@docusaurus/lqip-loader@3.5.2(webpack@5.93.0)': + '@docusaurus/lqip-loader@3.6.1(webpack@5.93.0(@swc/core@1.9.2))': dependencies: - '@docusaurus/logger': 3.5.2 - file-loader: 6.2.0(webpack@5.93.0) + '@docusaurus/logger': 3.6.1 + file-loader: 6.2.0(webpack@5.93.0(@swc/core@1.9.2)) lodash: 4.17.21 sharp: 0.32.6 tslib: 2.6.3 transitivePeerDependencies: - webpack - '@docusaurus/mdx-loader@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/mdx-loader@3.6.1(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/logger': 3.5.2 - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@mdx-js/mdx': 3.0.1 + '@docusaurus/logger': 3.6.1 + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@mdx-js/mdx': 3.1.0(acorn@8.12.1) '@slorber/remark-comment': 1.0.0 escape-html: 1.0.3 - estree-util-value-to-estree: 3.1.2 - file-loader: 6.2.0(webpack@5.95.0) + estree-util-value-to-estree: 3.2.1 + file-loader: 6.2.0(webpack@5.96.1(@swc/core@1.9.2)) fs-extra: 11.2.0 image-size: 1.1.1 mdast-util-mdx: 3.0.0 @@ -7492,23 +9567,23 @@ snapshots: tslib: 2.6.3 unified: 11.0.5 unist-util-visit: 5.0.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.95.0) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0(@swc/core@1.9.2)))(webpack@5.96.1(@swc/core@1.9.2)) vfile: 6.0.3 - webpack: 5.95.0 + webpack: 5.96.1(@swc/core@1.9.2) transitivePeerDependencies: - - '@docusaurus/types' - '@swc/core' + - acorn - esbuild - supports-color - typescript - uglify-js - webpack-cli - '@docusaurus/module-type-aliases@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/module-type-aliases@3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/history': 4.7.11 - '@types/react': 18.3.10 + '@types/react': 18.3.12 '@types/react-router-config': 5.0.11 '@types/react-router-dom': 5.3.3 react: 18.3.1 @@ -7522,13 +9597,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-client-redirects@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-client-redirects@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/logger': 3.5.2 - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/logger': 3.6.1 + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) eta: 2.2.0 fs-extra: 11.2.0 lodash: 4.17.21 @@ -7536,12 +9611,13 @@ snapshots: react-dom: 18.3.1(react@18.3.1) tslib: 2.6.3 transitivePeerDependencies: - - '@docusaurus/types' + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7555,17 +9631,17 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-blog@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': - dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/logger': 3.5.2 - '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/plugin-content-blog@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + dependencies: + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/logger': 3.6.1 + '@docusaurus/mdx-loader': 3.6.1(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-common': 3.6.1(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) cheerio: 1.0.0-rc.12 feed: 4.2.2 fs-extra: 11.2.0 @@ -7577,13 +9653,15 @@ snapshots: tslib: 2.6.3 unist-util-visit: 5.0.0 utility-types: 3.11.0 - webpack: 5.95.0 + webpack: 5.96.1(@swc/core@1.9.2) transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7597,17 +9675,17 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': - dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/logger': 3.5.2 - '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + dependencies: + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/logger': 3.6.1 + '@docusaurus/mdx-loader': 3.6.1(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/module-type-aliases': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-common': 3.6.1(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 fs-extra: 11.2.0 @@ -7617,13 +9695,15 @@ snapshots: react-dom: 18.3.1(react@18.3.1) tslib: 2.6.3 utility-types: 3.11.0 - webpack: 5.93.0 + webpack: 5.93.0(@swc/core@1.9.2) transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7637,24 +9717,26 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-pages@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-content-pages@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.1(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.6.3 - webpack: 5.95.0 + webpack: 5.96.1(@swc/core@1.9.2) transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7668,22 +9750,24 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-debug@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-debug@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-json-view-lite: 1.5.0(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7697,20 +9781,22 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-analytics@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-google-analytics@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7724,21 +9810,23 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-gtag@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-google-gtag@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@types/gtag.js': 0.0.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7752,20 +9840,22 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-google-tag-manager@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7779,27 +9869,29 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-ideal-image@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-ideal-image@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/lqip-loader': 3.5.2(webpack@5.93.0) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/lqip-loader': 3.6.1(webpack@5.93.0(@swc/core@1.9.2)) '@docusaurus/responsive-loader': 1.7.0(sharp@0.32.6) - '@docusaurus/theme-translations': 3.5.2 - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/theme-translations': 3.6.1 + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@slorber/react-ideal-image': 0.0.12(prop-types@15.8.1)(react-waypoint@10.3.0(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-waypoint: 10.3.0(react@18.3.1) sharp: 0.32.6 tslib: 2.6.3 - webpack: 5.93.0 + webpack: 5.93.0(@swc/core@1.9.2) transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7814,25 +9906,27 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-sitemap@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/plugin-sitemap@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/logger': 3.5.2 - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/logger': 3.6.1 + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) sitemap: 7.1.2 - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' + - acorn - bufferutil - csso - debug @@ -7846,31 +9940,33 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/preset-classic@3.5.2(@algolia/client-search@4.24.0)(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2)': - dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-content-blog': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-content-pages': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-debug': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-google-analytics': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-google-gtag': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-google-tag-manager': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-sitemap': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-classic': 3.5.2(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-search-algolia': 3.5.2(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2) - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/preset-classic@3.6.1(@algolia/client-search@5.14.2)(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(@types/react@18.3.12)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.3)': + dependencies: + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-blog': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-pages': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-debug': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-google-analytics': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-google-gtag': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-google-tag-manager': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-sitemap': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-classic': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(@types/react@18.3.12)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-common': 3.6.1(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-search-algolia': 3.6.1(@algolia/client-search@5.14.2)(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(@types/react@18.3.12)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.3) + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - '@algolia/client-search' + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' - '@types/react' + - acorn - bufferutil - csso - debug @@ -7887,7 +9983,7 @@ snapshots: '@docusaurus/react-loadable@6.0.0(react@18.3.1)': dependencies: - '@types/react': 18.3.10 + '@types/react': 18.3.12 react: 18.3.1 '@docusaurus/responsive-loader@1.7.0(sharp@0.32.6)': @@ -7896,24 +9992,25 @@ snapshots: optionalDependencies: sharp: 0.32.6 - '@docusaurus/theme-classic@3.5.2(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': - dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-blog': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/plugin-content-pages': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-translations': 3.5.2 - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@mdx-js/react': 3.0.1(@types/react@18.3.10)(react@18.3.1) + '@docusaurus/theme-classic@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(@types/react@18.3.12)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + dependencies: + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/logger': 3.6.1 + '@docusaurus/mdx-loader': 3.6.1(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/module-type-aliases': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-blog': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-pages': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-common': 3.6.1(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-translations': 3.6.1 + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@mdx-js/react': 3.1.0(@types/react@18.3.12)(react@18.3.1) clsx: 2.1.1 copy-text-to-clipboard: 3.2.0 - infima: 0.2.0-alpha.44 + infima: 0.2.0-alpha.45 lodash: 4.17.21 nprogress: 0.2.0 postcss: 8.4.41 @@ -7926,11 +10023,13 @@ snapshots: tslib: 2.6.3 utility-types: 3.11.0 transitivePeerDependencies: + - '@docusaurus/faster' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' - '@types/react' + - acorn - bufferutil - csso - debug @@ -7944,15 +10043,15 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@docusaurus/theme-common@3.6.1(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/mdx-loader': 3.6.1(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/module-type-aliases': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-docs': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/history': 4.7.11 - '@types/react': 18.3.10 + '@types/react': 18.3.12 '@types/react-router-config': 5.0.11 clsx: 2.1.1 parse-numeric-range: 1.3.0 @@ -7962,24 +10061,24 @@ snapshots: tslib: 2.6.3 utility-types: 3.11.0 transitivePeerDependencies: - - '@docusaurus/types' - '@swc/core' + - acorn - esbuild - supports-color - typescript - uglify-js - webpack-cli - '@docusaurus/theme-search-algolia@3.5.2(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(@types/react@18.3.10)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.2)': + '@docusaurus/theme-search-algolia@3.6.1(@algolia/client-search@5.14.2)(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(@types/react@18.3.12)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.6.3)': dependencies: - '@docsearch/react': 3.6.2(@algolia/client-search@4.24.0)(@types/react@18.3.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0) - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/logger': 3.5.2 - '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@docusaurus/theme-translations': 3.5.2 - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) + '@docsearch/react': 3.8.0(@algolia/client-search@5.14.2)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/logger': 3.6.1 + '@docusaurus/plugin-content-docs': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-common': 3.6.1(@docusaurus/plugin-content-docs@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(@swc/core@1.9.2)(acorn@8.12.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-translations': 3.6.1 + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) algoliasearch: 4.24.0 algoliasearch-helper: 3.22.5(algoliasearch@4.24.0) clsx: 2.1.1 @@ -7988,17 +10087,18 @@ snapshots: lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 utility-types: 3.11.0 transitivePeerDependencies: - '@algolia/client-search' - - '@docusaurus/types' + - '@docusaurus/faster' - '@mdx-js/react' - '@parcel/css' - '@rspack/core' - '@swc/core' - '@swc/css' - '@types/react' + - acorn - bufferutil - csso - debug @@ -8013,25 +10113,25 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-translations@3.5.2': + '@docusaurus/theme-translations@3.6.1': dependencies: fs-extra: 11.2.0 tslib: 2.6.3 - '@docusaurus/tsconfig@3.5.2': {} + '@docusaurus/tsconfig@3.6.1': {} - '@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/types@3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@mdx-js/mdx': 3.0.1 '@types/history': 4.7.11 - '@types/react': 18.3.10 + '@types/react': 18.3.12 commander: 5.1.0 joi: 17.13.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) utility-types: 3.11.0 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) webpack-merge: 5.10.0 transitivePeerDependencies: - '@swc/core' @@ -8040,38 +10140,47 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-common@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@docusaurus/utils-common@3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tslib: 2.6.3 - optionalDependencies: - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + transitivePeerDependencies: + - '@swc/core' + - esbuild + - react + - react-dom + - supports-color + - uglify-js + - webpack-cli - '@docusaurus/utils-validation@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2)': + '@docusaurus/utils-validation@3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/logger': 3.5.2 - '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2) - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@docusaurus/logger': 3.6.1 + '@docusaurus/utils': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) fs-extra: 11.2.0 joi: 17.13.3 js-yaml: 4.1.0 lodash: 4.17.21 tslib: 2.6.3 transitivePeerDependencies: - - '@docusaurus/types' - '@swc/core' - esbuild + - react + - react-dom - supports-color - typescript - uglify-js - webpack-cli - '@docusaurus/utils@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.2)': + '@docusaurus/utils@3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/logger': 3.5.2 - '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - '@svgr/webpack': 8.1.0(typescript@5.6.2) + '@docusaurus/logger': 3.6.1 + '@docusaurus/types': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-common': 3.6.1(@swc/core@1.9.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@svgr/webpack': 8.1.0(typescript@5.6.3) escape-string-regexp: 4.0.0 - file-loader: 6.2.0(webpack@5.95.0) + file-loader: 6.2.0(webpack@5.96.1(@swc/core@1.9.2)) fs-extra: 11.2.0 github-slugger: 1.5.0 globby: 11.1.0 @@ -8084,22 +10193,24 @@ snapshots: resolve-pathname: 3.0.0 shelljs: 0.8.5 tslib: 2.6.3 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.95.0) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0(@swc/core@1.9.2)))(webpack@5.96.1(@swc/core@1.9.2)) utility-types: 3.11.0 - webpack: 5.95.0 - optionalDependencies: - '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + webpack: 5.96.1(@swc/core@1.9.2) transitivePeerDependencies: - '@swc/core' - esbuild + - react + - react-dom - supports-color - typescript - uglify-js - webpack-cli + '@dual-bundle/import-meta-resolve@4.1.0': {} + '@emnapi/runtime@1.2.0': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@eslint-community/eslint-utils@4.4.0(eslint@7.32.0)': @@ -8109,10 +10220,10 @@ snapshots: '@eslint-community/regexpp@4.11.0': {} - '@eslint-kit/eslint-config-base@4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)': + '@eslint-kit/eslint-config-base@4.1.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)': dependencies: eslint: 7.32.0 - eslint-plugin-import: 2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0) + eslint-plugin-import: 2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0) eslint-plugin-sonarjs: 0.7.0(eslint@7.32.0) eslint-plugin-unicorn: 32.0.1(eslint@7.32.0) transitivePeerDependencies: @@ -8146,7 +10257,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@fontsource-variable/overpass@5.1.0': {} + '@fontsource-variable/overpass@5.1.1': {} '@hapi/hoek@9.3.0': {} @@ -8248,7 +10359,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -8304,12 +10415,58 @@ snapshots: transitivePeerDependencies: - supports-color - '@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1)': + '@mdx-js/mdx@3.1.0(acorn@8.12.1)': + dependencies: + '@types/estree': 1.0.6 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdx': 2.0.13 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.2 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.0(acorn@8.12.1) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.0 + remark-parse: 11.0.0 + remark-rehype: 11.1.1 + source-map: 0.7.4 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - acorn + - supports-color + + '@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 18.3.10 + '@types/react': 18.3.12 react: 18.3.1 + '@module-federation/runtime-tools@0.5.1': + dependencies: + '@module-federation/runtime': 0.5.1 + '@module-federation/webpack-bundler-runtime': 0.5.1 + + '@module-federation/runtime@0.5.1': + dependencies: + '@module-federation/sdk': 0.5.1 + + '@module-federation/sdk@0.5.1': {} + + '@module-federation/webpack-bundler-runtime@0.5.1': + dependencies: + '@module-federation/runtime': 0.5.1 + '@module-federation/sdk': 0.5.1 + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': dependencies: eslint-scope: 5.1.1 @@ -8326,6 +10483,67 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@parcel/watcher-android-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-x64@2.5.0': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.0': + optional: true + + '@parcel/watcher-win32-arm64@2.5.0': + optional: true + + '@parcel/watcher-win32-ia32@2.5.0': + optional: true + + '@parcel/watcher-win32-x64@2.5.0': + optional: true + + '@parcel/watcher@2.5.0': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.0 + '@parcel/watcher-darwin-arm64': 2.5.0 + '@parcel/watcher-darwin-x64': 2.5.0 + '@parcel/watcher-freebsd-x64': 2.5.0 + '@parcel/watcher-linux-arm-glibc': 2.5.0 + '@parcel/watcher-linux-arm-musl': 2.5.0 + '@parcel/watcher-linux-arm64-glibc': 2.5.0 + '@parcel/watcher-linux-arm64-musl': 2.5.0 + '@parcel/watcher-linux-x64-glibc': 2.5.0 + '@parcel/watcher-linux-x64-musl': 2.5.0 + '@parcel/watcher-win32-arm64': 2.5.0 + '@parcel/watcher-win32-ia32': 2.5.0 + '@parcel/watcher-win32-x64': 2.5.0 + optional: true + '@pnpm/config.env-replace@1.1.0': {} '@pnpm/network.ca-file@1.0.2': @@ -8340,6 +10558,54 @@ snapshots: '@polka/url@1.0.0-next.25': {} + '@rspack/binding-darwin-arm64@1.1.1': + optional: true + + '@rspack/binding-darwin-x64@1.1.1': + optional: true + + '@rspack/binding-linux-arm64-gnu@1.1.1': + optional: true + + '@rspack/binding-linux-arm64-musl@1.1.1': + optional: true + + '@rspack/binding-linux-x64-gnu@1.1.1': + optional: true + + '@rspack/binding-linux-x64-musl@1.1.1': + optional: true + + '@rspack/binding-win32-arm64-msvc@1.1.1': + optional: true + + '@rspack/binding-win32-ia32-msvc@1.1.1': + optional: true + + '@rspack/binding-win32-x64-msvc@1.1.1': + optional: true + + '@rspack/binding@1.1.1': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.1.1 + '@rspack/binding-darwin-x64': 1.1.1 + '@rspack/binding-linux-arm64-gnu': 1.1.1 + '@rspack/binding-linux-arm64-musl': 1.1.1 + '@rspack/binding-linux-x64-gnu': 1.1.1 + '@rspack/binding-linux-x64-musl': 1.1.1 + '@rspack/binding-win32-arm64-msvc': 1.1.1 + '@rspack/binding-win32-ia32-msvc': 1.1.1 + '@rspack/binding-win32-x64-msvc': 1.1.1 + + '@rspack/core@1.1.1': + dependencies: + '@module-federation/runtime-tools': 0.5.1 + '@rspack/binding': 1.1.1 + '@rspack/lite-tapable': 1.0.1 + caniuse-lite: 1.0.30001680 + + '@rspack/lite-tapable@1.0.1': {} + '@rushstack/eslint-patch@1.0.6': {} '@sideway/address@4.1.5': @@ -8414,12 +10680,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.25.2) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.25.2) - '@svgr/core@8.1.0(typescript@5.6.2)': + '@svgr/core@8.1.0(typescript@5.6.3)': dependencies: '@babel/core': 7.25.2 '@svgr/babel-preset': 8.1.0(@babel/core@7.25.2) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.6.2) + cosmiconfig: 8.3.6(typescript@5.6.3) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -8430,39 +10696,136 @@ snapshots: '@babel/types': 7.25.2 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.6.2))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.6.3))': dependencies: '@babel/core': 7.25.2 '@svgr/babel-preset': 8.1.0(@babel/core@7.25.2) - '@svgr/core': 8.1.0(typescript@5.6.2) + '@svgr/core': 8.1.0(typescript@5.6.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.6.2))(typescript@5.6.2)': + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.6.3))(typescript@5.6.3)': dependencies: - '@svgr/core': 8.1.0(typescript@5.6.2) - cosmiconfig: 8.3.6(typescript@5.6.2) + '@svgr/core': 8.1.0(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.6.3) deepmerge: 4.3.1 svgo: 3.3.2 transitivePeerDependencies: - typescript - '@svgr/webpack@8.1.0(typescript@5.6.2)': + '@svgr/webpack@8.1.0(typescript@5.6.3)': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-react-constant-elements': 7.25.1(@babel/core@7.25.2) '@babel/preset-env': 7.25.3(@babel/core@7.25.2) '@babel/preset-react': 7.24.7(@babel/core@7.25.2) '@babel/preset-typescript': 7.24.7(@babel/core@7.25.2) - '@svgr/core': 8.1.0(typescript@5.6.2) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.6.2)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.6.2))(typescript@5.6.2) + '@svgr/core': 8.1.0(typescript@5.6.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.6.3)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.6.3))(typescript@5.6.3) transitivePeerDependencies: - supports-color - typescript + '@swc/core-darwin-arm64@1.9.2': + optional: true + + '@swc/core-darwin-x64@1.9.2': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.9.2': + optional: true + + '@swc/core-linux-arm64-gnu@1.9.2': + optional: true + + '@swc/core-linux-arm64-musl@1.9.2': + optional: true + + '@swc/core-linux-x64-gnu@1.9.2': + optional: true + + '@swc/core-linux-x64-musl@1.9.2': + optional: true + + '@swc/core-win32-arm64-msvc@1.9.2': + optional: true + + '@swc/core-win32-ia32-msvc@1.9.2': + optional: true + + '@swc/core-win32-x64-msvc@1.9.2': + optional: true + + '@swc/core@1.9.2': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.15 + optionalDependencies: + '@swc/core-darwin-arm64': 1.9.2 + '@swc/core-darwin-x64': 1.9.2 + '@swc/core-linux-arm-gnueabihf': 1.9.2 + '@swc/core-linux-arm64-gnu': 1.9.2 + '@swc/core-linux-arm64-musl': 1.9.2 + '@swc/core-linux-x64-gnu': 1.9.2 + '@swc/core-linux-x64-musl': 1.9.2 + '@swc/core-win32-arm64-msvc': 1.9.2 + '@swc/core-win32-ia32-msvc': 1.9.2 + '@swc/core-win32-x64-msvc': 1.9.2 + + '@swc/counter@0.1.3': {} + + '@swc/html-darwin-arm64@1.9.2': + optional: true + + '@swc/html-darwin-x64@1.9.2': + optional: true + + '@swc/html-linux-arm-gnueabihf@1.9.2': + optional: true + + '@swc/html-linux-arm64-gnu@1.9.2': + optional: true + + '@swc/html-linux-arm64-musl@1.9.2': + optional: true + + '@swc/html-linux-x64-gnu@1.9.2': + optional: true + + '@swc/html-linux-x64-musl@1.9.2': + optional: true + + '@swc/html-win32-arm64-msvc@1.9.2': + optional: true + + '@swc/html-win32-ia32-msvc@1.9.2': + optional: true + + '@swc/html-win32-x64-msvc@1.9.2': + optional: true + + '@swc/html@1.9.2': + dependencies: + '@swc/counter': 0.1.3 + optionalDependencies: + '@swc/html-darwin-arm64': 1.9.2 + '@swc/html-darwin-x64': 1.9.2 + '@swc/html-linux-arm-gnueabihf': 1.9.2 + '@swc/html-linux-arm64-gnu': 1.9.2 + '@swc/html-linux-arm64-musl': 1.9.2 + '@swc/html-linux-x64-gnu': 1.9.2 + '@swc/html-linux-x64-musl': 1.9.2 + '@swc/html-win32-arm64-msvc': 1.9.2 + '@swc/html-win32-ia32-msvc': 1.9.2 + '@swc/html-win32-x64-msvc': 1.9.2 + + '@swc/types@0.1.15': + dependencies: + '@swc/counter': 0.1.3 + '@szmarczak/http-timer@5.0.1': dependencies: defer-to-connect: 2.0.1 @@ -8476,20 +10839,20 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/bonjour@3.5.13': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 4.19.5 - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/connect@3.4.38': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/debug@4.1.12': dependencies: @@ -8515,7 +10878,7 @@ snapshots: '@types/express-serve-static-core@4.19.5': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -8543,7 +10906,7 @@ snapshots: '@types/http-proxy@1.17.15': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/istanbul-lib-coverage@2.0.6': {} @@ -8573,17 +10936,15 @@ snapshots: '@types/mime@1.3.5': {} - '@types/minimist@1.2.5': {} - '@types/ms@0.7.34': {} '@types/node-forge@1.3.11': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/node@17.0.45': {} - '@types/node@22.7.4': + '@types/node@22.9.0': dependencies: undici-types: 6.19.8 @@ -8599,28 +10960,28 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/react-dom@18.3.0': + '@types/react-dom@18.3.1': dependencies: - '@types/react': 18.3.10 + '@types/react': 18.3.12 '@types/react-router-config@5.0.11': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.10 + '@types/react': 18.3.12 '@types/react-router': 5.1.20 '@types/react-router-dom@5.3.3': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.10 + '@types/react': 18.3.12 '@types/react-router': 5.1.20 '@types/react-router@5.1.20': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.10 + '@types/react': 18.3.12 - '@types/react@18.3.10': + '@types/react@18.3.12': dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 @@ -8629,14 +10990,14 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/semver@7.5.8': {} '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/serve-index@1.9.4': dependencies: @@ -8645,12 +11006,12 @@ snapshots: '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/send': 0.17.4 '@types/sockjs@0.3.36': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/unist@2.0.10': {} @@ -8660,7 +11021,7 @@ snapshots: '@types/ws@8.5.12': dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 '@types/yargs-parser@21.0.3': {} @@ -8668,13 +11029,13 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)(typescript@5.6.2)': + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.3) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@7.32.0)(typescript@5.6.2) - '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/type-utils': 6.21.0(eslint@7.32.0)(typescript@5.6.3) + '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.6 eslint: 7.32.0 @@ -8682,22 +11043,22 @@ snapshots: ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2)': + '@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.6 eslint: 7.32.0 optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -8706,21 +11067,21 @@ snapshots: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/type-utils@6.21.0(eslint@7.32.0)(typescript@5.6.2)': + '@typescript-eslint/type-utils@6.21.0(eslint@7.32.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.2) - '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + '@typescript-eslint/utils': 6.21.0(eslint@7.32.0)(typescript@5.6.3) debug: 4.3.6 eslint: 7.32.0 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.2)': + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 @@ -8729,20 +11090,20 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.21.0(eslint@7.32.0)(typescript@5.6.2)': + '@typescript-eslint/utils@6.21.0(eslint@7.32.0)(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@7.32.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) eslint: 7.32.0 semver: 7.6.3 transitivePeerDependencies: @@ -8761,20 +11122,39 @@ snapshots: '@webassemblyjs/helper-numbers': 1.11.6 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/floating-point-hex-parser@1.11.6': {} + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + '@webassemblyjs/helper-api-error@1.11.6': {} + '@webassemblyjs/helper-api-error@1.13.2': {} + '@webassemblyjs/helper-buffer@1.12.1': {} + '@webassemblyjs/helper-buffer@1.14.1': {} + '@webassemblyjs/helper-numbers@1.11.6': dependencies: '@webassemblyjs/floating-point-hex-parser': 1.11.6 '@webassemblyjs/helper-api-error': 1.11.6 '@xtuc/long': 4.2.2 + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + '@webassemblyjs/helper-wasm-bytecode@1.11.6': {} + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + '@webassemblyjs/helper-wasm-section@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -8782,16 +11162,33 @@ snapshots: '@webassemblyjs/helper-wasm-bytecode': 1.11.6 '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/ieee754@1.11.6': dependencies: '@xtuc/ieee754': 1.2.0 + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + '@webassemblyjs/leb128@1.11.6': dependencies: '@xtuc/long': 4.2.2 + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + '@webassemblyjs/utf8@1.11.6': {} + '@webassemblyjs/utf8@1.13.2': {} + '@webassemblyjs/wasm-edit@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -8803,6 +11200,17 @@ snapshots: '@webassemblyjs/wasm-parser': 1.12.1 '@webassemblyjs/wast-printer': 1.12.1 + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + '@webassemblyjs/wasm-gen@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -8811,6 +11219,14 @@ snapshots: '@webassemblyjs/leb128': 1.11.6 '@webassemblyjs/utf8': 1.11.6 + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + '@webassemblyjs/wasm-opt@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -8818,6 +11234,13 @@ snapshots: '@webassemblyjs/wasm-gen': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wasm-parser@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -8827,11 +11250,25 @@ snapshots: '@webassemblyjs/leb128': 1.11.6 '@webassemblyjs/utf8': 1.11.6 + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + '@webassemblyjs/wast-printer@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -8861,6 +11298,8 @@ snapshots: acorn@8.12.1: {} + acorn@8.14.0: {} + address@1.2.2: {} aggregate-error@3.1.0: @@ -8918,6 +11357,22 @@ snapshots: '@algolia/requester-node-http': 4.24.0 '@algolia/transporter': 4.24.0 + algoliasearch@5.14.2: + dependencies: + '@algolia/client-abtesting': 5.14.2 + '@algolia/client-analytics': 5.14.2 + '@algolia/client-common': 5.14.2 + '@algolia/client-insights': 5.14.2 + '@algolia/client-personalization': 5.14.2 + '@algolia/client-query-suggestions': 5.14.2 + '@algolia/client-search': 5.14.2 + '@algolia/ingestion': 1.14.2 + '@algolia/monitoring': 1.14.2 + '@algolia/recommend': 5.14.2 + '@algolia/requester-browser-xhr': 5.14.2 + '@algolia/requester-fetch': 5.14.2 + '@algolia/requester-node-http': 5.14.2 + all-contributors-cli@6.26.1: dependencies: '@babel/runtime': 7.25.0 @@ -8996,7 +11451,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 @@ -9026,8 +11481,6 @@ snapshots: is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 - arrify@1.0.1: {} - astral-regex@2.0.0: {} astring@1.8.6: {} @@ -9036,14 +11489,14 @@ snapshots: at-least-node@1.0.0: {} - autoprefixer@10.4.20(postcss@8.4.41): + autoprefixer@10.4.20(postcss@8.4.49): dependencies: - browserslist: 4.23.3 - caniuse-lite: 1.0.30001651 + browserslist: 4.24.2 + caniuse-lite: 1.0.30001680 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.1.0 - postcss: 8.4.41 + picocolors: 1.1.1 + postcss: 8.4.49 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -9052,12 +11505,12 @@ snapshots: b4a@1.6.6: {} - babel-loader@9.1.3(@babel/core@7.25.2)(webpack@5.93.0): + babel-loader@9.2.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) babel-plugin-dynamic-import-node@2.3.3: dependencies: @@ -9072,6 +11525,15 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): + dependencies: + '@babel/compat-data': 7.26.2 + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -9080,6 +11542,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) + core-js-compat: 3.38.0 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -9087,6 +11557,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -9198,12 +11675,12 @@ snapshots: node-releases: 2.0.18 update-browserslist-db: 1.1.0(browserslist@4.23.3) - browserslist@4.24.0: + browserslist@4.24.2: dependencies: - caniuse-lite: 1.0.30001664 - electron-to-chromium: 1.5.29 + caniuse-lite: 1.0.30001680 + electron-to-chromium: 1.5.63 node-releases: 2.0.18 - update-browserslist-db: 1.1.1(browserslist@4.24.0) + update-browserslist-db: 1.1.1(browserslist@4.24.2) buffer-from@1.1.2: {} @@ -9245,13 +11722,6 @@ snapshots: pascal-case: 3.1.2 tslib: 2.6.3 - camelcase-keys@7.0.2: - dependencies: - camelcase: 6.3.0 - map-obj: 4.3.0 - quick-lru: 5.1.1 - type-fest: 1.4.0 - camelcase@5.3.1: {} camelcase@6.3.0: {} @@ -9260,14 +11730,14 @@ snapshots: caniuse-api@3.0.0: dependencies: - browserslist: 4.23.3 - caniuse-lite: 1.0.30001651 + browserslist: 4.24.2 + caniuse-lite: 1.0.30001680 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 caniuse-lite@1.0.30001651: {} - caniuse-lite@1.0.30001664: {} + caniuse-lite@1.0.30001680: {} ccount@2.0.1: {} @@ -9314,8 +11784,8 @@ snapshots: domhandler: 5.0.3 domutils: 3.1.0 htmlparser2: 8.0.2 - parse5: 7.1.2 - parse5-htmlparser2-tree-adapter: 7.0.0 + parse5: 7.2.1 + parse5-htmlparser2-tree-adapter: 7.1.0 chokidar@3.6.0: dependencies: @@ -9456,7 +11926,7 @@ snapshots: connect-history-api-fallback@2.0.0: {} - consola@2.15.3: {} + consola@3.2.3: {} consolidated-events@2.0.2: {} @@ -9481,7 +11951,7 @@ snapshots: copy-text-to-clipboard@3.2.0: {} - copy-webpack-plugin@11.0.0(webpack@5.93.0): + copy-webpack-plugin@11.0.0(webpack@5.96.1(@swc/core@1.9.2)): dependencies: fast-glob: 3.3.2 glob-parent: 6.0.2 @@ -9489,13 +11959,17 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) core-js-compat@3.38.0: dependencies: browserslist: 4.23.3 - core-js-pure@3.38.0: {} + core-js-compat@3.39.0: + dependencies: + browserslist: 4.24.2 + + core-js-pure@3.39.0: {} core-js@3.38.0: {} @@ -9509,14 +11983,23 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - cosmiconfig@8.3.6(typescript@5.6.2): + cosmiconfig@8.3.6(typescript@5.6.3): dependencies: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 + + cosmiconfig@9.0.0(typescript@5.6.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.6.3 cross-spawn@7.0.3: dependencies: @@ -9530,38 +12013,39 @@ snapshots: dependencies: type-fest: 1.4.0 - css-declaration-sorter@7.2.0(postcss@8.4.41): + css-declaration-sorter@7.2.0(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - css-functions-list@3.2.2: {} + css-functions-list@3.2.3: {} css-line-break@2.1.0: dependencies: utrie: 1.0.2 - css-loader@6.11.0(webpack@5.93.0): + css-loader@6.11.0(@rspack/core@1.1.1)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: - icss-utils: 5.1.0(postcss@8.4.41) - postcss: 8.4.41 - postcss-modules-extract-imports: 3.1.0(postcss@8.4.41) - postcss-modules-local-by-default: 4.0.5(postcss@8.4.41) - postcss-modules-scope: 3.2.0(postcss@8.4.41) - postcss-modules-values: 4.0.0(postcss@8.4.41) + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) + postcss-modules-local-by-default: 4.1.0(postcss@8.4.49) + postcss-modules-scope: 3.2.1(postcss@8.4.49) + postcss-modules-values: 4.0.0(postcss@8.4.49) postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.93.0 + '@rspack/core': 1.1.1 + webpack: 5.96.1(@swc/core@1.9.2) - css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.93.0): + css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 - cssnano: 6.1.2(postcss@8.4.41) + cssnano: 6.1.2(postcss@8.4.49) jest-worker: 29.7.0 - postcss: 8.4.41 + postcss: 8.4.49 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) optionalDependencies: clean-css: 5.3.3 @@ -9584,71 +12068,76 @@ snapshots: css-tree@2.2.1: dependencies: mdn-data: 2.0.28 - source-map-js: 1.2.0 + source-map-js: 1.2.1 css-tree@2.3.1: dependencies: mdn-data: 2.0.30 - source-map-js: 1.2.0 + source-map-js: 1.2.1 + + css-tree@3.0.1: + dependencies: + mdn-data: 2.12.1 + source-map-js: 1.2.1 css-what@6.1.0: {} cssesc@3.0.0: {} - cssnano-preset-advanced@6.1.2(postcss@8.4.41): - dependencies: - autoprefixer: 10.4.20(postcss@8.4.41) - browserslist: 4.24.0 - cssnano-preset-default: 6.1.2(postcss@8.4.41) - postcss: 8.4.41 - postcss-discard-unused: 6.0.5(postcss@8.4.41) - postcss-merge-idents: 6.0.3(postcss@8.4.41) - postcss-reduce-idents: 6.0.3(postcss@8.4.41) - postcss-zindex: 6.0.2(postcss@8.4.41) - - cssnano-preset-default@6.1.2(postcss@8.4.41): - dependencies: - browserslist: 4.23.3 - css-declaration-sorter: 7.2.0(postcss@8.4.41) - cssnano-utils: 4.0.2(postcss@8.4.41) - postcss: 8.4.41 - postcss-calc: 9.0.1(postcss@8.4.41) - postcss-colormin: 6.1.0(postcss@8.4.41) - postcss-convert-values: 6.1.0(postcss@8.4.41) - postcss-discard-comments: 6.0.2(postcss@8.4.41) - postcss-discard-duplicates: 6.0.3(postcss@8.4.41) - postcss-discard-empty: 6.0.3(postcss@8.4.41) - postcss-discard-overridden: 6.0.2(postcss@8.4.41) - postcss-merge-longhand: 6.0.5(postcss@8.4.41) - postcss-merge-rules: 6.1.1(postcss@8.4.41) - postcss-minify-font-values: 6.1.0(postcss@8.4.41) - postcss-minify-gradients: 6.0.3(postcss@8.4.41) - postcss-minify-params: 6.1.0(postcss@8.4.41) - postcss-minify-selectors: 6.0.4(postcss@8.4.41) - postcss-normalize-charset: 6.0.2(postcss@8.4.41) - postcss-normalize-display-values: 6.0.2(postcss@8.4.41) - postcss-normalize-positions: 6.0.2(postcss@8.4.41) - postcss-normalize-repeat-style: 6.0.2(postcss@8.4.41) - postcss-normalize-string: 6.0.2(postcss@8.4.41) - postcss-normalize-timing-functions: 6.0.2(postcss@8.4.41) - postcss-normalize-unicode: 6.1.0(postcss@8.4.41) - postcss-normalize-url: 6.0.2(postcss@8.4.41) - postcss-normalize-whitespace: 6.0.2(postcss@8.4.41) - postcss-ordered-values: 6.0.2(postcss@8.4.41) - postcss-reduce-initial: 6.1.0(postcss@8.4.41) - postcss-reduce-transforms: 6.0.2(postcss@8.4.41) - postcss-svgo: 6.0.3(postcss@8.4.41) - postcss-unique-selectors: 6.0.4(postcss@8.4.41) - - cssnano-utils@4.0.2(postcss@8.4.41): - dependencies: - postcss: 8.4.41 - - cssnano@6.1.2(postcss@8.4.41): - dependencies: - cssnano-preset-default: 6.1.2(postcss@8.4.41) + cssnano-preset-advanced@6.1.2(postcss@8.4.49): + dependencies: + autoprefixer: 10.4.20(postcss@8.4.49) + browserslist: 4.24.2 + cssnano-preset-default: 6.1.2(postcss@8.4.49) + postcss: 8.4.49 + postcss-discard-unused: 6.0.5(postcss@8.4.49) + postcss-merge-idents: 6.0.3(postcss@8.4.49) + postcss-reduce-idents: 6.0.3(postcss@8.4.49) + postcss-zindex: 6.0.2(postcss@8.4.49) + + cssnano-preset-default@6.1.2(postcss@8.4.49): + dependencies: + browserslist: 4.24.2 + css-declaration-sorter: 7.2.0(postcss@8.4.49) + cssnano-utils: 4.0.2(postcss@8.4.49) + postcss: 8.4.49 + postcss-calc: 9.0.1(postcss@8.4.49) + postcss-colormin: 6.1.0(postcss@8.4.49) + postcss-convert-values: 6.1.0(postcss@8.4.49) + postcss-discard-comments: 6.0.2(postcss@8.4.49) + postcss-discard-duplicates: 6.0.3(postcss@8.4.49) + postcss-discard-empty: 6.0.3(postcss@8.4.49) + postcss-discard-overridden: 6.0.2(postcss@8.4.49) + postcss-merge-longhand: 6.0.5(postcss@8.4.49) + postcss-merge-rules: 6.1.1(postcss@8.4.49) + postcss-minify-font-values: 6.1.0(postcss@8.4.49) + postcss-minify-gradients: 6.0.3(postcss@8.4.49) + postcss-minify-params: 6.1.0(postcss@8.4.49) + postcss-minify-selectors: 6.0.4(postcss@8.4.49) + postcss-normalize-charset: 6.0.2(postcss@8.4.49) + postcss-normalize-display-values: 6.0.2(postcss@8.4.49) + postcss-normalize-positions: 6.0.2(postcss@8.4.49) + postcss-normalize-repeat-style: 6.0.2(postcss@8.4.49) + postcss-normalize-string: 6.0.2(postcss@8.4.49) + postcss-normalize-timing-functions: 6.0.2(postcss@8.4.49) + postcss-normalize-unicode: 6.1.0(postcss@8.4.49) + postcss-normalize-url: 6.0.2(postcss@8.4.49) + postcss-normalize-whitespace: 6.0.2(postcss@8.4.49) + postcss-ordered-values: 6.0.2(postcss@8.4.49) + postcss-reduce-initial: 6.1.0(postcss@8.4.49) + postcss-reduce-transforms: 6.0.2(postcss@8.4.49) + postcss-svgo: 6.0.3(postcss@8.4.49) + postcss-unique-selectors: 6.0.4(postcss@8.4.49) + + cssnano-utils@4.0.2(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + + cssnano@6.1.2(postcss@8.4.49): + dependencies: + cssnano-preset-default: 6.1.2(postcss@8.4.49) lilconfig: 3.1.2 - postcss: 8.4.41 + postcss: 8.4.49 csso@5.0.5: dependencies: @@ -9688,15 +12177,12 @@ snapshots: dependencies: ms: 2.1.2 - decamelize-keys@1.1.1: + debug@4.3.7: dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 + ms: 2.1.3 decamelize@1.2.0: {} - decamelize@5.0.1: {} - decode-named-character-reference@1.0.2: dependencies: character-entities: 2.0.2 @@ -9750,6 +12236,8 @@ snapshots: destroy@1.2.0: {} + detect-libc@1.0.3: {} + detect-libc@2.0.3: {} detect-node@2.1.0: {} @@ -9790,11 +12278,11 @@ snapshots: dependencies: esutils: 2.0.3 - docusaurus-plugin-sass@0.2.5(@docusaurus/core@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2))(sass@1.79.3)(webpack@5.93.0): + docusaurus-plugin-sass@0.2.5(@docusaurus/core@3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3))(sass@1.81.0)(webpack@5.93.0(@swc/core@1.9.2)): dependencies: - '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.10)(react@18.3.1))(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - sass: 1.79.3 - sass-loader: 10.5.2(sass@1.79.3)(webpack@5.93.0) + '@docusaurus/core': 3.6.1(@docusaurus/faster@3.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@rspack/core@1.1.1)(@swc/core@1.9.2)(acorn@8.12.1)(eslint@7.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + sass: 1.81.0 + sass-loader: 10.5.2(sass@1.81.0)(webpack@5.93.0(@swc/core@1.9.2)) transitivePeerDependencies: - fibers - node-sass @@ -9855,10 +12343,10 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.29: {} - electron-to-chromium@1.5.6: {} + electron-to-chromium@1.5.63: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -9889,6 +12377,8 @@ snapshots: entities@4.5.0: {} + env-paths@2.2.1: {} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 @@ -9942,6 +12432,55 @@ snapshots: unbox-primitive: 1.0.2 which-typed-array: 1.1.15 + es-abstract@1.23.5: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.3 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.3 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + es-define-property@1.0.0: dependencies: get-intrinsic: 1.2.4 @@ -9970,6 +12509,20 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.14.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.2 + escalade@3.1.2: {} escalade@3.2.0: {} @@ -9988,9 +12541,9 @@ snapshots: dependencies: eslint: 7.32.0 - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)): dependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0) eslint-import-resolver-node@0.3.9: dependencies: @@ -10000,27 +12553,27 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.3) eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.3) eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0): + eslint-plugin-import@2.23.2(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0): dependencies: array-includes: 3.1.8 array.prototype.flat: 1.3.2 @@ -10029,7 +12582,7 @@ snapshots: doctrine: 2.1.0 eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) find-up: 2.1.0 has: 1.0.4 is-core-module: 2.15.0 @@ -10040,13 +12593,13 @@ snapshots: resolve: 1.22.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint@7.32.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -10056,7 +12609,7 @@ snapshots: doctrine: 2.1.0 eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -10067,7 +12620,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@7.32.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -10220,13 +12773,18 @@ snapshots: estree-util-is-identifier-name@3.0.0: {} + estree-util-scope@1.0.0: + dependencies: + '@types/estree': 1.0.6 + devlop: 1.1.0 + estree-util-to-js@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 astring: 1.8.6 source-map: 0.7.4 - estree-util-value-to-estree@3.1.2: + estree-util-value-to-estree@3.2.1: dependencies: '@types/estree': 1.0.6 @@ -10247,7 +12805,7 @@ snapshots: eval@0.1.8: dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 require-like: 0.1.2 eventemitter3@4.0.7: {} @@ -10326,7 +12884,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} @@ -10334,10 +12892,6 @@ snapshots: fast-uri@3.0.1: {} - fast-url-parser@1.1.3: - dependencies: - punycode: 1.4.1 - fastest-levenshtein@1.0.16: {} fastq@1.17.1: @@ -10364,21 +12918,21 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-entry-cache@7.0.2: + file-entry-cache@9.1.0: dependencies: - flat-cache: 3.2.0 + flat-cache: 5.0.0 - file-loader@6.2.0(webpack@5.93.0): + file-loader@6.2.0(webpack@5.93.0(@swc/core@1.9.2)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.93.0 + webpack: 5.93.0(@swc/core@1.9.2) - file-loader@6.2.0(webpack@5.95.0): + file-loader@6.2.0(webpack@5.96.1(@swc/core@1.9.2)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.95.0 + webpack: 5.96.1(@swc/core@1.9.2) filesize@8.0.7: {} @@ -10432,17 +12986,24 @@ snapshots: keyv: 4.5.4 rimraf: 3.0.2 + flat-cache@5.0.0: + dependencies: + flatted: 3.3.2 + keyv: 4.5.4 + flat@5.0.2: {} flatted@3.3.1: {} + flatted@3.3.2: {} + follow-redirects@1.15.6: {} for-each@0.3.3: dependencies: is-callable: 1.2.7 - fork-ts-checker-webpack-plugin@6.5.3(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0): + fork-ts-checker-webpack-plugin@6.5.3(eslint@7.32.0)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: '@babel/code-frame': 7.24.7 '@types/json-schema': 7.0.15 @@ -10457,8 +13018,8 @@ snapshots: schema-utils: 2.7.0 semver: 7.6.3 tapable: 1.1.3 - typescript: 5.6.2 - webpack: 5.93.0 + typescript: 5.6.3 + webpack: 5.96.1(@swc/core@1.9.2) optionalDependencies: eslint: 7.32.0 @@ -10582,7 +13143,7 @@ snapshots: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -10590,7 +13151,7 @@ snapshots: dependencies: dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 merge2: 1.4.1 slash: 4.0.0 @@ -10633,8 +13194,6 @@ snapshots: handle-thing@2.0.1: {} - hard-rejection@2.1.0: {} - has-bigints@1.0.2: {} has-flag@3.0.0: {} @@ -10676,7 +13235,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 - hast-util-raw@9.0.4: + hast-util-raw@9.1.0: dependencies: '@types/hast': 3.0.4 '@types/unist': 3.0.3 @@ -10685,7 +13244,7 @@ snapshots: hast-util-to-parse5: 8.0.0 html-void-elements: 3.0.0 mdast-util-to-hast: 13.2.0 - parse5: 7.1.2 + parse5: 7.2.1 unist-util-position: 5.0.0 unist-util-visit: 5.0.0 vfile: 6.0.3 @@ -10733,6 +13292,26 @@ snapshots: transitivePeerDependencies: - supports-color + hast-util-to-jsx-runtime@2.3.2: + dependencies: + '@types/estree': 1.0.6 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.1.3 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + style-to-object: 1.0.8 + unist-util-position: 5.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + hast-util-to-parse5@8.0.0: dependencies: '@types/hast': 3.0.4 @@ -10772,10 +13351,6 @@ snapshots: hosted-git-info@2.8.9: {} - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 - hpack.js@2.1.6: dependencies: inherits: 2.0.4 @@ -10805,13 +13380,13 @@ snapshots: entities: 4.5.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.31.5 + terser: 5.36.0 html-tags@3.3.1: {} html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.0(webpack@5.93.0): + html-webpack-plugin@5.6.0(@rspack/core@1.1.1)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -10819,7 +13394,8 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.93.0 + '@rspack/core': 1.1.1 + webpack: 5.96.1(@swc/core@1.9.2) html2canvas@1.4.1: dependencies: @@ -10867,7 +13443,7 @@ snapshots: http-proxy: 1.18.1 is-glob: 4.0.3 is-plain-obj: 3.0.0 - micromatch: 4.0.7 + micromatch: 4.0.8 optionalDependencies: '@types/express': 4.17.21 transitivePeerDependencies: @@ -10892,9 +13468,9 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.4.41): + icss-utils@5.1.0(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 ieee754@1.2.1: {} @@ -10902,13 +13478,17 @@ snapshots: ignore@5.3.1: {} + ignore@5.3.2: {} + + ignore@6.0.2: {} + image-size@1.1.1: dependencies: queue: 6.0.2 immer@9.0.21: {} - immutable@4.3.7: {} + immutable@5.0.2: {} import-fresh@3.3.0: dependencies: @@ -10923,9 +13503,7 @@ snapshots: indent-string@4.0.0: {} - indent-string@5.0.0: {} - - infima@0.2.0-alpha.44: {} + infima@0.2.0-alpha.45: {} inflight@1.0.6: dependencies: @@ -10944,6 +13522,8 @@ snapshots: inline-style-parser@0.2.3: {} + inline-style-parser@0.2.4: {} + inquirer@7.3.3: dependencies: ansi-escapes: 4.3.2 @@ -11070,8 +13650,6 @@ snapshots: is-path-inside@3.0.3: {} - is-plain-obj@1.1.0: {} - is-plain-obj@3.0.0: {} is-plain-obj@4.1.0: {} @@ -11138,7 +13716,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.7.4 + '@types/node': 22.9.0 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -11146,13 +13724,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 22.7.4 + '@types/node': 22.9.0 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -11182,6 +13760,8 @@ snapshots: jsesc@2.5.2: {} + jsesc@3.0.2: {} + json-buffer@3.0.1: {} json-fixer@1.6.15: @@ -11229,7 +13809,9 @@ snapshots: klona@2.0.6: {} - known-css-properties@0.29.0: {} + known-css-properties@0.34.0: {} + + known-css-properties@0.35.0: {} latest-version@7.0.0: dependencies: @@ -11237,7 +13819,7 @@ snapshots: launch-editor@2.8.1: dependencies: - picocolors: 1.1.0 + picocolors: 1.1.1 shell-quote: 1.8.1 leven@3.1.0: {} @@ -11247,6 +13829,51 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lightningcss-darwin-arm64@1.28.1: + optional: true + + lightningcss-darwin-x64@1.28.1: + optional: true + + lightningcss-freebsd-x64@1.28.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.28.1: + optional: true + + lightningcss-linux-arm64-gnu@1.28.1: + optional: true + + lightningcss-linux-arm64-musl@1.28.1: + optional: true + + lightningcss-linux-x64-gnu@1.28.1: + optional: true + + lightningcss-linux-x64-musl@1.28.1: + optional: true + + lightningcss-win32-arm64-msvc@1.28.1: + optional: true + + lightningcss-win32-x64-msvc@1.28.1: + optional: true + + lightningcss@1.28.1: + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.28.1 + lightningcss-darwin-x64: 1.28.1 + lightningcss-freebsd-x64: 1.28.1 + lightningcss-linux-arm-gnueabihf: 1.28.1 + lightningcss-linux-arm64-gnu: 1.28.1 + lightningcss-linux-arm64-musl: 1.28.1 + lightningcss-linux-x64-gnu: 1.28.1 + lightningcss-linux-x64-musl: 1.28.1 + lightningcss-win32-arm64-msvc: 1.28.1 + lightningcss-win32-x64-msvc: 1.28.1 + lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} @@ -11320,17 +13947,13 @@ snapshots: dependencies: yallist: 3.1.1 - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - map-obj@1.0.1: {} - - map-obj@4.3.0: {} - markdown-extensions@2.0.0: {} - markdown-table@3.0.3: {} + markdown-table@2.0.0: + dependencies: + repeat-string: 1.6.1 + + markdown-table@3.0.4: {} mathml-tag-names@2.1.3: {} @@ -11339,8 +13962,8 @@ snapshots: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.1 - mdast-util-to-markdown: 2.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.1 stringify-entities: 4.0.4 unist-util-visit-parents: 6.0.1 @@ -11371,13 +13994,30 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + mdast-util-frontmatter@2.0.1: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 escape-string-regexp: 5.0.0 - mdast-util-from-markdown: 2.0.1 - mdast-util-to-markdown: 2.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 micromark-extension-frontmatter: 2.0.0 transitivePeerDependencies: - supports-color @@ -11388,23 +14028,23 @@ snapshots: ccount: 2.0.1 devlop: 1.1.0 mdast-util-find-and-replace: 3.0.1 - micromark-util-character: 2.1.0 + micromark-util-character: 2.1.1 mdast-util-gfm-footnote@2.0.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.1 - mdast-util-to-markdown: 2.1.0 - micromark-util-normalize-identifier: 2.0.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.1 - mdast-util-to-markdown: 2.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11412,9 +14052,9 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - markdown-table: 3.0.3 - mdast-util-from-markdown: 2.0.1 - mdast-util-to-markdown: 2.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11422,20 +14062,20 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.1 - mdast-util-to-markdown: 2.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.0.0: dependencies: - mdast-util-from-markdown: 2.0.1 + mdast-util-from-markdown: 2.0.2 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.0.0 mdast-util-gfm-strikethrough: 2.0.0 mdast-util-gfm-table: 2.0.0 mdast-util-gfm-task-list-item: 2.0.0 - mdast-util-to-markdown: 2.1.0 + mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11450,6 +14090,17 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-mdx-jsx@3.1.2: dependencies: '@types/estree-jsx': 1.0.5 @@ -11468,6 +14119,23 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-mdx-jsx@3.1.3: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.1 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + mdast-util-mdx@3.0.0: dependencies: mdast-util-from-markdown: 2.0.1 @@ -11517,6 +14185,18 @@ snapshots: unist-util-visit: 5.0.0 zwitch: 2.0.4 + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + mdast-util-to-string@4.0.0: dependencies: '@types/mdast': 4.0.4 @@ -11525,6 +14205,10 @@ snapshots: mdn-data@2.0.30: {} + mdn-data@2.12.1: {} + + mdn-data@2.12.2: {} + media-typer@0.3.0: {} medium-zoom@1.1.0: {} @@ -11533,20 +14217,7 @@ snapshots: dependencies: fs-monkey: 1.0.6 - meow@10.1.5: - dependencies: - '@types/minimist': 1.2.5 - camelcase-keys: 7.0.2 - decamelize: 5.0.1 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 3.0.3 - read-pkg-up: 8.0.0 - redent: 4.0.0 - trim-newlines: 4.1.1 - type-fest: 1.4.0 - yargs-parser: 20.2.9 + meow@13.2.0: {} merge-descriptors@1.0.1: {} @@ -11575,69 +14246,88 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-core-commonmark@2.0.2: + dependencies: + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.0.2 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-extension-directive@3.0.2: dependencies: devlop: 1.1.0 - micromark-factory-space: 2.0.0 - micromark-factory-whitespace: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 parse-entities: 4.0.1 micromark-extension-frontmatter@2.0.0: dependencies: fault: 2.0.1 - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 micromark-extension-gfm-autolink-literal@2.1.0: dependencies: - micromark-util-character: 2.1.0 - micromark-util-sanitize-uri: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 micromark-extension-gfm-footnote@2.1.0: dependencies: devlop: 1.1.0 - micromark-core-commonmark: 2.0.1 - micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-normalize-identifier: 2.0.0 - micromark-util-sanitize-uri: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-core-commonmark: 2.0.2 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 micromark-extension-gfm-strikethrough@2.1.0: dependencies: devlop: 1.1.0 - micromark-util-chunked: 2.0.0 - micromark-util-classify-character: 2.0.0 - micromark-util-resolve-all: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 micromark-extension-gfm-table@2.1.0: dependencies: devlop: 1.1.0 - micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 micromark-extension-gfm-tagfilter@2.0.0: dependencies: - micromark-util-types: 2.0.0 + micromark-util-types: 2.0.1 micromark-extension-gfm-task-list-item@2.1.0: dependencies: devlop: 1.1.0 - micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 micromark-extension-gfm@3.0.0: dependencies: @@ -11647,8 +14337,8 @@ snapshots: micromark-extension-gfm-table: 2.1.0 micromark-extension-gfm-tagfilter: 2.0.0 micromark-extension-gfm-task-list-item: 2.1.0 - micromark-util-combine-extensions: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.1 micromark-extension-mdx-expression@3.0.0: dependencies: @@ -11707,6 +14397,12 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-factory-label@2.0.0: dependencies: devlop: 1.1.0 @@ -11714,6 +14410,13 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-factory-mdx-expression@2.0.1: dependencies: '@types/estree': 1.0.5 @@ -11735,6 +14438,11 @@ snapshots: micromark-util-character: 2.1.0 micromark-util-types: 2.0.0 + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.1 + micromark-factory-title@2.0.0: dependencies: micromark-factory-space: 2.0.0 @@ -11742,6 +14450,13 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-factory-whitespace@2.0.0: dependencies: micromark-factory-space: 2.0.0 @@ -11749,6 +14464,13 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-util-character@1.2.0: dependencies: micromark-util-symbol: 1.1.0 @@ -11759,25 +14481,49 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-util-chunked@2.0.0: dependencies: micromark-util-symbol: 2.0.0 + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-classify-character@2.0.0: dependencies: micromark-util-character: 2.1.0 micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-util-combine-extensions@2.0.0: dependencies: micromark-util-chunked: 2.0.0 micromark-util-types: 2.0.0 + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.1 + micromark-util-decode-numeric-character-reference@2.0.1: dependencies: micromark-util-symbol: 2.0.0 + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-decode-string@2.0.0: dependencies: decode-named-character-reference: 1.0.2 @@ -11785,8 +14531,17 @@ snapshots: micromark-util-decode-numeric-character-reference: 2.0.1 micromark-util-symbol: 2.0.0 + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.0.2 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + micromark-util-encode@2.0.0: {} + micromark-util-encode@2.0.1: {} + micromark-util-events-to-acorn@2.0.2: dependencies: '@types/acorn': 4.0.6 @@ -11800,20 +14555,36 @@ snapshots: micromark-util-html-tag-name@2.0.0: {} + micromark-util-html-tag-name@2.0.1: {} + micromark-util-normalize-identifier@2.0.0: dependencies: micromark-util-symbol: 2.0.0 + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-resolve-all@2.0.0: dependencies: micromark-util-types: 2.0.0 + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.1 + micromark-util-sanitize-uri@2.0.0: dependencies: micromark-util-character: 2.1.0 micromark-util-encode: 2.0.0 micromark-util-symbol: 2.0.0 + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-subtokenize@2.0.1: dependencies: devlop: 1.1.0 @@ -11821,18 +14592,29 @@ snapshots: micromark-util-symbol: 2.0.0 micromark-util-types: 2.0.0 + micromark-util-subtokenize@2.0.2: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + micromark-util-symbol@1.1.0: {} micromark-util-symbol@2.0.0: {} + micromark-util-symbol@2.0.1: {} + micromark-util-types@1.1.0: {} micromark-util-types@2.0.0: {} + micromark-util-types@2.0.1: {} + micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.6 + debug: 4.3.7 decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 @@ -11851,10 +14633,27 @@ snapshots: transitivePeerDependencies: - supports-color - micromatch@4.0.7: + micromark@4.0.1: dependencies: - braces: 3.0.3 - picomatch: 2.3.1 + '@types/debug': 4.1.12 + debug: 4.3.7 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.2 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.0.2 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + transitivePeerDependencies: + - supports-color micromatch@4.0.8: dependencies: @@ -11883,13 +14682,11 @@ snapshots: mimic-response@4.0.0: {} - min-indent@1.0.1: {} - - mini-css-extract-plugin@2.9.0(webpack@5.93.0): + mini-css-extract-plugin@2.9.2(webpack@5.96.1(@swc/core@1.9.2)): dependencies: schema-utils: 4.2.0 tapable: 2.2.1 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) minimalistic-assert@1.0.1: {} @@ -11901,12 +14698,6 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimist-options@4.1.0: - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - minimist@1.2.8: {} mkdirp-classic@0.5.3: {} @@ -11949,6 +14740,9 @@ snapshots: node-addon-api@6.1.0: {} + node-addon-api@7.1.1: + optional: true + node-emoji@2.1.3: dependencies: '@sindresorhus/is': 4.6.0 @@ -11971,13 +14765,6 @@ snapshots: semver: 5.7.2 validate-npm-package-license: 3.0.4 - normalize-package-data@3.0.3: - dependencies: - hosted-git-info: 4.1.0 - is-core-module: 2.15.0 - semver: 7.6.3 - validate-npm-package-license: 3.0.4 - normalize-path@2.1.1: dependencies: remove-trailing-separator: 1.1.0 @@ -11998,10 +14785,18 @@ snapshots: dependencies: boolbase: 1.0.0 + null-loader@4.0.1(webpack@5.96.1(@swc/core@1.9.2)): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.96.1(@swc/core@1.9.2) + object-assign@4.1.1: {} object-inspect@1.13.2: {} + object-inspect@1.13.3: {} + object-keys@1.1.1: {} object.assign@4.1.5: @@ -12028,7 +14823,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 object.values@1.2.0: dependencies: @@ -12161,19 +14956,19 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.24.7 + '@babel/code-frame': 7.26.2 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 parse-numeric-range@1.3.0: {} - parse5-htmlparser2-tree-adapter@7.0.0: + parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 - parse5: 7.1.2 + parse5: 7.2.1 - parse5@7.1.2: + parse5@7.2.1: dependencies: entities: 4.5.0 @@ -12208,7 +15003,7 @@ snapshots: dependencies: isarray: 0.0.1 - path-to-regexp@2.2.1: {} + path-to-regexp@3.3.0: {} path-type@3.0.0: dependencies: @@ -12224,7 +15019,7 @@ snapshots: estree-walker: 3.0.3 is-reference: 3.0.2 - picocolors@1.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -12252,243 +15047,249 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-calc@9.0.1(postcss@8.4.41): + postcss-calc@9.0.1(postcss@8.4.49): dependencies: - postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - postcss-colormin@6.1.0(postcss@8.4.41): + postcss-colormin@6.1.0(postcss@8.4.49): dependencies: - browserslist: 4.23.3 + browserslist: 4.24.2 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-convert-values@6.1.0(postcss@8.4.41): + postcss-convert-values@6.1.0(postcss@8.4.49): dependencies: - browserslist: 4.23.3 - postcss: 8.4.41 + browserslist: 4.24.2 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-discard-comments@6.0.2(postcss@8.4.41): + postcss-discard-comments@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-discard-duplicates@6.0.3(postcss@8.4.41): + postcss-discard-duplicates@6.0.3(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-discard-empty@6.0.3(postcss@8.4.41): + postcss-discard-empty@6.0.3(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-discard-overridden@6.0.2(postcss@8.4.41): + postcss-discard-overridden@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-discard-unused@6.0.5(postcss@8.4.41): + postcss-discard-unused@6.0.5(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-selector-parser: 6.1.2 - postcss-loader@7.3.4(postcss@8.4.41)(typescript@5.6.2)(webpack@5.93.0): + postcss-loader@7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: - cosmiconfig: 8.3.6(typescript@5.6.2) + cosmiconfig: 8.3.6(typescript@5.6.3) jiti: 1.21.6 - postcss: 8.4.41 + postcss: 8.4.49 semver: 7.6.3 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) transitivePeerDependencies: - typescript postcss-media-query-parser@0.2.3: {} - postcss-merge-idents@6.0.3(postcss@8.4.41): + postcss-merge-idents@6.0.3(postcss@8.4.49): dependencies: - cssnano-utils: 4.0.2(postcss@8.4.41) - postcss: 8.4.41 + cssnano-utils: 4.0.2(postcss@8.4.49) + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-merge-longhand@6.0.5(postcss@8.4.41): + postcss-merge-longhand@6.0.5(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - stylehacks: 6.1.1(postcss@8.4.41) + stylehacks: 6.1.1(postcss@8.4.49) - postcss-merge-rules@6.1.1(postcss@8.4.41): + postcss-merge-rules@6.1.1(postcss@8.4.49): dependencies: - browserslist: 4.23.3 + browserslist: 4.24.2 caniuse-api: 3.0.0 - cssnano-utils: 4.0.2(postcss@8.4.41) - postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + cssnano-utils: 4.0.2(postcss@8.4.49) + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 - postcss-minify-font-values@6.1.0(postcss@8.4.41): + postcss-minify-font-values@6.1.0(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-minify-gradients@6.0.3(postcss@8.4.41): + postcss-minify-gradients@6.0.3(postcss@8.4.49): dependencies: colord: 2.9.3 - cssnano-utils: 4.0.2(postcss@8.4.41) - postcss: 8.4.41 + cssnano-utils: 4.0.2(postcss@8.4.49) + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-minify-params@6.1.0(postcss@8.4.41): + postcss-minify-params@6.1.0(postcss@8.4.49): dependencies: - browserslist: 4.23.3 - cssnano-utils: 4.0.2(postcss@8.4.41) - postcss: 8.4.41 + browserslist: 4.24.2 + cssnano-utils: 4.0.2(postcss@8.4.49) + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-minify-selectors@6.0.4(postcss@8.4.41): + postcss-minify-selectors@6.0.4(postcss@8.4.49): dependencies: - postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 - postcss-modules-extract-imports@3.1.0(postcss@8.4.41): + postcss-modules-extract-imports@3.1.0(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-modules-local-by-default@4.0.5(postcss@8.4.41): + postcss-modules-local-by-default@4.1.0(postcss@8.4.49): dependencies: - icss-utils: 5.1.0(postcss@8.4.41) - postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 + postcss-selector-parser: 7.0.0 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.0(postcss@8.4.41): + postcss-modules-scope@3.2.1(postcss@8.4.49): dependencies: - postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + postcss: 8.4.49 + postcss-selector-parser: 7.0.0 - postcss-modules-values@4.0.0(postcss@8.4.41): + postcss-modules-values@4.0.0(postcss@8.4.49): dependencies: - icss-utils: 5.1.0(postcss@8.4.41) - postcss: 8.4.41 + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 - postcss-normalize-charset@6.0.2(postcss@8.4.41): + postcss-normalize-charset@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-normalize-display-values@6.0.2(postcss@8.4.41): + postcss-normalize-display-values@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-normalize-positions@6.0.2(postcss@8.4.41): + postcss-normalize-positions@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@6.0.2(postcss@8.4.41): + postcss-normalize-repeat-style@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-normalize-string@6.0.2(postcss@8.4.41): + postcss-normalize-string@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@6.0.2(postcss@8.4.41): + postcss-normalize-timing-functions@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@6.1.0(postcss@8.4.41): + postcss-normalize-unicode@6.1.0(postcss@8.4.49): dependencies: - browserslist: 4.23.3 - postcss: 8.4.41 + browserslist: 4.24.2 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-normalize-url@6.0.2(postcss@8.4.41): + postcss-normalize-url@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@6.0.2(postcss@8.4.41): + postcss-normalize-whitespace@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-ordered-values@6.0.2(postcss@8.4.41): + postcss-ordered-values@6.0.2(postcss@8.4.49): dependencies: - cssnano-utils: 4.0.2(postcss@8.4.41) - postcss: 8.4.41 + cssnano-utils: 4.0.2(postcss@8.4.49) + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-reduce-idents@6.0.3(postcss@8.4.41): + postcss-reduce-idents@6.0.3(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-reduce-initial@6.1.0(postcss@8.4.41): + postcss-reduce-initial@6.1.0(postcss@8.4.49): dependencies: - browserslist: 4.23.3 + browserslist: 4.24.2 caniuse-api: 3.0.0 - postcss: 8.4.41 + postcss: 8.4.49 - postcss-reduce-transforms@6.0.2(postcss@8.4.41): + postcss-reduce-transforms@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 - postcss-resolve-nested-selector@0.1.5: {} + postcss-resolve-nested-selector@0.1.6: {} - postcss-safe-parser@6.0.0(postcss@8.4.41): + postcss-safe-parser@7.0.1(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-scss@4.0.9(postcss@8.4.41): + postcss-scss@4.0.9(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-selector-parser@6.1.1: + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@6.1.2: + postcss-selector-parser@7.0.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-sort-media-queries@5.2.0(postcss@8.4.41): + postcss-sort-media-queries@5.2.0(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 sort-css-media-queries: 2.2.0 - postcss-sorting@8.0.2(postcss@8.4.41): + postcss-sorting@8.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 - postcss-svgo@6.0.3(postcss@8.4.41): + postcss-svgo@6.0.3(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss-value-parser: 4.2.0 svgo: 3.3.2 - postcss-unique-selectors@6.0.4(postcss@8.4.41): + postcss-unique-selectors@6.0.4(postcss@8.4.49): dependencies: - postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 postcss-value-parser@4.2.0: {} - postcss-zindex@6.0.2(postcss@8.4.41): + postcss-zindex@6.0.2(postcss@8.4.49): dependencies: - postcss: 8.4.41 + postcss: 8.4.49 postcss@8.4.41: dependencies: nanoid: 3.3.7 - picocolors: 1.1.0 + picocolors: 1.1.1 source-map-js: 1.2.0 + postcss@8.4.49: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prebuild-install@7.1.2: dependencies: detect-libc: 2.0.3 @@ -12555,19 +15356,17 @@ snapshots: end-of-stream: 1.4.4 once: 1.4.0 - punycode@1.4.1: {} - punycode@2.3.1: {} pupa@3.1.0: dependencies: escape-goat: 4.0.0 - pushfeedback-react@0.1.44: + pushfeedback-react@0.1.50: dependencies: - pushfeedback: 0.1.44 + pushfeedback: 0.1.49 - pushfeedback@0.1.44: + pushfeedback@0.1.49: dependencies: '@stencil/core': 2.22.3 html2canvas: 1.4.1 @@ -12615,7 +15414,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dev-utils@12.0.1(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0): + react-dev-utils@12.0.1(eslint@7.32.0)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: '@babel/code-frame': 7.24.7 address: 1.2.2 @@ -12626,7 +15425,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@7.32.0)(typescript@5.6.2)(webpack@5.93.0) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@7.32.0)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.9.2)) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -12641,9 +15440,9 @@ snapshots: shell-quote: 1.8.1 strip-ansi: 6.0.1 text-table: 0.2.0 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - eslint - supports-color @@ -12689,11 +15488,11 @@ snapshots: dependencies: react: 18.3.1 - react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.93.0): + react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.96.1(@swc/core@1.9.2)): dependencies: '@babel/runtime': 7.25.0 react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)' - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) react-router-config@5.1.1(react-router@5.3.4(react@18.3.1))(react@18.3.1): dependencies: @@ -12748,12 +15547,6 @@ snapshots: read-pkg: 5.2.0 type-fest: 0.8.1 - read-pkg-up@8.0.0: - dependencies: - find-up: 5.0.0 - read-pkg: 6.0.0 - type-fest: 1.4.0 - read-pkg@3.0.0: dependencies: load-json-file: 4.0.0 @@ -12767,13 +15560,6 @@ snapshots: parse-json: 5.2.0 type-fest: 0.6.0 - read-pkg@6.0.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 3.0.3 - parse-json: 5.2.0 - type-fest: 1.4.0 - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -12802,16 +15588,45 @@ snapshots: dependencies: resolve: 1.22.8 + recma-build-jsx@1.0.0: + dependencies: + '@types/estree': 1.0.6 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.0(acorn@8.12.1): + dependencies: + acorn-jsx: 5.3.2(acorn@8.12.1) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - acorn + + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.6 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.6 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + recursive-readdir@2.2.3: dependencies: minimatch: 3.1.2 - redent@4.0.0: + regenerate-unicode-properties@10.1.1: dependencies: - indent-string: 5.0.0 - strip-indent: 4.0.0 + regenerate: 1.4.2 - regenerate-unicode-properties@10.1.1: + regenerate-unicode-properties@10.2.0: dependencies: regenerate: 1.4.2 @@ -12832,6 +15647,13 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 + regexp.prototype.flags@1.5.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + regexpp@3.2.0: {} regexpu-core@5.3.2: @@ -12843,6 +15665,15 @@ snapshots: unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.1.0 + regexpu-core@6.1.1: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.0 + regjsgen: 0.8.0 + regjsparser: 0.11.2 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.0 + registry-auth-token@5.0.2: dependencies: '@pnpm/npm-conf': 2.3.1 @@ -12851,6 +15682,12 @@ snapshots: dependencies: rc: 1.2.8 + regjsgen@0.8.0: {} + + regjsparser@0.11.2: + dependencies: + jsesc: 3.0.2 + regjsparser@0.9.1: dependencies: jsesc: 0.5.0 @@ -12858,9 +15695,17 @@ snapshots: rehype-raw@7.0.0: dependencies: '@types/hast': 3.0.4 - hast-util-raw: 9.0.4 + hast-util-raw: 9.1.0 vfile: 6.0.3 + rehype-recma@1.0.0: + dependencies: + '@types/estree': 1.0.6 + '@types/hast': 3.0.4 + hast-util-to-estree: 3.1.0 + transitivePeerDependencies: + - supports-color + relateurl@0.2.7: {} remark-directive@3.0.0: @@ -12907,6 +15752,13 @@ snapshots: transitivePeerDependencies: - supports-color + remark-mdx@3.1.0: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 @@ -12924,10 +15776,18 @@ snapshots: unified: 11.0.5 vfile: 6.0.2 + remark-rehype@11.1.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.0 + unified: 11.0.5 + vfile: 6.0.3 + remark-stringify@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-to-markdown: 2.1.0 + mdast-util-to-markdown: 2.1.2 unified: 11.0.5 remove-trailing-separator@1.1.0: {} @@ -12940,6 +15800,8 @@ snapshots: lodash: 4.17.21 strip-ansi: 6.0.1 + repeat-string@1.6.1: {} + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -12994,7 +15856,7 @@ snapshots: rtlcss@4.2.0: dependencies: escalade: 3.1.2 - picocolors: 1.1.0 + picocolors: 1.1.1 postcss: 8.4.41 strip-json-comments: 3.1.1 @@ -13031,22 +15893,24 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@10.5.2(sass@1.79.3)(webpack@5.93.0): + sass-loader@10.5.2(sass@1.81.0)(webpack@5.93.0(@swc/core@1.9.2)): dependencies: klona: 2.0.6 loader-utils: 2.0.4 neo-async: 2.6.2 schema-utils: 3.3.0 semver: 7.6.3 - webpack: 5.93.0 + webpack: 5.93.0(@swc/core@1.9.2) optionalDependencies: - sass: 1.79.3 + sass: 1.81.0 - sass@1.79.3: + sass@1.81.0: dependencies: chokidar: 4.0.1 - immutable: 4.3.7 + immutable: 5.0.2 source-map-js: 1.2.0 + optionalDependencies: + '@parcel/watcher': 2.5.0 sax@1.4.1: {} @@ -13119,15 +15983,14 @@ snapshots: dependencies: randombytes: 2.1.0 - serve-handler@6.1.5: + serve-handler@6.1.6: dependencies: bytes: 3.0.0 content-disposition: 0.5.2 - fast-url-parser: 1.1.3 mime-types: 2.1.18 minimatch: 3.1.2 path-is-inside: 1.0.2 - path-to-regexp: 2.2.1 + path-to-regexp: 3.3.0 range-parser: 1.2.0 serve-index@1.9.1: @@ -13302,6 +16165,8 @@ snapshots: source-map-js@1.2.0: {} + source-map-js@1.2.1: {} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 @@ -13329,7 +16194,7 @@ snapshots: spdy-transport@3.0.0: dependencies: - debug: 4.3.6 + debug: 4.3.7 detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -13340,7 +16205,7 @@ snapshots: spdy@4.0.2: dependencies: - debug: 4.3.6 + debug: 4.3.7 handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -13356,7 +16221,7 @@ snapshots: statuses@2.0.1: {} - std-env@3.7.0: {} + std-env@3.8.0: {} streamx@2.18.0: dependencies: @@ -13447,16 +16312,10 @@ snapshots: strip-final-newline@2.0.0: {} - strip-indent@4.0.0: - dependencies: - min-indent: 1.0.1 - strip-json-comments@2.0.1: {} strip-json-comments@3.1.1: {} - style-search@0.1.0: {} - style-to-object@0.4.4: dependencies: inline-style-parser: 0.1.1 @@ -13465,97 +16324,102 @@ snapshots: dependencies: inline-style-parser: 0.2.3 - stylehacks@6.1.1(postcss@8.4.41): + style-to-object@1.0.8: dependencies: - browserslist: 4.23.3 - postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + inline-style-parser: 0.2.4 - stylelint-config-recess-order@4.6.0(stylelint@15.11.0(typescript@5.6.2)): + stylehacks@6.1.1(postcss@8.4.49): dependencies: - stylelint: 15.11.0(typescript@5.6.2) - stylelint-order: 6.0.4(stylelint@15.11.0(typescript@5.6.2)) + browserslist: 4.24.2 + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 + + stylelint-config-recess-order@5.1.1(stylelint@16.10.0(typescript@5.6.3)): + dependencies: + stylelint: 16.10.0(typescript@5.6.3) + stylelint-order: 6.0.4(stylelint@16.10.0(typescript@5.6.3)) - stylelint-config-recommended-scss@13.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)): + stylelint-config-recommended-scss@14.1.0(postcss@8.4.49)(stylelint@16.10.0(typescript@5.6.3)): dependencies: - postcss-scss: 4.0.9(postcss@8.4.41) - stylelint: 15.11.0(typescript@5.6.2) - stylelint-config-recommended: 13.0.0(stylelint@15.11.0(typescript@5.6.2)) - stylelint-scss: 5.3.2(stylelint@15.11.0(typescript@5.6.2)) + postcss-scss: 4.0.9(postcss@8.4.49) + stylelint: 16.10.0(typescript@5.6.3) + stylelint-config-recommended: 14.0.1(stylelint@16.10.0(typescript@5.6.3)) + stylelint-scss: 6.9.0(stylelint@16.10.0(typescript@5.6.3)) optionalDependencies: - postcss: 8.4.41 + postcss: 8.4.49 - stylelint-config-recommended@13.0.0(stylelint@15.11.0(typescript@5.6.2)): + stylelint-config-recommended@14.0.1(stylelint@16.10.0(typescript@5.6.3)): dependencies: - stylelint: 15.11.0(typescript@5.6.2) + stylelint: 16.10.0(typescript@5.6.3) - stylelint-config-standard-scss@11.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)): + stylelint-config-standard-scss@13.1.0(postcss@8.4.49)(stylelint@16.10.0(typescript@5.6.3)): dependencies: - stylelint: 15.11.0(typescript@5.6.2) - stylelint-config-recommended-scss: 13.1.0(postcss@8.4.41)(stylelint@15.11.0(typescript@5.6.2)) - stylelint-config-standard: 34.0.0(stylelint@15.11.0(typescript@5.6.2)) + stylelint: 16.10.0(typescript@5.6.3) + stylelint-config-recommended-scss: 14.1.0(postcss@8.4.49)(stylelint@16.10.0(typescript@5.6.3)) + stylelint-config-standard: 36.0.1(stylelint@16.10.0(typescript@5.6.3)) optionalDependencies: - postcss: 8.4.41 + postcss: 8.4.49 - stylelint-config-standard@34.0.0(stylelint@15.11.0(typescript@5.6.2)): + stylelint-config-standard@36.0.1(stylelint@16.10.0(typescript@5.6.3)): dependencies: - stylelint: 15.11.0(typescript@5.6.2) - stylelint-config-recommended: 13.0.0(stylelint@15.11.0(typescript@5.6.2)) + stylelint: 16.10.0(typescript@5.6.3) + stylelint-config-recommended: 14.0.1(stylelint@16.10.0(typescript@5.6.3)) - stylelint-order@6.0.4(stylelint@15.11.0(typescript@5.6.2)): + stylelint-order@6.0.4(stylelint@16.10.0(typescript@5.6.3)): dependencies: - postcss: 8.4.41 - postcss-sorting: 8.0.2(postcss@8.4.41) - stylelint: 15.11.0(typescript@5.6.2) + postcss: 8.4.49 + postcss-sorting: 8.0.2(postcss@8.4.49) + stylelint: 16.10.0(typescript@5.6.3) - stylelint-scss@5.3.2(stylelint@15.11.0(typescript@5.6.2)): + stylelint-scss@6.9.0(stylelint@16.10.0(typescript@5.6.3)): dependencies: - known-css-properties: 0.29.0 + css-tree: 3.0.1 + is-plain-object: 5.0.0 + known-css-properties: 0.35.0 + mdn-data: 2.12.2 postcss-media-query-parser: 0.2.3 - postcss-resolve-nested-selector: 0.1.5 - postcss-selector-parser: 6.1.1 + postcss-resolve-nested-selector: 0.1.6 + postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - stylelint: 15.11.0(typescript@5.6.2) + stylelint: 16.10.0(typescript@5.6.3) - stylelint@15.11.0(typescript@5.6.2): + stylelint@16.10.0(typescript@5.6.3): dependencies: - '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) - '@csstools/css-tokenizer': 2.4.1 - '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) - '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.1) + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + '@csstools/media-query-list-parser': 3.0.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/selector-specificity': 4.0.0(postcss-selector-parser@6.1.2) + '@dual-bundle/import-meta-resolve': 4.1.0 balanced-match: 2.0.0 colord: 2.9.3 - cosmiconfig: 8.3.6(typescript@5.6.2) - css-functions-list: 3.2.2 - css-tree: 2.3.1 - debug: 4.3.6 + cosmiconfig: 9.0.0(typescript@5.6.3) + css-functions-list: 3.2.3 + css-tree: 3.0.1 + debug: 4.3.7 fast-glob: 3.3.2 fastest-levenshtein: 1.0.16 - file-entry-cache: 7.0.2 + file-entry-cache: 9.1.0 global-modules: 2.0.0 globby: 11.1.0 globjoin: 0.1.4 html-tags: 3.3.1 - ignore: 5.3.1 - import-lazy: 4.0.0 + ignore: 6.0.2 imurmurhash: 0.1.4 is-plain-object: 5.0.0 - known-css-properties: 0.29.0 + known-css-properties: 0.34.0 mathml-tag-names: 2.1.3 - meow: 10.1.5 - micromatch: 4.0.7 + meow: 13.2.0 + micromatch: 4.0.8 normalize-path: 3.0.0 - picocolors: 1.1.0 - postcss: 8.4.41 - postcss-resolve-nested-selector: 0.1.5 - postcss-safe-parser: 6.0.0(postcss@8.4.41) - postcss-selector-parser: 6.1.1 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-resolve-nested-selector: 0.1.6 + postcss-safe-parser: 7.0.1(postcss@8.4.49) + postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 string-width: 4.2.3 - strip-ansi: 6.0.1 - style-search: 0.1.0 - supports-hyperlinks: 3.0.0 + supports-hyperlinks: 3.1.0 svg-tags: 1.0.0 table: 6.8.2 write-file-atomic: 5.0.1 @@ -13577,7 +16441,7 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-hyperlinks@3.0.0: + supports-hyperlinks@3.1.0: dependencies: has-flag: 4.0.0 supports-color: 7.2.0 @@ -13596,7 +16460,13 @@ snapshots: css-tree: 2.3.1 css-what: 6.1.0 csso: 5.0.5 - picocolors: 1.1.0 + picocolors: 1.1.1 + + swc-loader@0.2.6(@swc/core@1.9.2)(webpack@5.96.1(@swc/core@1.9.2)): + dependencies: + '@swc/core': 1.9.2 + '@swc/counter': 0.1.3 + webpack: 5.96.1(@swc/core@1.9.2) table@6.8.2: dependencies: @@ -13639,23 +16509,27 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.18.0 - terser-webpack-plugin@5.3.10(webpack@5.93.0): + terser-webpack-plugin@5.3.10(@swc/core@1.9.2)(webpack@5.93.0(@swc/core@1.9.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.5 - webpack: 5.93.0 + webpack: 5.93.0(@swc/core@1.9.2) + optionalDependencies: + '@swc/core': 1.9.2 - terser-webpack-plugin@5.3.10(webpack@5.95.0): + terser-webpack-plugin@5.3.10(@swc/core@1.9.2)(webpack@5.96.1(@swc/core@1.9.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.5 - webpack: 5.95.0 + webpack: 5.96.1(@swc/core@1.9.2) + optionalDependencies: + '@swc/core': 1.9.2 terser@5.31.5: dependencies: @@ -13664,6 +16538,13 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + terser@5.36.0: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.0 + commander: 2.20.3 + source-map-support: 0.5.21 + text-decoder@1.1.1: dependencies: b4a: 1.6.6 @@ -13707,13 +16588,11 @@ snapshots: trim-lines@3.0.1: {} - trim-newlines@4.1.1: {} - trough@2.2.0: {} - ts-api-utils@1.3.0(typescript@5.6.2): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: - typescript: 5.6.2 + typescript: 5.6.3 tsconfig-paths@3.15.0: dependencies: @@ -13726,7 +16605,7 @@ snapshots: tslib@2.6.3: {} - tslib@2.7.0: {} + tslib@2.8.1: {} tunnel-agent@0.6.0: dependencies: @@ -13789,7 +16668,7 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript@5.6.2: {} + typescript@5.6.3: {} unbox-primitive@1.0.2: dependencies: @@ -13811,6 +16690,8 @@ snapshots: unicode-match-property-value-ecmascript@2.1.0: {} + unicode-match-property-value-ecmascript@2.2.0: {} + unicode-property-aliases-ecmascript@2.1.0: {} unified@11.0.5: @@ -13867,13 +16748,13 @@ snapshots: dependencies: browserslist: 4.23.3 escalade: 3.1.2 - picocolors: 1.1.0 + picocolors: 1.1.1 - update-browserslist-db@1.1.1(browserslist@4.24.0): + update-browserslist-db@1.1.1(browserslist@4.24.2): dependencies: - browserslist: 4.24.0 + browserslist: 4.24.2 escalade: 3.2.0 - picocolors: 1.1.0 + picocolors: 1.1.1 update-notifier@6.0.2: dependencies: @@ -13896,23 +16777,23 @@ snapshots: dependencies: punycode: 2.3.1 - url-loader@4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.93.0(@swc/core@1.9.2)))(webpack@5.93.0(@swc/core@1.9.2)): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.93.0 + webpack: 5.93.0(@swc/core@1.9.2) optionalDependencies: - file-loader: 6.2.0(webpack@5.93.0) + file-loader: 6.2.0(webpack@5.93.0(@swc/core@1.9.2)) - url-loader@4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.95.0): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.93.0(@swc/core@1.9.2)))(webpack@5.96.1(@swc/core@1.9.2)): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.95.0 + webpack: 5.96.1(@swc/core@1.9.2) optionalDependencies: - file-loader: 6.2.0(webpack@5.93.0) + file-loader: 6.2.0(webpack@5.93.0(@swc/core@1.9.2)) util-deprecate@1.0.2: {} @@ -13989,23 +16870,23 @@ snapshots: gzip-size: 6.0.0 html-escaper: 2.0.2 opener: 1.5.2 - picocolors: 1.1.0 + picocolors: 1.1.1 sirv: 2.0.4 ws: 7.5.10 transitivePeerDependencies: - bufferutil - utf-8-validate - webpack-dev-middleware@5.3.4(webpack@5.93.0): + webpack-dev-middleware@5.3.4(webpack@5.96.1(@swc/core@1.9.2)): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) - webpack-dev-server@4.15.2(webpack@5.93.0): + webpack-dev-server@4.15.2(webpack@5.96.1(@swc/core@1.9.2)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -14035,10 +16916,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.93.0) + webpack-dev-middleware: 5.3.4(webpack@5.96.1(@swc/core@1.9.2)) ws: 8.18.0 optionalDependencies: - webpack: 5.93.0 + webpack: 5.96.1(@swc/core@1.9.2) transitivePeerDependencies: - bufferutil - debug @@ -14051,9 +16932,15 @@ snapshots: flat: 5.0.2 wildcard: 2.0.1 + webpack-merge@6.0.1: + dependencies: + clone-deep: 4.0.1 + flat: 5.0.2 + wildcard: 2.0.1 + webpack-sources@3.2.3: {} - webpack@5.93.0: + webpack@5.93.0(@swc/core@1.9.2): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 @@ -14076,7 +16963,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.93.0) + terser-webpack-plugin: 5.3.10(@swc/core@1.9.2)(webpack@5.93.0(@swc/core@1.9.2)) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -14084,15 +16971,15 @@ snapshots: - esbuild - uglify-js - webpack@5.95.0: + webpack@5.96.1(@swc/core@1.9.2): dependencies: + '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/wasm-edit': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.12.1 - acorn-import-attributes: 1.9.5(acorn@8.12.1) - browserslist: 4.24.0 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.14.0 + browserslist: 4.24.2 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.1 es-module-lexer: 1.5.4 @@ -14106,7 +16993,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.95.0) + terser-webpack-plugin: 5.3.10(@swc/core@1.9.2)(webpack@5.96.1(@swc/core@1.9.2)) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -14114,13 +17001,17 @@ snapshots: - esbuild - uglify-js - webpackbar@5.0.2(webpack@5.93.0): + webpackbar@6.0.1(webpack@5.96.1(@swc/core@1.9.2)): dependencies: + ansi-escapes: 4.3.2 chalk: 4.1.2 - consola: 2.15.3 + consola: 3.2.3 + figures: 3.2.0 + markdown-table: 2.0.0 pretty-time: 1.1.0 - std-env: 3.7.0 - webpack: 5.93.0 + std-env: 3.8.0 + webpack: 5.96.1(@swc/core@1.9.2) + wrap-ansi: 7.0.0 websocket-driver@0.7.4: dependencies: @@ -14175,6 +17066,12 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@8.1.0: dependencies: ansi-styles: 6.2.1 @@ -14209,8 +17106,6 @@ snapshots: yallist@3.1.1: {} - yallist@4.0.0: {} - yaml@1.10.2: {} yargs-parser@18.1.3: @@ -14218,8 +17113,6 @@ snapshots: camelcase: 5.3.1 decamelize: 1.2.0 - yargs-parser@20.2.9: {} - yargs@15.4.1: dependencies: cliui: 6.0.0 diff --git a/src/app/doc-item.scss b/src/app/doc-item.scss index 501fae6201..7624878fc8 100644 --- a/src/app/doc-item.scss +++ b/src/app/doc-item.scss @@ -1,4 +1,4 @@ -@import "./theme"; +@use "./theme"; html { /** diff --git a/src/app/index.scss b/src/app/index.scss index 9f389dd50b..4b20256db6 100644 --- a/src/app/index.scss +++ b/src/app/index.scss @@ -6,11 +6,11 @@ * work well for content-centric websites. */ -@import "./theme"; -@import "./scroll"; -@import "./navbar"; -@import "./doc-item"; -@import "../features/feedback/doc/pushfeedback"; +@use "./theme"; +@use "./scroll"; +@use "./navbar"; +@use "./doc-item"; +@use "../features/feedback/doc/pushfeedback"; h1, h2, diff --git a/src/app/navbar.scss b/src/app/navbar.scss index eae0ff67a0..86d882aad6 100644 --- a/src/app/navbar.scss +++ b/src/app/navbar.scss @@ -1,4 +1,4 @@ -@import "./theme"; +@use "./theme"; .navbar { &__brand { diff --git a/src/app/scroll.scss b/src/app/scroll.scss index 37075e1fa1..595a17ec4e 100644 --- a/src/app/scroll.scss +++ b/src/app/scroll.scss @@ -1,4 +1,4 @@ -@import "./theme"; +@use "./theme"; /* Inherited from docusaurus scrollbar stylesheets for inner containers */ html { From 03e5a82ca4ad8ad70facb3a7cf5b90e8118e68c9 Mon Sep 17 00:00:00 2001 From: Minsu <52266597+Gaic4o@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:53:56 +0900 Subject: [PATCH 19/29] docs: with-react-query page translated into Korean (#750) * docs: with-react-query page translated into Korean * docs: apply feedback to Korean translation of with-react-query page --- .../current/guides/tech/with-react-query.mdx | 425 ++++++++++++++++++ 1 file changed, 425 insertions(+) create mode 100644 i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx b/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx new file mode 100644 index 0000000000..280c254a95 --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx @@ -0,0 +1,425 @@ +--- +sidebar_position: 10 +--- +# React Query와 함께 사용하기 + +## “키를 어디에 두어야 하는가” 문제 + +### 해결책 — 엔티티별로 분리하기 + +프로젝트가 이미 엔티티 단위로 구성되어 있으며, 각 요청이 단일 엔티티에 해당한다면, 엔티티별로 코드를 구성하는 것이 좋습니다. 예를 들어, 다음과 같은 디렉토리 구조를 사용할 수 있습니다: + +```sh +└── src/ # + ├── app/ # + | ... # + ├── pages/ # + | ... # + ├── entities/ # + | ├── {entity}/ # + | ... └── api/ # + | ├── `{entity}.query` # 쿼리 키와 함수 + | ├── `get-{entity}` # 엔티티 조회 함수 + | ├── `create-{entity}` # 엔티티 생성 함수 + | ├── `update-{entity}` # 엔티티 업데이트 함수 + | ├── `delete-{entity}` # 엔티티 삭제 함수 + | ... # + | # + ├── features/ # + | ... # + ├── widgets/ # + | ... # + └── shared/ # + ... # +``` + +만약 엔티티 간에 연결이 필요한 경우 (예: Country 엔티티에 City 엔티티 필드가 포함되는 경우), [@x-notation을 활용한 교차 임포트 방식](https://github.com/feature-sliced/documentation/discussions/390#discussioncomment-5570073)을 사용하거나 대안으로 아래의 구조를 고려할 수 있습니다. + +### 대안 방안 — shared에 유지하기 + +엔티티별 분리가 적절하지 않은 경우, 다음과 같은 구조를 사용할 수 있습니다: + +```sh +└── src/ # + ... # + └── shared/ # + ├── api/ # + ... ├── `queries` # 쿼리 팩토리들 + | ├── `document.ts` # + | ├── `background-jobs.ts` # + | ... # + └── index.ts # +``` + +이후 `@/shared/api/index.ts`에서 다음과 같이 사용합니다: + +```ts title="@/shared/api/index.ts" +export { documentQueries } from "./queries/document"; +``` + +## "mutation 위치 설정" 문제 + +쿼리와 mutation을 같은 위치에 두는 것은 권장되지 않습니다. 다음 두 가지 옵션이 있습니다: + +### 1. 사용 위치 근처의 `api` 디렉토리에서 커스텀 훅 정의하기 + +```tsx title="@/features/update-post/api/use-update-title.ts" +export const useUpdateTitle = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ id, newTitle }) => + apiClient + .patch(`/posts/${id}`, { title: newTitle }) + .then((data) => console.log(data)), + + onSuccess: (newPost) => { + queryClient.setQueryData(postsQueries.ids(id), newPost); + }, + }); +}; +``` + +### 2. 공용 또는 엔티티에서 mutation 함수를 정의하고, 컴포넌트에서 `useMutation`을 직접 사용하기 + +```tsx +const { mutateAsync, isPending } = useMutation({ + mutationFn: postApi.createPost, +}); +``` + +```tsx title="@/pages/post-create/ui/post-create-page.tsx" +export const CreatePost = () => { + const { classes } = useStyles(); + const [title, setTitle] = useState(""); + + const { mutate, isPending } = useMutation({ + mutationFn: postApi.createPost, + }); + + const handleChange = (e: ChangeEvent) => + setTitle(e.target.value); + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + mutate({ title, userId: DEFAULT_USER_ID }); + }; + + return ( +
+ + + Create + + + ); +}; +``` + +## 요청의 조직화 + +### 쿼리 팩토리 + +쿼리 팩토리는 쿼리 키 목록을 반환하는 함수를 포함한 객체입니다. 사용 방법은 다음과 같습니다: + +```ts +const keyFactory = { + all: () => ["entity"], + lists: () => [...postQueries.all(), "list"], +}; +``` + +:::info +`queryOptions`는 react-query@v5의 내장 유틸리티입니다 (선택 사항) + +```ts +queryOptions({ + queryKey, + ...options, +}); +``` + +더 큰 타입 안정성, react-query의 향후 버전과의 호환성, 함수 및 쿼리 키에 대한 쉬운 액세스를 위해, "@tanstack/react-query"의 내장 queryOptions 함수를 사용할 수 있습니다 [(자세한 내용은 여기)](https://tkdodo.eu/blog/the-query-options-api#queryoptions). + +::: + +### 1. 쿼리 팩토리 생성 예시 + +```tsx title="@/entities/post/api/post.queries.ts" +import { keepPreviousData, queryOptions } from "@tanstack/react-query"; +import { getPosts } from "./get-posts"; +import { getDetailPost } from "./get-detail-post"; +import { PostDetailQuery } from "./query/post.query"; + +export const postQueries = { + all: () => ["posts"], + + lists: () => [...postQueries.all(), "list"], + list: (page: number, limit: number) => + queryOptions({ + queryKey: [...postQueries.lists(), page, limit], + queryFn: () => getPosts(page, limit), + placeholderData: keepPreviousData, + }), + + details: () => [...postQueries.all(), "detail"], + detail: (query?: PostDetailQuery) => + queryOptions({ + queryKey: [...postQueries.details(), query?.id], + queryFn: () => getDetailPost({ id: query?.id }), + staleTime: 5000, + }), +}; +``` + +### 2. 애플리케이션 코드에서의 쿼리 팩토리 사용 예시 +```tsx +import { useParams } from "react-router-dom"; +import { postApi } from "@/entities/post"; +import { useQuery } from "@tanstack/react-query"; + +type Params = { + postId: string; +}; + +export const PostPage = () => { + const { postId } = useParams(); + const id = parseInt(postId || ""); + const { + data: post, + error, + isLoading, + isError, + } = useQuery(postApi.postQueries.detail({ id })); + + if (isLoading) { + return
Loading...
; + } + + if (isError || !post) { + return <>{error?.message}; + } + + return ( +
+

Post id: {post.id}

+
+

{post.title}

+
+

{post.body}

+
+
+
Owner: {post.userId}
+
+ ); +}; +``` + +### 쿼리 팩토리 사용의 장점 +- **요청 구조화**: 팩토리를 통해 모든 API 요청을 한 곳에 조직화하여 코드의 가독성과 유지보수성을 높입니다. +- **쿼리 및 키에 대한 편리한 접근**: 다양한 유형의 쿼리와 해당 키에 쉽게 접근할 수 있는 메서드를 제공합니다. +- **쿼리 재호출 용이성**: 애플리케이션의 여러 부분에서 쿼리 키를 변경할 필요 없이 쉽게 재호출할 수 있습니다. + +## 페이지네이션 +이 섹션에서는 페이지네이션을 사용하여 게시물 엔티티를 가져오는 API 요청을 수행하는 `getPosts` 함수의 예를 소개합니다. + +### 1. `getPosts` 함수 생성하기 +getPosts 함수는 `api` 세그먼트의 `get-posts.ts` 파일에 있습니다. + +```tsx title="@/pages/post-feed/api/get-posts.ts" +import { apiClient } from "@/shared/api/base"; + +import { PostWithPaginationDto } from "./dto/post-with-pagination.dto"; +import { PostQuery } from "./query/post.query"; +import { mapPost } from "./mapper/map-post"; +import { PostWithPagination } from "../model/post-with-pagination"; + +const calculatePostPage = (totalCount: number, limit: number) => + Math.floor(totalCount / limit); + +export const getPosts = async ( + page: number, + limit: number, +): Promise => { + const skip = page * limit; + const query: PostQuery = { skip, limit }; + const result = await apiClient.get("/posts", query); + + return { + posts: result.posts.map((post) => mapPost(post)), + limit: result.limit, + skip: result.skip, + total: result.total, + totalPages: calculatePostPage(result.total, limit), + }; +}; +``` + +### 2. 페이지네이션을 위한 쿼리 팩토리 +`postQueries` 쿼리 팩토리는 특정 페이지와 제한에 맞춰 게시물 목록을 요청하는 등 게시물 관련 다양한 쿼리 옵션을 정의합니다. + +```tsx +import { keepPreviousData, queryOptions } from "@tanstack/react-query"; +import { getPosts } from "./get-posts"; + +export const postQueries = { + all: () => ["posts"], + lists: () => [...postQueries.all(), "list"], + list: (page: number, limit: number) => + queryOptions({ + queryKey: [...postQueries.lists(), page, limit], + queryFn: () => getPosts(page, limit), + placeholderData: keepPreviousData, + }), +}; +``` + + +### 3. 애플리케이션 코드에서의 사용 + +```tsx title="@/pages/home/ui/index.tsx" +export const HomePage = () => { + const itemsOnScreen = DEFAULT_ITEMS_ON_SCREEN; + const [page, setPage] = usePageParam(DEFAULT_PAGE); + const { data, isFetching, isLoading } = useQuery( + postApi.postQueries.list(page, itemsOnScreen), + ); + return ( + <> + setPage(page)} + page={page} + count={data?.totalPages} + variant="outlined" + color="primary" + /> + + + ); +}; +``` +:::note +예시는 단순화된 버전이며, 전체 코드는 [GitHub](https://github.com/ruslan4432013/fsd-react-query-example)에서 확인할 수 있습니다. +::: + +## 쿼리 관리를 위한 `QueryProvider` +이 가이드에서는 `QueryProvider`를 어떻게 구성하는지 살펴봅니다. + +### 1. `QueryProvider` 생성하기 +`query-provider.tsx` 파일은 `@/app/providers/query-provider.tsx` 경로에 있습니다. + +```tsx title="@/app/providers/query-provider.tsx" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { ReactNode } from "react"; + +type Props = { + children: ReactNode; + client: QueryClient; +}; + +export const QueryProvider = ({ client, children }: Props) => { + return ( + + {children} + + + ); +}; +``` + +### 2. `QueryClient` 생성하기 +`QueryClient`는 API 요청을 관리하는 인스턴스입니다. `query-client.ts` 파일은 `@/shared/api/query-client.ts`에 속해 있으며, 쿼리 캐싱을 위해 특정 설정으로 `QueryClient`를 생성합니다. + +```tsx title="@/shared/api/query-client.ts" +import { QueryClient } from "@tanstack/react-query"; + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, + gcTime: 5 * 60 * 1000, + }, + }, +}); +``` + +## 코드 생성 + +API 코드를 생성해주는 도구들이 있지만, 이러한 방식은 위의 예제 처럼 직접 코드를 작성하는 방법보다 유연성이 부족할 수 있습니다. 그러나 Swagger 파일이 잘 구성되어 있고 이러한 자동 생성 도구를 사용하는 경우, 생성된 코드를 `@/shared/api` 디렉토리에 두어 관리하는 것이 효율적일 수 있습니다. + + +## React Query를 조직화하기 위한 추가 조언 +### API 클라이언트 + +공유 레이어에서 커스텀 API 클라이언트 클래스를 사용하면, 프로젝트 내 API 작업을 일관성 있게 관리할 수 있습니다. 이를 통해 로깅, 헤더 설정, 데이터 전송 형식(JSON 또는 XML 등)을 한 곳에서 관리할 수 있게 됩니다. 또한 이 접근 방식은 API와의 상호작용에 대한 변경 사항을 쉽게 반영할 수 있게 하여, 프로젝트의 유지보수성과 개발 편의성을 크게 향상시킵니다. + + +```tsx title="@/shared/api/api-client.ts" +import { API_URL } from "@/shared/config"; + +export class ApiClient { + private baseUrl: string; + + constructor(url: string) { + this.baseUrl = url; + } + + async handleResponse(response: Response): Promise { + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + try { + return await response.json(); + } catch (error) { + throw new Error("Error parsing JSON response"); + } + } + + public async get( + endpoint: string, + queryParams?: Record, + ): Promise { + const url = new URL(endpoint, this.baseUrl); + + if (queryParams) { + Object.entries(queryParams).forEach(([key, value]) => { + url.searchParams.append(key, value.toString()); + }); + } + const response = await fetch(url.toString(), { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + return this.handleResponse(response); + } + + public async post>( + endpoint: string, + body: TData, + ): Promise { + const response = await fetch(`${this.baseUrl}${endpoint}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + return this.handleResponse(response); + } +} + +export const apiClient = new ApiClient(API_URL); +``` + +## 참고 자료 {#see-also} + +- [(GitHub) 샘플 프로젝트](https://github.com/ruslan4432013/fsd-react-query-example) +- [(CodeSandbox) 샘플 프로젝트](https://codesandbox.io/p/github/ruslan4432013/fsd-react-query-example/main) +- [쿼리 팩토리에 대하여](https://tkdodo.eu/blog/the-query-options-api) + + From faf487cf560f74f4ad17cf725e9a413eb6cfad11 Mon Sep 17 00:00:00 2001 From: Minsu <52266597+Gaic4o@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:55:47 +0900 Subject: [PATCH 20/29] docs: about mission page translated into Korean (#754) * docs: about mission page translated into Korean * docs: apply feedback to Korean translation of mission page --- .../current/about/mission.md | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 i18n/kr/docusaurus-plugin-content-docs/current/about/mission.md diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/about/mission.md b/i18n/kr/docusaurus-plugin-content-docs/current/about/mission.md new file mode 100644 index 0000000000..a13527ccc6 --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/current/about/mission.md @@ -0,0 +1,51 @@ +--- +sidebar_position: 1 +--- + +# 미션 + +이 문서에서는 방법론을 개발할 때 우리가 추구하는 목표와 적용 가능성의 한계를 설명합니다. + +- 방법론 개발의 목표는 이념과 단순성 간의 균형을 맞추는 것입니다. +- 모든 사람에게 완벽하게 맞는 만능 해결책을 만들 수는 없습니다. + +**그럼에도, 방법론은 다양한 개발자들에게 접근하기 쉽고 실용적이어야 합니다.** + +## 목표 + +### 다양한 개발자에게 직관적이고 명확하게 + +방법론은 프로젝트에 참여하는 대부분의 팀원들이 쉽게 접근하고 이해할 수 있도록 설계되어야 합니다.
+ +*향후 어떤 도구가 추가되더라도, 시니어나 리더 개발자들만 이해할 수 있는 방법론이라면 충분하지 않습니다.* + +### 일상적인 문제 해결 + +방법론은 개발 프로젝트에서 일상적으로 발생하는 문제에 대해 명확한 이유와 해결책을 제시해야 합니다. + +**이를 위해 CLI와 린터(linter) 같은 도구들도 함께 제공해야 합니다.** + +이를 통해 개발자들은 아키텍처와 개발상의 오랜 문제를 우회할 수 있는 검증된 접근 방식을 활용할 수 있습니다. + +> *@sergeysova: 방법론을 기반으로 코드를 작성하는 개발자는 이미 많은 문제에 대한 해결책이 마련되어 있기 때문에, 문제 발생 빈도가 10배 정도 줄어들 것이라고 상상해보세요.* + +## 한계 + +우리는 *특정 관점을 강요하고* 싶지 않으며, 개발자로서의 *여러 습관이 문제 해결을 방해할 수 있다는 점도 이해합니다.* + +모든 개발자의 시스템을 설계하거나 개발하는 데 경험 수준이 다르기 떄문에, **다음 사항을 이해하는 것이 중요합니다:** + +- **모두에게 동일하게 적용되지 않을 수 있음:**: 너무 간단하거나 명확한 접근법이 모든 상황에서 항상 효과적이지는 않습니다. + > *@sergeysova: 어떤 개념들은 문제를 직접 겪고, 오랜 시간을 들여 해결하는 과정을 통해서만 직관적으로 이해할 수 있는 경우가 많습니다. + > + > - *수학: 그래프 이론.* + > - *물리학: 양자 역학.* + > - *프로그래밍: 애플리케이션 아키텍처.* + +- **가능하고 바람직한 방향**: 단순함과 확장 가능성의 조화 + +## 참고 자료 + +- [아키텍쳐 문제들][refs-architecture--problems] + +[refs-architecture--problems]: /docs/about/understanding/architecture#problems From 645c569d39317639a6071bbdcfa64f7253d645b6 Mon Sep 17 00:00:00 2001 From: Minsu <52266597+Gaic4o@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:56:43 +0900 Subject: [PATCH 21/29] docs: community page translated into Korean (#757) * docs: community page translated into Korean * docs: apply feedback to Korean translation of community page --- .../community/index.mdx | 41 +++++++++++++++++++ .../community/team.mdx | 18 ++++++++ 2 files changed, 59 insertions(+) create mode 100644 i18n/kr/docusaurus-plugin-content-docs/community/index.mdx create mode 100644 i18n/kr/docusaurus-plugin-content-docs/community/team.mdx diff --git a/i18n/kr/docusaurus-plugin-content-docs/community/index.mdx b/i18n/kr/docusaurus-plugin-content-docs/community/index.mdx new file mode 100644 index 0000000000..bb8a09a1a9 --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/community/index.mdx @@ -0,0 +1,41 @@ +--- +hide_table_of_contents: true +--- + +# 💫 커뮤니티 + +

+커뮤니티 리소스, 추가 자료 +

+ +## Main + +import NavCard from "@site/src/shared/ui/nav-card/tmpl.mdx" +import { StarOutlined, SearchOutlined, TeamOutlined, VerifiedOutlined } from "@ant-design/icons"; + + + + + + diff --git a/i18n/kr/docusaurus-plugin-content-docs/community/team.mdx b/i18n/kr/docusaurus-plugin-content-docs/community/team.mdx new file mode 100644 index 0000000000..24ebc84ba9 --- /dev/null +++ b/i18n/kr/docusaurus-plugin-content-docs/community/team.mdx @@ -0,0 +1,18 @@ +--- +sidebar_class_name: sidebar-item--wip +sidebar_position: 2 +--- + +import WIP from '@site/src/shared/ui/wip/tmpl.mdx' + +# 팀 소개 + + + +## 코어 팀 + +### 챔피언 + +## 기여자 + +## 협력 기업 From de27f36148fbf32147a7d815edf0a7cd03746c8c Mon Sep 17 00:00:00 2001 From: Yaroslav Gulnazaryan <43448610+frontend-sensei@users.noreply.github.com> Date: Mon, 25 Nov 2024 03:00:10 +0300 Subject: [PATCH 22/29] docs: change usersAdapter to artistAdapter (#763) * docs: change usersAdapter to artistAdapter * docs: fix incorrect adapter usage in multiple language docs --- .../current/guides/examples/types.md | 2 +- .../current/guides/examples/types.md | 4 ++-- .../current/guides/examples/types.md | 2 +- .../current/guides/examples/types.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/types.md b/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/types.md index cd6390be4b..78e3748c6b 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/types.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/examples/types.md @@ -305,7 +305,7 @@ export const slice = createSlice({ extraReducers: (builder) => { builder.addCase(fetchSong.fulfilled, (state, action) => { // And handle the same fetch result by inserting the artists here - usersAdapter.upsertMany(state, action.payload.users) + artistAdapter.upsertMany(state, action.payload.artists) }) }, }) diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md index d0111f68b1..e76320af1f 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/types.md @@ -309,7 +309,7 @@ export const slice = createSlice({ extraReducers: (builder) => { builder.addCase(fetchSong.fulfilled, (state, action) => { // ここでバックエンドからの同じレスポンスを処理し、ユーザーを追加します - usersAdapter.upsertMany(state, action.payload.users) + artistAdapter.upsertMany(state, action.payload.artists) }) }, }) @@ -433,4 +433,4 @@ declare module "use-react-screenshot"; [ext-type-fest]: https://github.com/sindresorhus/type-fest [ext-zod]: https://zod.dev [ext-vite]: https://vitejs.dev -[ext-ts-reset]: https://www.totaltypescript.com/ts-reset \ No newline at end of file +[ext-ts-reset]: https://www.totaltypescript.com/ts-reset diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md index 505f150c8e..5b07e91060 100644 --- a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md +++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md @@ -308,7 +308,7 @@ export const slice = createSlice({ extraReducers: (builder) => { builder.addCase(fetchSong.fulfilled, (state, action) => { // 같은 fetch 결과를 처리하며, 여기서 artists를 삽입합니다. - usersAdapter.upsertMany(state, action.payload.users) + artistAdapter.upsertMany(state, action.payload.artists) }) }, }) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/types.md b/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/types.md index c00ae7fe90..5108e959e3 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/types.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/examples/types.md @@ -307,7 +307,7 @@ export const slice = createSlice({ extraReducers: (builder) => { builder.addCase(fetchSong.fulfilled, (state, action) => { // И здесь обрабатываем тот же ответ с бэкенда, добавляя исполнителей - usersAdapter.upsertMany(state, action.payload.users) + artistAdapter.upsertMany(state, action.payload.artists) }) }, }) From 76f4f189afc848af095e77962cf38d110e9e7061 Mon Sep 17 00:00:00 2001 From: Lev Chelyadinov Date: Tue, 3 Dec 2024 22:46:59 +0100 Subject: [PATCH 23/29] fix: replace the leftover "experimental"-ness of `@x` (#771) --- .../current/guides/tech/with-react-query.mdx | 5 +++-- .../current/guides/tech/with-react-query.mdx | 3 ++- .../current/guides/tech/with-react-query.mdx | 6 +++--- .../current/guides/tech/with-react-query.mdx | 4 +++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx index 1bb64f57f3..88931cfa3f 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx @@ -34,8 +34,7 @@ the purest division will be by entity. In this case, we suggest using the follow ``` If there are connections between the entities (for example, the Country entity has a field-list of City entities), -then you can use an [experimental approach to organized cross-imports -via @x-notation](https://github.com/feature-sliced/documentation/discussions/390#discussioncomment-5570073) or consider the alternative solution below. +then you can use the [public API for cross-imports][public-api-for-cross-imports] or consider the alternative solution below. ### Alternative solution — keep it in shared @@ -433,3 +432,5 @@ export const apiClient = new ApiClient(API_URL); - [(GitHub) Sample Project](https://github.com/ruslan4432013/fsd-react-query-example) - [(CodeSandbox) Sample Project](https://codesandbox.io/p/github/ruslan4432013/fsd-react-query-example/main) - [About the query factory](https://tkdodo.eu/blog/the-query-options-api) + +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx index 4eabab8afc..991666764a 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx @@ -34,7 +34,7 @@ sidebar_position: 10 ... # ``` -もしエンティティ間に関係がある場合(例えば、「国」のエンティティに「都市」のエンティティ一覧フィールドがある場合)、`@x` アノテーションを使用した組織的なクロスインポートの[実験的アプローチ](https://github.com/feature-sliced/documentation/discussions/390#discussioncomment-5570073)を利用するか、以下の代替案を検討できます。 +もしエンティティ間に関係がある場合(例えば、「国」のエンティティに「都市」のエンティティ一覧フィールドがある場合)、`@x` アノテーションを使用した組織的なクロスインポートの[クロスインポート用のパブリックAPI][public-api-for-cross-imports]を利用するか、以下の代替案を検討できます。 ### 代替案 — クエリを公開で保存する @@ -432,3 +432,4 @@ export const apiClient = new ApiClient(API_URL); - [The Query Options API](https://tkdodo.eu/blog/the-query-options-api) +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx b/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx index 280c254a95..0c3e01e3cf 100644 --- a/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx +++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx @@ -1,7 +1,7 @@ --- sidebar_position: 10 --- -# React Query와 함께 사용하기 +# React Query와 함께 사용하기 ## “키를 어디에 두어야 하는가” 문제 @@ -33,7 +33,7 @@ sidebar_position: 10 ... # ``` -만약 엔티티 간에 연결이 필요한 경우 (예: Country 엔티티에 City 엔티티 필드가 포함되는 경우), [@x-notation을 활용한 교차 임포트 방식](https://github.com/feature-sliced/documentation/discussions/390#discussioncomment-5570073)을 사용하거나 대안으로 아래의 구조를 고려할 수 있습니다. +만약 엔티티 간에 연결이 필요한 경우 (예: Country 엔티티에 City 엔티티 필드가 포함되는 경우), [교차 가져오기를 위한 공개 API][public-api-for-cross-imports]을 사용하거나 대안으로 아래의 구조를 고려할 수 있습니다. ### 대안 방안 — shared에 유지하기 @@ -422,4 +422,4 @@ export const apiClient = new ApiClient(API_URL); - [(CodeSandbox) 샘플 프로젝트](https://codesandbox.io/p/github/ruslan4432013/fsd-react-query-example/main) - [쿼리 팩토리에 대하여](https://tkdodo.eu/blog/the-query-options-api) - +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx index ea8e25032d..db40bcd655 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-react-query.mdx @@ -35,7 +35,7 @@ sidebar_position: 10 ``` Если среди сущностей есть связи (например, у сущности Страна есть поле-список сущностей Город), то можно воспользоваться -[экспериментальным подходом к организованным кросс-импортам через @x-нотацию](https://github.com/feature-sliced/documentation/discussions/390#discussioncomment-5570073) или рассмотреть альтернативное решение ниже. +[публичным API для кросс-импортов][public-api-for-cross-imports] или рассмотреть альтернативное решение ниже. ### Альтернативное решение — хранить запросы в общем доступе. @@ -432,3 +432,5 @@ export const apiClient = new ApiClient(API_URL); - [(GitHub) Пример проекта](https://github.com/ruslan4432013/fsd-react-query-example) - [(CodeSandbox) Пример проекта](https://codesandbox.io/p/github/ruslan4432013/fsd-react-query-example/main) - [О фабрике запросов](https://tkdodo.eu/blog/the-query-options-api) + +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports From a1985eef91adc26ce13b81ed7588d8322af4415b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=89=E3=81=A8=E3=81=BF=E3=82=8B?= <166593964+ratomiru@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:41:48 +0900 Subject: [PATCH 24/29] =?UTF-8?q?feat(=E7=BF=BB=E8=A8=B3):=20FSD=202.1=20(?= =?UTF-8?q?#773)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../current/get-started/tutorial.md | 2 +- .../current/guides/examples/auth.md | 2 +- .../current/guides/migration/from-custom.md | 2 +- .../current/guides/migration/from-v1.md | 4 +- .../current/guides/migration/from-v2-0.md | 45 ++++ .../current/guides/tech/with-nuxtjs.mdx | 2 +- .../current/guides/tech/with-sveltekit.mdx | 4 +- .../current/reference/index.mdx | 2 +- .../reference/isolation/_category_.yaml | 1 - .../reference/isolation/coupling-cohesion.md | 146 ---------- .../reference/isolation/decouple-entities.mdx | 21 -- .../current/reference/isolation/index.md | 61 ----- .../current/reference/layers.mdx | 190 ++++++------- .../current/reference/public-api.md | 249 +++++++----------- .../current/reference/slices-segments.mdx | 68 +++-- 15 files changed, 272 insertions(+), 527 deletions(-) create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md delete mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/_category_.yaml delete mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/coupling-cohesion.md delete mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/decouple-entities.mdx delete mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/reference/isolation/index.md diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md index 46ef4b4e92..8c18e275f1 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/get-started/tutorial.md @@ -39,7 +39,7 @@ sidebar_position: 2 Feature-Sliced Designの特徴は、ページが互いに依存できないことです。つまり、1つのページが他のページのコードをインポートすることはできません。これは**層のインポートルール**によって禁じられています。 -*スライス内のモジュールは、下層にあるスライスのみをインポートできる。* +*スライス内のモジュール(ファイル)は、下層にあるスライスのみをインポートできる。* この場合、ページはスライスであるため、そのページ内のモジュール(ファイル)は、他のページではなく、下層からのみコードをインポートできます。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md index 264a970c26..a35f108866 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/examples/auth.md @@ -192,7 +192,7 @@ FSDプロジェクトには、ユーザーエンティティや現在のユー APIクライアントは通常、`shared/api`に配置されるか、エンティティ間で分散されるため、このアプローチの主な問題は、他のリクエストがトークンにアクセスできるようにしつつ、[レイヤーのインポートルール][import-rule-on-layers]を破らないことです。 -> スライス内のモジュールは、下層にあるスライスのみをインポートできる。 +> スライス内のモジュール(ファイル)は、下層にあるスライスのみをインポートできる。 この問題にはいくつかの解決策があります。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md index 94b6a2e3bb..c0a0f2e9e2 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 1 sidebar_label: カスタムアーキテクチャからの移行 --- diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md index d6003f47d2..282faaecdc 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v1.md @@ -1,8 +1,8 @@ --- -sidebar_position: 4 +sidebar_position: 2 --- -# v1からの移行 +# v1からv2への移行 ## なぜv2なのか? {#why-v2} diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md new file mode 100644 index 0000000000..a29c7f7d2f --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/migration/from-v2-0.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 3 +--- + +# v2.0からv2.1への移行 + +v2.1の主な変更点は、インターフェースを分解するための「ページファースト」という新しいメンタルモデルです。 + +v2.0では、FSDは分解のためにエンティティ表現やインタラクティビティの最小部分まで考慮し、インターフェース内のエンティティとフィーチャーを特定することを推奨していました。そうしてから、エンティティとフィーチャーからウィジェットやページが構築されていきました。この分解モデルでは、ほとんどのロジックはエンティティとフィーチャーにあり、ページはそれ自体にはあまり重要性のない構成層に過ぎませんでした。 + +v2.1では、分解をページから始めること、または場合によってはページで止めることを推奨します。ほとんどの人はすでにアプリを個々のページに分ける方法を知っており、ページはコードベース内のコンポーネントを見つける際の一般的な出発点でもあります。この新しい分解モデルでは、各個別のページにほとんどのUIとロジックを保持し、Sharedに再利用可能な基盤を維持します。複数のページでビジネスロジックを再利用する必要が生じた場合は、それを下層のレイヤーに移動できます。 + +Feature-Sliced Designへのもう一つの追加は、`@x`表記を使用したエンティティ間のクロスインポートの標準化です。 + +## 移行方法 {#how-to-migrate} + +v2.1には破壊的な変更はなく、FSD v2.0で書かれたプロジェクトもFSD v2.1の有効なプロジェクトです。しかし、新しいメンタルモデルがチームや特に新しい開発者のオンボーディングにとってより有益であると考えているため、分解に対して小さな調整を行うことを推奨します。 + +### スライスのマージ + +移行を始めるための簡単な方法は、プロジェクトでFSDのリンターである[Steiger][steiger]を実行することです。Steigerは新しいメンタルモデルで構築されており、最も役立つルールは次のとおりです。 + +- [`insignificant-slice`][insignificant-slice] — エンティティ、またはフィーチャーが1ページでのみ使用されている場合、このルールはそのエンティティ、またはフィーチャーをページに完全にマージすることを提案します。 +- [`excessive-slicing`][excessive-slicing] — レイヤーにスライスが多すぎる場合、通常は分解が細かすぎるサインです。このルールは、プロジェクトのナビゲーションを助けるためにいくつかのスライスをマージ、またはグループ化することを提案します。 + +```bash +npx steiger src +``` + +これにより、1回だけ使用されるスライスを特定できるため、それらが本当に必要か再考することができます。そのような考慮において、レイヤーはその内部のすべてのスライスのための何らかのグローバル名前空間を形成することを念頭に置いてください。1回だけ使用される変数でグローバル名前空間を汚染しないようにするのと同様に、レイヤーの名前空間内の場所を貴重なものとして扱い、慎重に使用するべきです。 + +### クロスインポートの標準化 + +以前にプロジェクト内でクロスインポートがあった場合、Feature-Sliced Designでのクロスインポートのための新しい表記法`@x`を活用できます。これは次のようになります。 + +```ts title="entities/B/some/file.ts" +import type { EntityA } from "entities/A/@x/B"; +``` + +詳細については、リファレンスの[クロスインポートの公開API][public-api-for-cross-imports]セクションを参照してください。 + +[insignificant-slice]: https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/insignificant-slice +[steiger]: https://github.com/feature-sliced/steiger +[excessive-slicing]: https://github.com/feature-sliced/steiger/tree/master/packages/steiger-plugin-fsd/src/excessive-slicing +[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx index a0b7de7e16..f3ec6eacb1 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-nuxtjs.mdx @@ -111,7 +111,7 @@ export default defineNuxtConfig({ 例えば、プロジェクトに`Home`ページを追加するには、次の手順を行います。 - `pages`層内にページスライスを追加する - `app`層内に適切なルートを追加する -- スライスのページとルートを統合する +- スライスのページをルートに接続する ページスライスを作成するには、[CLI](https://github.com/feature-sliced/cli)を使用します。 ```shell diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx index c7b450db92..17460fac88 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx +++ b/i18n/ja/docusaurus-plugin-content-docs/current/guides/tech/with-sveltekit.mdx @@ -62,7 +62,7 @@ fsd pages home `ui`セグメント内に`home-page.svelte`ファイルを作成し、公開APIを介してアクセスできるようにします。  ```ts title="src/pages/home/index.ts" -export { default as HomePage } from './ui/home-page'; +export { default as HomePage } from './ui/home-page.svelte'; ``` このページのルートを`app`層内に作成します。 @@ -81,7 +81,7 @@ export { default as HomePage } from './ui/home-page'; │ │ │ ├── index.ts ``` -最後に`index.svelte`ファイル内にページコンポーネントを追加します。 +最後に`+page.svelte`ファイル内にページコンポーネントを追加します。 ```html title="src/app/routes/+page.svelte"