From 79bbfe93096c4cb66f86a669bf48b2eeae113e0b Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Tue, 9 Apr 2024 04:51:40 +0200 Subject: [PATCH] Initial Version --- LICENSE | 674 +++++ README.md | 117 +- main.ts | 597 ++++- manifest.json | 14 +- package-lock.json | 2229 +++++++++++++++++ package.json | 2 +- src/components/CustomSettingsTab.ts | 184 ++ src/components/NormalModal.ts | 192 ++ src/components/SelectionModal.ts | 291 +++ src/components/dialogs/BasicDialog.ts | 74 + src/components/dialogs/MissingAPIKeyDialog.ts | 69 + src/components/dialogs/QuotaExceededDialog.ts | 74 + src/components/dialogs/SettingsDialog.ts | 178 ++ src/models/CustomResponse.ts | 19 + src/utils/constants.ts | 5 + src/utils/languages.ts | 193 ++ src/utils/utils.ts | 16 + styles.css | 630 ++++- tsconfig.json | 4 +- 19 files changed, 5381 insertions(+), 181 deletions(-) create mode 100644 LICENSE create mode 100644 package-lock.json create mode 100644 src/components/CustomSettingsTab.ts create mode 100644 src/components/NormalModal.ts create mode 100644 src/components/SelectionModal.ts create mode 100644 src/components/dialogs/BasicDialog.ts create mode 100644 src/components/dialogs/MissingAPIKeyDialog.ts create mode 100644 src/components/dialogs/QuotaExceededDialog.ts create mode 100644 src/components/dialogs/SettingsDialog.ts create mode 100644 src/models/CustomResponse.ts create mode 100644 src/utils/constants.ts create mode 100644 src/utils/languages.ts create mode 100644 src/utils/utils.ts diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a5eae15 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + + Preamble + +The GNU General Public License is a free, copyleft license for +software and other kinds of works. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + +Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + +Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + +Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + +0. Definitions. + +"This License" refers to version 3 of the GNU General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +1. Source Code. + +The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + +The Corresponding Source for a work in source code form is that +same work. + +2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + +4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + +8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + +13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + +14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + +You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + +The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index bb0348e..bdfcea5 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,71 @@ -# Obsidian Sample Plugin +# About the Rapid AI Plugin -This is a sample plugin for Obsidian (https://obsidian.md). +Elevate your productivity with an AI assistant that enables rapid content generation, integrates selected text actions, provides keyboard shortcuts, and offers quick-action buttons, all accessible from various workspace points. -This project uses Typescript to provide type checking and documentation. -The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does. +- Instant AI assistant for generating content +- Selected Text Integration: Quickly perform any AI action on selected text. +- Keyboard Shortcuts and quick action buttons +- Access the AI assistant from anywhere in your vault, sidebar, status bar, context menu, and command line. +- High availability API to provide unlimited request rates for an efficient workflow. -**Note:** The Obsidian API is still in early alpha and is subject to change at any time! +# Screenshots and Examples -This sample plugin demonstrates some of the basic functionality the plugin API can do. -- Adds a ribbon icon, which shows a Notice when clicked. -- Adds a command "Open Sample Modal" which opens a Modal. -- Adds a plugin setting tab to the settings page. -- Registers a global click event and output 'click' to the console. -- Registers a global interval which logs 'setInterval' to the console. +![https://i.imgur.com/RoHc7Mu.png](https://i.imgur.com/RoHc7Mu.png) -## First time developing plugins? +![https://i.imgur.com/TDEi0sj.png](https://i.imgur.com/TDEi0sj.png) -Quick starting guide for new plugin devs: +![https://i.imgur.com/oEWAe78.png](https://i.imgur.com/oEWAe78.png) -- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with. -- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it). -- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder. -- Install NodeJS, then run `npm i` in the command line under your repo folder. -- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`. -- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`. -- Reload Obsidian to load the new version of your plugin. -- Enable plugin in settings window. -- For updates to the Obsidian API run `npm update` in the command line under your repo folder. +![https://i.imgur.com/g8EioS3.png](https://i.imgur.com/g8EioS3.png) -## Releasing new releases +![https://i.imgur.com/pUjg0ad.png](https://i.imgur.com/pUjg0ad.png) -- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release. -- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible. -- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases -- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release. -- Publish the release. +![https://i.imgur.com/F4PgE0E.png](https://i.imgur.com/F4PgE0E.png) -> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`. -> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json` +![https://i.imgur.com/H6P71cc.png](https://i.imgur.com/H6P71cc.png) -## Adding your plugin to the community plugin list +## Correct Grammar Quick Action Button Example -- Check https://github.com/obsidianmd/obsidian-releases/blob/master/plugin-review.md -- Publish an initial version. -- Make sure you have a `README.md` file in the root of your repo. -- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin. +[![Correct Grammar Quick Action Button Example](https://img.youtube.com/vi/xwSSV1A5d9Y/0.jpg)](https://www.youtube.com/watch?v=xwSSV1A5d9Y) -## How to use +## Translate Quick Action Button Example -- Clone this repo. -- Make sure your NodeJS is at least v16 (`node --version`). -- `npm i` or `yarn` to install dependencies. -- `npm run dev` to start compilation in watch mode. +[![Translate Quick Action Button Example](https://img.youtube.com/vi/oMhOQRrGOG0/0.jpg)](https://www.youtube.com/watch?v=oMhOQRrGOG0) -## Manually installing the plugin +## Generate Diagrams Example -- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`. +[![Generate Diagrams Example](https://img.youtube.com/vi/ShilXnCGjxQ/0.jpg)](https://www.youtube.com/watch?v=ShilXnCGjxQ) -## Improve code quality with eslint (optional) -- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code. -- To use eslint with this project, make sure to install eslint from terminal: - - `npm install -g eslint` -- To use eslint to analyze this project use this command: - - `eslint main.ts` - - eslint will then create a report with suggestions for code improvement by file and line number. -- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder: - - `eslint .\src\` +## Adjust Python Code Example -## Funding URL +[![Adjust Python Code Example](https://img.youtube.com/vi/fSWkXwvg3d0/0.jpg)](https://www.youtube.com/watch?v=fSWkXwvg3d0) -You can include funding URLs where people who use your plugin can financially support it. +# How to Get an API Key -The simple way is to set the `fundingUrl` field to your link in your `manifest.json` file: +This plugin uses an API called 'Obsidian AI API.' To obtain an API key, follow these steps: -```json -{ - "fundingUrl": "https://buymeacoffee.com" -} -``` +- Subscribe to the API [from here](https://rapidapi.com/obsidian-api-obsidian-api-default/api/obsidian-ai). +- Copy the API key from the `X-RapidAPI-Key` field. +- Navigate to the plugin settings and paste the API key into the `API Key` textbox. -If you have multiple URLs, you can also do: +You can test the API key by clicking on the “Test Key” button on the plugin settings page. Now you are ready to use the plugin. -```json -{ - "fundingUrl": { - "Buy Me a Coffee": "https://buymeacoffee.com", - "GitHub Sponsor": "https://github.com/sponsors", - "Patreon": "https://www.patreon.com/" - } -} -``` +You can also watch this tutorial. -## API Documentation +[https://youtu.be/tp3O40bBqs0](https://youtu.be/tp3O40bBqs0) -See https://github.com/obsidianmd/obsidian-api +# How to Change Shortcuts + +You can add and change shortcuts for showing the AI assistant by following these steps: + +- Navigate to settings. +- Access the "Community plugins" section. +- Locate the Rapid AI plugin under the "Installed Plugins" section. +- Click on the plus button representing hotkey settings. +- Modify or reset the shortcut according to your preference. + +![https://i.imgur.com/Ew5249d.png](https://i.imgur.com/Ew5249d.png) + +You can watch this tutorial video. + +[https://youtu.be/N8SG263By2Y](https://youtu.be/N8SG263By2Y) diff --git a/main.ts b/main.ts index 2d07212..0f3896b 100644 --- a/main.ts +++ b/main.ts @@ -1,134 +1,541 @@ -import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian'; +import { + MarkdownView, + Modal, + moment, + Notice, + Plugin, + requestUrl, + setIcon, +} from "obsidian"; -// Remember to rename these classes and interfaces! +import { SelectionModal } from "src/components/SelectionModal"; +import { NormalModal } from "src/components/NormalModal"; +import { CustomResponse, Status } from "src/models/CustomResponse"; +import { CustomSettingsTab } from "src/components/CustomSettingsTab"; +import { SettingsDialog } from "src/components/dialogs/SettingsDialog"; +import { BasicDialog } from "src/components/dialogs/BasicDialog"; +import { MissingAPIKeyDialog } from "src/components/dialogs/MissingAPIKeyDialog"; +import { API_PRICING_URL, API_URL } from "src/utils/constants"; +import { QuotaExceededDialog } from "src/components/dialogs/QuotaExceededDialog"; -interface MyPluginSettings { - mySetting: string; +interface PluginSettings { + rapidAPIKey: string; + translateTo: string; } -const DEFAULT_SETTINGS: MyPluginSettings = { - mySetting: 'default' -} +const DEFAULT_SETTINGS: Partial = { + rapidAPIKey: "", + translateTo: "English", +}; -export default class MyPlugin extends Plugin { - settings: MyPluginSettings; +async function makeAIRequest( + apiKey: string, + sentence: string, + selectedText?: string, + systemInstructions?: string +): Promise { + if (apiKey.trim() == "") { + return new CustomResponse(Status.EmptyAPIKey, ""); + } + const url = "https://obsidian-ai.p.rapidapi.com/"; + const headers = { + "Content-Type": "application/json", + "X-RapidAPI-Key": apiKey, + }; + const targetMessages = []; + const straighforward = + "Give direct answer. Do not include any explanation or any accompanying text"; + if (selectedText) { + let instruction; + if (systemInstructions) { + instruction = `${systemInstructions}. Today is ${moment().format( + "YYYY-MM-DD dddd" + )}, local time is ${moment().format( + "HH:mm:ss" + )}. ${straighforward}`; + targetMessages.push( + { role: "system", content: instruction }, + { role: "user", content: `${selectedText}` } + ); + } else { + instruction = `The first message is the selected text by the user. You are a helpful AI assistant for markdown editor. Today is ${moment().format( + "YYYY-MM-DD dddd" + )}, local time is ${moment().format( + "HH:mm:ss" + )}. ${straighforward}`; + targetMessages.push( + { role: "system", content: instruction }, + { role: "user", content: `${selectedText}` }, + { role: "user", content: sentence } + ); + } + } else { + const instruction = `Today is ${moment().format( + "YYYY-MM-DD" + )}, local time is ${moment().format("HH:mm:ss")}. ${straighforward}`; + targetMessages.push( + { role: "system", content: instruction }, + { role: "user", content: sentence } + ); + } - async onload() { - await this.loadSettings(); + const body = { + model: "gpt-3.5-turbo", + prompts: targetMessages, + }; - // This creates an icon in the left ribbon. - const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => { - // Called when the user clicks the icon. - new Notice('This is a notice!'); + try { + const response = await requestUrl({ + url: url, + method: "POST", + body: JSON.stringify(body), + headers: headers, }); - // Perform additional things with the ribbon - ribbonIconEl.addClass('my-plugin-ribbon-class'); + const responseBody = response.json; + const content = responseBody.choices[0]?.message?.content; + return new CustomResponse(Status.Success, content); + } catch (e) { + const errorMessage: string = e.toString().toLowerCase(); + console.log(errorMessage); + switch (true) { + case errorMessage.includes("disconnected"): + return new CustomResponse(Status.InternetDisconnected, ""); + case errorMessage.includes("429"): + return new CustomResponse(Status.ExceededQuota, ""); + case errorMessage.includes("403"): + return new CustomResponse(Status.UserUnsubscribed, ""); + default: + return new CustomResponse(Status.UnknownError, ""); + } + } +} - // This adds a status bar item to the bottom of the app. Does not work on mobile apps. - const statusBarItemEl = this.addStatusBarItem(); - statusBarItemEl.setText('Status Bar Text'); +async function invokeKey(apiKey: string): Promise { + if (apiKey.trim() == "") { + return new CustomResponse(Status.EmptyAPIKey, ""); + } + const url = "https://obsidian-ai.p.rapidapi.com/"; + const headers = { + "Content-Type": "application/json", + "X-RapidAPI-Key": apiKey, + }; - // This adds a simple command that can be triggered anywhere - this.addCommand({ - id: 'open-sample-modal-simple', - name: 'Open sample modal (simple)', - callback: () => { - new SampleModal(this.app).open(); - } + const body = { + invokeKey: true, + }; + + try { + const response = await requestUrl({ + url: url, + method: "POST", + body: JSON.stringify(body), + headers: headers, }); - // This adds an editor command that can perform some operation on the current editor instance - this.addCommand({ - id: 'sample-editor-command', - name: 'Sample editor command', - editorCallback: (editor: Editor, view: MarkdownView) => { - console.log(editor.getSelection()); - editor.replaceSelection('Sample Editor Command'); + const responseBody = response.json; + if (responseBody.valid && responseBody.valid == true) { + return new CustomResponse(Status.Success, ""); + } else { + return new CustomResponse(Status.InvalidAPIKey, ""); + } + } catch (e) { + const errorMessage: string = e.toString().toLowerCase(); + switch (true) { + case errorMessage.includes("disconnected"): + return new CustomResponse(Status.InternetDisconnected, ""); + case errorMessage.includes("429"): + return new CustomResponse(Status.ExceededQuota, ""); + case errorMessage.includes("403"): + return new CustomResponse(Status.UserUnsubscribed, ""); + default: + return new CustomResponse(Status.InvalidAPIKey, ""); + } + } +} + +export default class RapidAIPlugin extends Plugin { + settings: PluginSettings; + settingsTab: CustomSettingsTab; + async loadSettings() { + this.settings = Object.assign( + {}, + DEFAULT_SETTINGS, + await this.loadData() + ); + } + + async copyText(text: string) { + try { + await navigator.clipboard.writeText(text); + } catch (error) { + new Notice("An error occurred while copying"); + } + } + + async insertText(text: string) { + try { + const view = this.app.workspace.getActiveViewOfType(MarkdownView); + if (view) { + view.editor.replaceRange(text, view.editor.getCursor()); } - }); - // This adds a complex command that can check whether the current state of the app allows execution of the command - this.addCommand({ - id: 'open-sample-modal-complex', - name: 'Open sample modal (complex)', - checkCallback: (checking: boolean) => { - // Conditions to check - const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView); - if (markdownView) { - // If checking is true, we're simply "checking" if the command can be run. - // If checking is false, then we want to actually perform the operation. - if (!checking) { - new SampleModal(this.app).open(); - } - - // This command will only show up in Command Palette when the check function returns true - return true; - } + } catch (error) { + new Notice("An error occurred while inserting text"); + } + } + + getSelectedText() { + try { + const view = this.app.workspace.getActiveViewOfType(MarkdownView); + const selection = view?.editor.getSelection(); + return selection; + } catch (e) { + return ""; + } + } + + replaceSelectedText(text: string) { + try { + const view = this.app.workspace.getActiveViewOfType(MarkdownView); + if (view) { + view.editor.replaceSelection(text); } - }); + } catch (error) { + new Notice("An error occurred while replacing text"); + } + } - // This adds a settings tab so the user can configure various aspects of the plugin - this.addSettingTab(new SampleSettingTab(this.app, this)); + async saveSettings() { + await this.saveData(this.settings); + } - // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin) - // Using this function will automatically remove the event listener when this plugin is disabled. - this.registerDomEvent(document, 'click', (evt: MouseEvent) => { - console.log('click', evt); + showSettingsDialog() { + const dialog: SettingsDialog = new SettingsDialog(this.app, { + currentAPIKey: this.settings.rapidAPIKey, + currentTranslateTo: this.settings.translateTo, + onTestKeyClick: (key: string) => this.onTestKeyClick(dialog, key), + onAPIKeyChange: (key: string) => this.onAPIKeyChange(key), + onlanguageChange: (langauge: string) => + this.onlanguageChange(langauge), }); + dialog.open(); + } - // When registering intervals, this function will automatically clear the interval when the plugin is disabled. - this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000)); + showMissingAPIKey() { + const dialog = new MissingAPIKeyDialog(this.app, { + apiLink: API_URL, + onGoToSettingsClick: () => { + this.showSettingsDialog(); + dialog.close(); + }, + }); + dialog.open(); } - onunload() { + showNoSubscriptionModal() { + const dialog = new BasicDialog(this.app, { + title: "No subscription found", + subtitle: + "You need to subscribe to the API first. You can subscribe from here.", + action: "Subscribe", + onActionButtonClick: () => { + window.open(API_URL, "_blank"); + dialog.close(); + }, + }); + dialog.open(); + } + showQuotaExceeded() { + const dialog = new QuotaExceededDialog(this.app, { + onUpgradeButtonClick: () => { + window.open(API_PRICING_URL, "_blank"); + dialog.close(); + }, + }); + dialog.open(); } - async loadSettings() { - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + showInvalidAPIKey() { + const dialog = new BasicDialog(this.app, { + title: "Invalid API key", + subtitle: + "Please use a valid API key. You can change it from the settings.", + action: "Go to Settings", + onActionButtonClick: () => { + this.showSettingsDialog(); + dialog.close(); + }, + }); + dialog.open(); } - async saveSettings() { - await this.saveData(this.settings); + requestFailed(modal: Modal, result: CustomResponse) { + if (modal instanceof NormalModal) { + modal.setLoading(false); + } else if (modal instanceof SelectionModal) { + modal.setLoading(false); + } + switch (result.status) { + case Status.InternetDisconnected: + new Notice("Please connect to the internet."); + break; + case Status.ExceededQuota: + this.showQuotaExceeded(); + break; + case Status.UserUnsubscribed: + this.showNoSubscriptionModal(); + break; + case Status.EmptyAPIKey: + this.showMissingAPIKey(); + break; + case Status.InvalidAPIKey: + this.showInvalidAPIKey(); + break; + case Status.UnknownError: + new Notice("An Error Occurred. Please try again later"); + break; + case Status.EmptyPrompt: + new Notice("Please enter the prompt"); + break; + } } -} -class SampleModal extends Modal { - constructor(app: App) { - super(app); + emptyPrompt() { + new Notice("Please the prompt"); + } + + openNormalModal() { + const modal = new NormalModal(this.app, { + onSendButtonClick: async () => { + const prompt = modal.getUserPrompt(); + if (prompt.trim() == "") { + this.emptyPrompt(); + return; + } + modal.hideOutputPanel(); + modal.setLoading(true); + + const result = await makeAIRequest( + this.settings.rapidAPIKey, + prompt + ); + if (result.status == Status.Success) { + modal.setOutputText(result.body); + modal.setLoading(false); + modal.showOutputPanel(); + } else { + this.requestFailed(modal, result); + } + }, + onCopyButtonClick: () => { + this.copyText(modal.getOutputText()); + new Notice("Copied"); + }, + onInsertButtonClick: () => { + this.insertText(modal.getOutputText()); + modal.close(); + }, + }); + modal.open(); + modal.hideOutputPanel(); } - onOpen() { - const {contentEl} = this; - contentEl.setText('Woah!'); + openSelectionModal(selectedText: string, translationLanguage: string) { + const modal = new SelectionModal(this.app, selectedText, { + onSendButtonClick: async () => { + const prompt = modal.getUserPrompt(); + if (prompt.trim() == "") { + this.emptyPrompt(); + return; + } + modal.setOutputVisibility(false); + modal.setLoading(true); + + const result = await makeAIRequest( + this.settings.rapidAPIKey, + prompt, + this.getSelectedText() + ); + if (result.status == Status.Success) { + modal.setOutputText(result.body); + modal.setLoading(false); + modal.setOutputVisibility(true); + } else { + this.requestFailed(modal, result); + } + }, + onCopyButtonClick: () => { + this.copyText(modal.getOutputText()); + new Notice("Copied"); + }, + onInsertButtonClick: () => { + this.replaceSelectedText(modal.getOutputText()); + modal.close(); + }, + onCorrectGrammarClick: async () => { + await quickAction(modal, "You are an a grammar corrector"); + }, + onFormatClick: async () => { + await quickAction(modal, "You are an markdown formatter"); + }, + onTranslateClick: async () => { + await quickAction( + modal, + `You are an ${translationLanguage} translator` + ); + }, + }); + modal.open(); + modal.setOutputVisibility(false); + + const quickAction = async (modal: SelectionModal, action: string) => { + modal.setOutputVisibility(false); + modal.setInputTextVisiblity(false); + modal.setLoading(true); + + const prompt = modal.getUserPrompt(); + + const result = await makeAIRequest( + this.settings.rapidAPIKey, + prompt, + this.getSelectedText(), + action + ); + if (result.status == Status.Success) { + modal.setOutputText(result.body); + modal.setOutputVisibility(true); + } else { + this.requestFailed(modal, result); + modal.setOutputVisibility(false); + } + modal.setLoading(false); + + modal.setInputTextVisiblity(true); + }; } - onClose() { - const {contentEl} = this; - contentEl.empty(); + openModal() { + const selectedText = this.getSelectedText(); + if (selectedText) { + const language = this.settings.translateTo; + this.openSelectionModal(selectedText, language); + } else { + this.openNormalModal(); + } + } + async onAPIKeyChange(key: string) { + this.settings.rapidAPIKey = key; + await this.saveSettings(); } -} -class SampleSettingTab extends PluginSettingTab { - plugin: MyPlugin; + async onTestKeyClick(dialog: object, key: string) { + if (dialog instanceof CustomSettingsTab) { + dialog.setLoadingState(true); + dialog.setStatusVisiblity(false); + } else if (dialog instanceof SettingsDialog) { + dialog.setLoadingState(true); + dialog.setStatusVisiblity(false); + } + + const result = await invokeKey(key); + const setStatus = (dialog: unknown, status: string, icon: string) => { + if (dialog instanceof CustomSettingsTab) { + dialog.setTestStatus(status, icon); + } else if (dialog instanceof SettingsDialog) { + dialog.setTestStatus(status, icon); + } + }; + switch (result.status) { + case Status.Success: + setStatus(dialog, "It Works Perfctly", "badge-check"); + break; + case Status.InternetDisconnected: + setStatus(dialog, "Internet Disconnected", "unplug"); + break; + case Status.ExceededQuota: + setStatus( + dialog, + "Your quota has exceeded the current plan. Please upgrade your plan", + "shield-alert" + ); + break; + case Status.InvalidAPIKey: + setStatus(dialog, "Invalid API Key", "ban"); + break; + case Status.UserUnsubscribed: + setStatus( + dialog, + "You are not subscribed to the API", + "shield-alert" + ); + break; + case Status.EmptyAPIKey: + setStatus(dialog, "Missing API Key", "key-round"); + break; + default: + setStatus(dialog, "Invalid API Key", "ban"); + break; + } + + if (dialog instanceof CustomSettingsTab) { + dialog.setStatusVisiblity(true); + dialog.setLoadingState(false); + } else if (dialog instanceof SettingsDialog) { + dialog.setStatusVisiblity(true); + dialog.setLoadingState(false); + } + } - constructor(app: App, plugin: MyPlugin) { - super(app, plugin); - this.plugin = plugin; + async onlanguageChange(langauge: string) { + this.settings.translateTo = langauge; + await this.saveSettings(); } + async onload() { + // Settings + await this.loadSettings(); + this.settingsTab = new CustomSettingsTab(this.app, this, { + onAPIKeyChange: async (key) => this.onAPIKeyChange(key), + onTestKeyClick: async (key) => + this.onTestKeyClick(this.settingsTab, key), + onlanguageChange: async (langauge) => + this.onlanguageChange(langauge), + }); + this.addSettingTab(this.settingsTab); - display(): void { - const {containerEl} = this; + // Side Bar Button + this.addRibbonIcon("cpu", "Rapid AI", () => { + this.openModal(); + }); - containerEl.empty(); + // Status Bar Button + const item = this.addStatusBarItem(); + item.createEl("button"); + setIcon(item, "cpu"); + // item.style.color = "#FFCA28"; + item.addEventListener("click", () => { + this.openModal(); + }); - new Setting(containerEl) - .setName('Setting #1') - .setDesc('It\'s a secret') - .addText(text => text - .setPlaceholder('Enter your secret') - .setValue(this.plugin.settings.mySetting) - .onChange(async (value) => { - this.plugin.settings.mySetting = value; - await this.plugin.saveSettings(); - })); + // Context Menu Item + this.registerEvent( + this.app.workspace.on("editor-menu", (menu, editor, view) => { + menu.addItem((item) => { + item.setTitle("Ask AI") + .setIcon("cpu") + .onClick(async () => { + this.openModal(); + }); + }); + }) + ); + + // Command Pallete + this.addCommand({ + id: "ask-ai", + name: "Ask AI", + hotkeys: [], + callback: () => { + this.openModal(); + }, + }); } } diff --git a/manifest.json b/manifest.json index dfa940e..46f4678 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,11 @@ { - "id": "sample-plugin", - "name": "Sample Plugin", + "id": "rapid-ai", + "name": "Rapid AI", "version": "1.0.0", "minAppVersion": "0.15.0", - "description": "Demonstrates some of the capabilities of the Obsidian API.", - "author": "Obsidian", - "authorUrl": "https://obsidian.md", - "fundingUrl": "https://obsidian.md/pricing", + "description": "AI Assistant for selected text and generating content with Markdown. Shortcuts and quick action buttons provide instant AI assistance. It provides a high availability API for unlimited Chat GPT request rates, so you can ensure smooth work for any workload.", + "author": "Rapid AI", + "authorUrl": "https://rapidapi.com/organization/obsidian-api", + "fundingUrl": "https://rapidapi.com/obsidian-api-obsidian-api-default/api/obsidian-ai/pricing", "isDesktopOnly": false -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..660e050 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2229 @@ +{ + "name": "obsidian-sample-plugin", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "obsidian-sample-plugin", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@types/node": "^16.11.6", + "@typescript-eslint/eslint-plugin": "5.29.0", + "@typescript-eslint/parser": "5.29.0", + "builtin-modules": "3.3.0", + "esbuild": "0.17.3", + "obsidian": "latest", + "tslib": "2.4.0", + "typescript": "4.7.4" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==", + "dev": true, + "peer": true + }, + "node_modules/@codemirror/view": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.1.tgz", + "integrity": "sha512-wLw0t3R9AwOSQThdZ5Onw8QQtem5asE7+bPlnzc57eubPqiuJKIzwjMZ+C42vQett+iva+J8VgFV4RYWDBh5FA==", + "dev": true, + "peer": true, + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz", + "integrity": "sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.3.tgz", + "integrity": "sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.3.tgz", + "integrity": "sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.3.tgz", + "integrity": "sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.3.tgz", + "integrity": "sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.3.tgz", + "integrity": "sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.3.tgz", + "integrity": "sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.3.tgz", + "integrity": "sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.3.tgz", + "integrity": "sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.3.tgz", + "integrity": "sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.3.tgz", + "integrity": "sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.3.tgz", + "integrity": "sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.3.tgz", + "integrity": "sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.3.tgz", + "integrity": "sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.3.tgz", + "integrity": "sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.3.tgz", + "integrity": "sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.3.tgz", + "integrity": "sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.3.tgz", + "integrity": "sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.3.tgz", + "integrity": "sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.3.tgz", + "integrity": "sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.3.tgz", + "integrity": "sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.3.tgz", + "integrity": "sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "peer": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true, + "peer": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/codemirror": { + "version": "5.60.8", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz", + "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==", + "dev": true, + "dependencies": { + "@types/tern": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.18.95", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.95.tgz", + "integrity": "sha512-z9w+CcR7ahc7UhsKe+PGB25nmPmCERQBAdLdFHhoZ6+FfgSr7gUvdQI0eLH2t7ue8u5wKsLdde6cHKPjhC8vGg==", + "dev": true + }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz", + "integrity": "sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/type-utils": "5.29.0", + "@typescript-eslint/utils": "5.29.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.29.0.tgz", + "integrity": "sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/typescript-estree": "5.29.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.29.0.tgz", + "integrity": "sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/visitor-keys": "5.29.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.29.0.tgz", + "integrity": "sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.29.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.29.0.tgz", + "integrity": "sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.29.0.tgz", + "integrity": "sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/visitor-keys": "5.29.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.29.0.tgz", + "integrity": "sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/typescript-estree": "5.29.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.29.0.tgz", + "integrity": "sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "peer": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "peer": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/esbuild": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz", + "integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.3", + "@esbuild/android-arm64": "0.17.3", + "@esbuild/android-x64": "0.17.3", + "@esbuild/darwin-arm64": "0.17.3", + "@esbuild/darwin-x64": "0.17.3", + "@esbuild/freebsd-arm64": "0.17.3", + "@esbuild/freebsd-x64": "0.17.3", + "@esbuild/linux-arm": "0.17.3", + "@esbuild/linux-arm64": "0.17.3", + "@esbuild/linux-ia32": "0.17.3", + "@esbuild/linux-loong64": "0.17.3", + "@esbuild/linux-mips64el": "0.17.3", + "@esbuild/linux-ppc64": "0.17.3", + "@esbuild/linux-riscv64": "0.17.3", + "@esbuild/linux-s390x": "0.17.3", + "@esbuild/linux-x64": "0.17.3", + "@esbuild/netbsd-x64": "0.17.3", + "@esbuild/openbsd-x64": "0.17.3", + "@esbuild/sunos-x64": "0.17.3", + "@esbuild/win32-arm64": "0.17.3", + "@esbuild/win32-ia32": "0.17.3", + "@esbuild/win32-x64": "0.17.3" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "peer": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "peer": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "peer": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "peer": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "peer": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "peer": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "peer": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "peer": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, + "node_modules/obsidian": { + "version": "1.5.7-1", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.5.7-1.tgz", + "integrity": "sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==", + "dev": true, + "dependencies": { + "@types/codemirror": "5.60.8", + "moment": "2.29.4" + }, + "peerDependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "peer": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "peer": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "dev": true, + "peer": true + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "dev": true, + "peer": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "peer": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index 6a00766..345113e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "keywords": [], "author": "", - "license": "MIT", + "license": "MIT", "devDependencies": { "@types/node": "^16.11.6", "@typescript-eslint/eslint-plugin": "5.29.0", diff --git a/src/components/CustomSettingsTab.ts b/src/components/CustomSettingsTab.ts new file mode 100644 index 0000000..ec3206a --- /dev/null +++ b/src/components/CustomSettingsTab.ts @@ -0,0 +1,184 @@ +import RapidAIPlugin from "main"; +import { + PluginSettingTab, + App, + setIcon, + Setting, + DropdownComponent, +} from "obsidian"; +import { API_MANAGEMENT_URL, API_URL } from "src/utils/constants"; +import { langauges } from "src/utils/languages"; +import { getBadge } from "src/utils/utils"; + +export class CustomSettingsTab extends PluginSettingTab { + private plugin: RapidAIPlugin; + + private testKeyButton: HTMLButtonElement; + private APIKeyTextbox: HTMLInputElement; + + private onTestKeyClick: (key: string) => void; + private onAPIKeyChange: (key: string) => void; + private onLanguageChange: (language: string) => void; + private txtTestStatus: HTMLSpanElement; + private iconTestStatus: HTMLSpanElement; + private divTestState: HTMLDivElement; + private TestButtonContent = "Test API Key"; + + constructor( + app: App, + plugin: RapidAIPlugin, + { + onTestKeyClick, + onAPIKeyChange, + onlanguageChange, + }: { + onTestKeyClick: (key: string) => void; + onAPIKeyChange: (key: string) => void; + onlanguageChange: (langauge: string) => void; + } + ) { + super(app, plugin); + this.plugin = plugin; + this.onTestKeyClick = onTestKeyClick; + this.onAPIKeyChange = onAPIKeyChange; + this.onLanguageChange = onlanguageChange; + } + + setTestStatus(status: string, icon: string) { + this.txtTestStatus.innerText = status; + setIcon(this.iconTestStatus, icon); + } + + setStatusVisiblity(isVisible: boolean) { + if (isVisible) { + this.divTestState.style.display = "flex"; + } else { + this.divTestState.style.display = "none"; + } + } + + setLoadingState(isLoading: boolean) { + if (isLoading) { + this.testKeyButton.setText("Sending ..."); + } else { + this.testKeyButton.setText(this.TestButtonContent); + } + } + + private createSettingsDiv(): HTMLDivElement { + const divMain = document.createElement("div"); + divMain.addClass("settings-tab-main-div"); + + const titleText = document.createElement("h4"); + titleText.addClass("settings-tab-title"); + titleText.innerText = "Rapid API Key"; + divMain.appendChild(titleText); + + const input_divTextBox = document.createElement("div"); + input_divTextBox.addClass("settings-tab-key-div"); + divMain.appendChild(input_divTextBox); + + this.APIKeyTextbox = document.createElement("input"); + this.APIKeyTextbox.addClass("settings-tab-key-textbox"); + this.APIKeyTextbox.value = this.plugin.settings.rapidAPIKey; + input_divTextBox.appendChild(this.APIKeyTextbox); + this.APIKeyTextbox.addEventListener("input", (event) => { + this.onAPIKeyChange(this.APIKeyTextbox.value); + }); + + const divTestKey = document.createElement("div"); + divTestKey.addClass("settings-tab-test-key-div"); + divMain.appendChild(divTestKey); + + this.testKeyButton = document.createElement("button"); + this.testKeyButton.addClass("settings-tab-test-key-button"); + this.testKeyButton.setText(this.TestButtonContent); + this.testKeyButton.addEventListener("click", () => { + this.onTestKeyClick(this.APIKeyTextbox.value); + }); + divTestKey.appendChild(this.testKeyButton); + + this.divTestState = document.createElement("div"); + this.divTestState.addClass("settings-tab-key-state-div"); + divTestKey.appendChild(this.divTestState); + + this.iconTestStatus = document.createElement("span"); + this.iconTestStatus.addClass("settings-tab-key-state-icon"); + setIcon(this.iconTestStatus, "badge-check"); + this.divTestState.appendChild(this.iconTestStatus); + + this.txtTestStatus = document.createElement("span"); + this.txtTestStatus.addClass("settings-tab-state-text"); + this.txtTestStatus.innerText = "It Works Perfctly"; + this.divTestState.appendChild(this.txtTestStatus); + + const anchorElement = document.createElement("a"); + anchorElement.addClass("settings-tab-api-link"); + anchorElement.href = API_URL; + anchorElement.text = "Get your API key from here"; + anchorElement.target = "_blank"; + divMain.appendChild(anchorElement); + + const badge = getBadge(140); + badge.addClass("settings-tab-badge"); + divMain.appendChild(badge); + + const manageSubscription = this.createManageSubscription(); + divMain.appendChild(manageSubscription); + + const hr = document.createElement("hr"); + hr.addClass("settings-tab-hr"); + divMain.appendChild(hr); + + const languageDiv = this.createLanguageDiv(); + divMain.appendChild(languageDiv); + + return divMain; + } + + private createManageSubscription() { + const manageSubscription = document.createElement("a"); + manageSubscription.addClass("settings-tab-manage-subscription"); + manageSubscription.href = API_MANAGEMENT_URL; + manageSubscription.text = "Check Usage & Manage Subscription"; + manageSubscription.target = "_blank"; + return manageSubscription; + } + + private createLanguageDiv(): HTMLDivElement { + const divMain = document.createElement("div"); + divMain.addClass("settings-tab-language-div"); + + const txtTitle = document.createElement("h4"); + txtTitle.addClass("settings-tab-langauge-title"); + txtTitle.innerText = "Translation"; + divMain.appendChild(txtTitle); + + const divSubtitle = document.createElement("div"); + divSubtitle.addClass("settings-tab-language-subtiitle-div"); + divMain.appendChild(divSubtitle); + + const txtSubtitle = document.createElement("p"); + txtSubtitle.addClass("settings-tab-language-subtitle"); + txtSubtitle.innerText = "Translate to"; + divSubtitle.appendChild(txtSubtitle); + + const dropDown = new DropdownComponent(divSubtitle); + dropDown.selectEl.addClass("settings-tab-language-dropdown"); + + for (const [language] of langauges) { + dropDown.addOption(language, language); + } + dropDown.onChange((value) => this.onLanguageChange(value)); + dropDown.setValue(this.plugin.settings.translateTo); + + return divMain; + } + + display(): void { + const { containerEl } = this; + containerEl.empty(); + containerEl.appendChild(this.createSettingsDiv()); + new Setting(containerEl); + } +} diff --git a/src/components/NormalModal.ts b/src/components/NormalModal.ts new file mode 100644 index 0000000..d42d534 --- /dev/null +++ b/src/components/NormalModal.ts @@ -0,0 +1,192 @@ +import { App, Modal, setIcon } from "obsidian"; + +export class NormalModal extends Modal { + private sendButton: HTMLButtonElement; + private insertButton: HTMLButtonElement; + private copyButton: HTMLElement; + + private inputTextBox: HTMLTextAreaElement; + private outputTextBox: HTMLTextAreaElement; + private outputDiv: HTMLDivElement; + + private onSendButtonClick: () => void; + private onCopyButtonClick: () => void; + private onInsertButtonClick: () => void; + + constructor( + app: App, + { + onSendButtonClick, + onCopyButtonClick, + onInsertButtonClick, + }: { + onSendButtonClick: () => void; + onCopyButtonClick: () => void; + onInsertButtonClick: () => void; + } + ) { + super(app); + this.onSendButtonClick = onSendButtonClick; + this.onCopyButtonClick = onCopyButtonClick; + this.onInsertButtonClick = onInsertButtonClick; + } + + hideOutputPanel() { + this.outputDiv.style.display = "none"; + } + showOutputPanel() { + this.outputDiv.style.display = "flex"; + } + + setOutputText(text: string) { + this.outputTextBox.setText(text); + } + + setLoading(isLoading: boolean) { + if (isLoading) { + this.sendButton.innerText = "Processing ..."; + } else { + this.sendButton.innerText = "Send Message"; + } + this.inputTextBox.readOnly = isLoading; + } + + getUserPrompt(): string { + return this.inputTextBox.value; + } + + getOutputText(): string { + return this.outputTextBox.value; + } + + setOutputVisibility(isVisible: boolean) { + if (isVisible) { + this.outputDiv.style.display = "flex"; + } else { + this.outputDiv.style.display = "none"; + } + } + + createInputPanel(): HTMLDivElement { + const divInput = document.createElement("div"); + divInput.addClass("normal-modal-main-div"); + + const input_divTitle = document.createElement("div"); + input_divTitle.addClass("normal-modal-input-title-div"); + setIcon(input_divTitle, "cpu"); + + const input_titleText = document.createElement("h4"); + input_titleText.addClass("normal-modal-input-title-text"); + input_titleText.innerText = "Ask Al"; + input_divTitle.appendChild(input_titleText); + divInput.appendChild(input_divTitle); + + const input_divTextBox = document.createElement("div"); + input_divTextBox.addClass("normal-modal-input-textbox-div"); + divInput.appendChild(input_divTextBox); + + this.inputTextBox = document.createElement("textarea"); + this.inputTextBox.addClass("normal-modal-input-textbox"); + this.inputTextBox.placeholder = "Ask AI anything"; + this.inputTextBox.addEventListener("keydown", async (event) => { + if (event.ctrlKey && event.key === "Enter") { + event.preventDefault(); + this.onSendButtonClick(); + } + }); + input_divTextBox.appendChild(this.inputTextBox); + + const input_divTip = document.createElement("div"); + input_divTip.addClass("normal-modal-input-tip-div"); + input_divTextBox.appendChild(input_divTip); + + const input_tipStarter = document.createElement("span"); + input_tipStarter.innerText = "Ctrl +"; + input_divTip.appendChild(input_tipStarter); + + const input_tipIcon = document.createElement("span"); + input_tipIcon.addClass("normal-modal-input-tip-icon"); + setIcon(input_tipIcon, "wrap-text"); + input_divTip.appendChild(input_tipIcon); + + const input_tipEnding = document.createElement("span"); + input_tipEnding.innerText = "to send"; + input_divTip.appendChild(input_tipEnding); + + this.sendButton = document.createElement("button"); + this.sendButton.addClass("normal-modal-input-send-button"); + this.sendButton.innerText = "Send Message"; + this.sendButton.addEventListener("click", this.onSendButtonClick); + divInput.appendChild(this.sendButton); + + return divInput; + } + + createOutputDiv(): HTMLDivElement { + this.outputDiv = document.createElement("div"); + this.outputDiv.addClass("normal-modal-output-main-div"); + + const titleText = document.createElement("h4"); + titleText.addClass("normal-modal-output-title"); + titleText.innerText = "Output"; + this.outputDiv.appendChild(titleText); + + const divTextBox = document.createElement("div"); + divTextBox.addClass("normal-modal-output-textbox-div"); + this.outputDiv.appendChild(divTextBox); + + this.outputTextBox = document.createElement("textarea"); + this.outputTextBox.addClass("normal-modal-output-textbox"); + this.outputTextBox.readOnly = true; + divTextBox.appendChild(this.outputTextBox); + + this.copyButton = document.createElement("span"); + this.copyButton.addClass("copy-icon-button"); + this.copyButton.addClass("normal-modal-copy-button"); + setIcon(this.copyButton, "copy"); + this.copyButton.addEventListener("click", this.onCopyButtonClick); + divTextBox.appendChild(this.copyButton); + + this.insertButton = document.createElement("button"); + this.insertButton.addClass("normal-modal-output-insert-button"); + this.insertButton.addEventListener("click", this.onInsertButtonClick); + this.outputDiv.appendChild(this.insertButton); + + const divButtonContent = document.createElement("div"); + divButtonContent.addClass("normal-modal-output-insert-button-div"); + this.insertButton.appendChild(divButtonContent); + + const submitIcon = document.createElement("span"); + submitIcon.addClass("normal-modal-ouput-submit-icon"); + setIcon(submitIcon, "check-circle-2"); + divButtonContent.appendChild(submitIcon); + + const submitText = document.createElement("span"); + submitText.addClass("normal-modal-ouput-submit-text"); + submitText.setText("Submit on Editor"); + divButtonContent.appendChild(submitText); + + return this.outputDiv; + } + + onOpen() { + const { contentEl } = this; + const divContainer = contentEl.createEl("div"); + divContainer.style.display = "flex"; + divContainer.style.flexDirection = "column"; + divContainer.style.alignItems = "stretch"; + + const inputDiv = this.createInputPanel(); + divContainer.appendChild(inputDiv); + + const outputDiv = this.createOutputDiv(); + divContainer.appendChild(outputDiv); + + this.setOutputVisibility(false); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/components/SelectionModal.ts b/src/components/SelectionModal.ts new file mode 100644 index 0000000..d12984d --- /dev/null +++ b/src/components/SelectionModal.ts @@ -0,0 +1,291 @@ +import { App, Modal, setIcon } from "obsidian"; + +export class SelectionModal extends Modal { + private sendButton: HTMLButtonElement; + private insertButton: HTMLButtonElement; + private copyButton: HTMLElement; + + private inputDiv: HTMLDivElement; + private outputDiv: HTMLDivElement; + + private inputTextBox: HTMLTextAreaElement; + private outputTextBox: HTMLTextAreaElement; + + private correctGrammarButton: HTMLButtonElement; + private translateButton: HTMLButtonElement; + private formatButton: HTMLButtonElement; + + private selectedText: string; + + private onSendButtonClick: () => void; + private onCopyButtonClick: () => void; + private onInsertButtonClick: () => void; + + private onCorrectGrammarClick: () => void; + private onTranslateClick: () => void; + private onFormatClick: () => void; + + constructor( + app: App, + selectedText: string, + { + onSendButtonClick, + onCopyButtonClick, + onInsertButtonClick, + onCorrectGrammarClick, + onTranslateClick, + onFormatClick, + }: { + onSendButtonClick: () => void; + onCopyButtonClick: () => void; + onInsertButtonClick: () => void; + onCorrectGrammarClick: () => void; + onTranslateClick: () => void; + onFormatClick: () => void; + } + ) { + super(app); + this.selectedText = selectedText; + this.onSendButtonClick = onSendButtonClick; + this.onCopyButtonClick = onCopyButtonClick; + this.onInsertButtonClick = onInsertButtonClick; + this.onCorrectGrammarClick = onCorrectGrammarClick; + this.onTranslateClick = onTranslateClick; + this.onFormatClick = onFormatClick; + } + + setOutputText(text: string) { + this.outputTextBox.setText(text); + } + + setInputTextVisiblity(isVisible: boolean) { + if (isVisible) { + this.inputTextBox.style.display = "flex"; + } else { + this.inputTextBox.style.display = "none"; + } + } + + setLoading(isLoading: boolean) { + if (isLoading) { + this.sendButton.innerText = "Processing ..."; + } else { + this.sendButton.innerText = "Send Message"; + } + this.inputTextBox.readOnly = isLoading; + + this.correctGrammarButton.disabled = isLoading; + this.translateButton.disabled = isLoading; + this.formatButton.disabled = isLoading; + } + + setOutputVisibility(isVisible: boolean) { + if (isVisible) { + this.outputDiv.style.display = "flex"; + } else { + this.outputDiv.style.display = "none"; + } + } + + getUserPrompt(): string { + return this.inputTextBox.value; + } + + getOutputText(): string { + return this.outputTextBox.value; + } + + createInputPanel(): HTMLDivElement { + this.inputDiv = document.createElement("div"); + this.inputDiv.addClass("selection-modal-input-main-div"); + + const input_divTitle = document.createElement("div"); + input_divTitle.addClass("selection-modal-input-title-div"); + setIcon(input_divTitle, "text-select"); + this.inputDiv.appendChild(input_divTitle); + + const input_titleText = document.createElement("h4"); + input_titleText.addClass("selection-modal-input-title"); + input_titleText.innerText = "Selected Text"; + input_divTitle.appendChild(input_titleText); + + const input_divSelectedText = document.createElement("div"); + input_divSelectedText.dir = "auto"; + input_divSelectedText.addClass( + "selection-modal-input-selected-text-div" + ); + input_divSelectedText.setText(this.selectedText); + this.inputDiv.appendChild(input_divSelectedText); + + const input_divTextBox = document.createElement("div"); + input_divTextBox.addClass("selection-modal-input-textbox-div"); + this.inputDiv.appendChild(input_divTextBox); + + const divActions = document.createElement("div"); + divActions.addClass("selection-modal-input-actions-div"); + this.inputDiv.appendChild(divActions); + + this.correctGrammarButton = createIconButton( + "Correct Grammar", + "spell-check", + this.onCorrectGrammarClick + ); + divActions.appendChild(this.correctGrammarButton); + + this.translateButton = createIconButton( + "Translate", + "languages", + this.onTranslateClick + ); + this.translateButton.addClass("selection-modal-input-translate-button"); + divActions.appendChild(this.translateButton); + + this.formatButton = createIconButton( + "Fromat", + "align-center", + this.onFormatClick + ); + this.formatButton.addClass("selection-modal-input-format-button"); + divActions.appendChild(this.formatButton); + + this.inputTextBox = document.createElement("textarea"); + this.inputTextBox.addClass("selection-modal-input-textbox"); + this.inputTextBox.dir = "auto"; + this.inputTextBox.placeholder = "Ask AI anything"; + this.inputTextBox.rows = 1; + input_divTextBox.appendChild(this.inputTextBox); + + this.sendButton = document.createElement("button"); + this.sendButton.innerText = "Send Message"; + this.sendButton.addClass("selection-modal-send-button"); + this.sendButton.addEventListener("click", this.onSendButtonClick); + this.inputDiv.appendChild(this.sendButton); + return this.inputDiv; + } + + createOutputDiv(): HTMLDivElement { + this.outputDiv = document.createElement("div"); + this.outputDiv.addClass("selection-modal-output-main-div"); + + const titleText = document.createElement("h4"); + titleText.addClass("selection-modal-output-title"); + titleText.innerText = "Output"; + this.outputDiv.appendChild(titleText); + + const divTextBox = document.createElement("div"); + divTextBox.addClass("selection-modal-output-textbox-div"); + this.outputDiv.appendChild(divTextBox); + + this.outputTextBox = document.createElement("textarea"); + this.outputTextBox.addClass("selection-modal-output-textbox"); + this.outputTextBox.dir = "auto"; + + this.outputTextBox.readOnly = true; + divTextBox.appendChild(this.outputTextBox); + + this.copyButton = document.createElement("span"); + this.copyButton.addClass("copy-icon-button"); + this.copyButton.addClass("selection-modal-output-copy-button"); + setIcon(this.copyButton, "copy"); + this.copyButton.addEventListener("click", this.onCopyButtonClick); + divTextBox.appendChild(this.copyButton); + + this.insertButton = document.createElement("button"); + this.insertButton.addClass("selection-modal-output-insert-button"); + this.insertButton.addEventListener("click", this.onInsertButtonClick); + this.outputDiv.appendChild(this.insertButton); + + const submitIcon = document.createElement("span"); + submitIcon.addClass("selection-modal-output-insert-icon"); + setIcon(submitIcon, "check-circle-2"); + this.insertButton.appendChild(submitIcon); + + const submitText = document.createElement("span"); + submitText.addClass("selection-modal-output-insert-text"); + submitText.setText("Replace selection"); + this.insertButton.appendChild(submitText); + + return this.outputDiv; + } + + createTipDiv(): HTMLElement { + const input_divTip = document.createElement("div"); + input_divTip.style.display = "flex"; + input_divTip.style.flexDirection = "row"; + input_divTip.style.marginTop = "18px"; + input_divTip.style.alignItems = "start"; + input_divTip.style.marginLeft = "auto"; + + const input_tipIcon = document.createElement("span"); + input_tipIcon.addClass("selection-modal-output-tip-icon"); + input_tipIcon.setText("↩"); + input_divTip.appendChild(input_tipIcon); + + const input_tipEnding = document.createElement("span"); + input_tipEnding.innerText = "to Send"; + input_divTip.appendChild(input_tipEnding); + return input_divTip; + } + + onOpen() { + const { contentEl } = this; + const divContainer = contentEl.createEl("div"); + divContainer.style.display = "flex"; + divContainer.style.flexDirection = "column"; + divContainer.style.alignItems = "stretch"; + + const inputDiv = this.createInputPanel(); + divContainer.appendChild(inputDiv); + + const outputDiv = this.createOutputDiv(); + divContainer.appendChild(outputDiv); + + this.inputTextBox.addEventListener("keydown", async (event) => { + if (event.key === "Enter" && !event.shiftKey) { + event.preventDefault(); + this.onSendButtonClick(); + } + this.inputTextBox.rows = + this.inputTextBox.value.split("\n").length || 1; + }); + + this.inputTextBox.addEventListener("keyup", async (event) => { + this.inputTextBox.rows = + this.inputTextBox.value.split("\n").length || 1; + }); + + this.inputTextBox.addEventListener("keypress", async (event) => { + this.inputTextBox.rows = + this.inputTextBox.value.split("\n").length || 1; + }); + + this.setOutputVisibility(false); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} + +function createIconButton( + title: string, + icon: string, + onPress: () => void +): HTMLButtonElement { + const insertButton = document.createElement("button"); + insertButton.addClass("selection-modal-icon-button"); + insertButton.addEventListener("click", onPress); + + const submitIcon = document.createElement("span"); + submitIcon.addClass("selection-modal-icon-button-icon"); + setIcon(submitIcon, icon); + insertButton.appendChild(submitIcon); + + const submitText = document.createElement("span"); + submitText.addClass("selection-modal-icon-button-text"); + submitText.setText(title); + insertButton.appendChild(submitText); + + return insertButton; +} diff --git a/src/components/dialogs/BasicDialog.ts b/src/components/dialogs/BasicDialog.ts new file mode 100644 index 0000000..851bf7b --- /dev/null +++ b/src/components/dialogs/BasicDialog.ts @@ -0,0 +1,74 @@ +import { App, Modal } from "obsidian"; +import { getBadge } from "src/utils/utils"; + +export class BasicDialog extends Modal { + private actionButton: HTMLButtonElement; + + private title: string; + private subtitle: string; + private action: string; + private onActionButtonClick: () => void; + constructor( + app: App, + { + title, + subtitle, + action, + onActionButtonClick, + }: { + title: string; + subtitle: string; + action: string; + onActionButtonClick: () => void; + } + ) { + super(app); + this.title = title; + this.subtitle = subtitle; + this.action = action; + this.onActionButtonClick = onActionButtonClick; + } + + createInputPanel(): HTMLDivElement { + const divMain = document.createElement("div"); + divMain.addClass("basic-dialog-main-div"); + + const txtTitle = document.createElement("h4"); + txtTitle.addClass("basic-dialog-main-title"); + txtTitle.innerText = this.title; + divMain.appendChild(txtTitle); + + const txtSubtitle = document.createElement("p"); + txtSubtitle.innerText = this.subtitle; + txtSubtitle.addClass("basic-dialog-main-subtitle"); + divMain.appendChild(txtSubtitle); + + this.actionButton = document.createElement("button"); + this.actionButton.innerText = this.action; + this.actionButton.tabIndex = -1; + this.actionButton.addClass("basic-dialog-action-button"); + this.actionButton.addEventListener("click", this.onActionButtonClick); + divMain.appendChild(this.actionButton); + + const badge = getBadge(120); + badge.addClass("basic-dialog-badge"); + divMain.appendChild(badge); + return divMain; + } + + onOpen() { + const { contentEl } = this; + const divContainer = contentEl.createEl("div"); + divContainer.style.display = "flex"; + divContainer.style.flexDirection = "column"; + divContainer.style.alignItems = "stretch"; + + const inputDiv = this.createInputPanel(); + divContainer.appendChild(inputDiv); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/components/dialogs/MissingAPIKeyDialog.ts b/src/components/dialogs/MissingAPIKeyDialog.ts new file mode 100644 index 0000000..2b00d93 --- /dev/null +++ b/src/components/dialogs/MissingAPIKeyDialog.ts @@ -0,0 +1,69 @@ +import { App, Modal } from "obsidian"; +import { getBadge } from "src/utils/utils"; + +export class MissingAPIKeyDialog extends Modal { + private actionButton: HTMLButtonElement; + + private apiLink: string; + private onGoToSettingsClick: () => void; + constructor( + app: App, + { + apiLink, + onGoToSettingsClick, + }: { + apiLink: string; + onGoToSettingsClick: () => void; + } + ) { + super(app); + this.apiLink = apiLink; + this.onGoToSettingsClick = onGoToSettingsClick; + } + + createInputPanel(): HTMLDivElement { + const divMain = document.createElement("div"); + divMain.addClass("missing-key-dialog-main-div"); + + const txtTitle = document.createElement("h3"); + txtTitle.innerText = "Missing API Key"; + txtTitle.addClass("missing-key-dialog-title"); + divMain.appendChild(txtTitle); + + const hrefSubtitle = document.createElement("a"); + hrefSubtitle.href = this.apiLink; + hrefSubtitle.text = "You can obtain an API key from here"; + hrefSubtitle.target = "_blank"; + divMain.appendChild(hrefSubtitle); + + const badge = getBadge(120); + badge.addClass("missing-key-dialog-badge"); + divMain.appendChild(badge); + + const txtSettingsTip = document.createElement("p"); + txtSettingsTip.addClass("missing-key-dialog-tip-text"); + txtSettingsTip.innerText = + "After you get the API key, connect it from the settings plugin."; + divMain.appendChild(txtSettingsTip); + + this.actionButton = document.createElement("button"); + this.actionButton.innerText = "Go to Settings"; + this.actionButton.addClass("missing-key-dialog-action-button"); + this.actionButton.addEventListener("click", this.onGoToSettingsClick); + divMain.appendChild(this.actionButton); + return divMain; + } + + onOpen() { + const { contentEl } = this; + const divContainer = contentEl.createEl("div"); + divContainer.addClass("missing-key-dialog-main-container"); + const inputDiv = this.createInputPanel(); + divContainer.appendChild(inputDiv); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/components/dialogs/QuotaExceededDialog.ts b/src/components/dialogs/QuotaExceededDialog.ts new file mode 100644 index 0000000..0d546d5 --- /dev/null +++ b/src/components/dialogs/QuotaExceededDialog.ts @@ -0,0 +1,74 @@ +import { App, Modal } from "obsidian"; +import { API_MANAGEMENT_URL, API_PRICING_URL } from "src/utils/constants"; +import { getBadge } from "src/utils/utils"; + +export class QuotaExceededDialog extends Modal { + private upgradeButton: HTMLButtonElement; + + private onUpgradeButtonClick: () => void; + constructor( + app: App, + { + onUpgradeButtonClick: onUpgradeButtonClick, + }: { + onUpgradeButtonClick: () => void; + } + ) { + super(app); + this.onUpgradeButtonClick = onUpgradeButtonClick; + } + + createInputPanel(): HTMLDivElement { + const divMain = document.createElement("div"); + divMain.addClass("quota-exceeded-dialog-main-div"); + + const txtTitle = document.createElement("h4"); + txtTitle.addClass("quota-exceeded-dialog-title"); + txtTitle.innerText = "Plan Quota Limit Reached"; + divMain.appendChild(txtTitle); + + const divRow = document.createElement("div"); + divMain.appendChild(divRow); + + const txtSubtitle = document.createElement("span"); + txtSubtitle.addClass("quota-exceeded-dialog-subtitle"); + txtSubtitle.setText( + "It seems your plan has reached its quota limit. Consider upgrading to a higher plan. " + ); + + divRow.appendChild(txtSubtitle); + + const manageSubscription = document.createElement("a"); + manageSubscription.href = API_MANAGEMENT_URL; + manageSubscription.text = "Check Usage & Manage Subscription"; + manageSubscription.target = "_blank"; + manageSubscription.addClass( + "quota-exceeded-dialog-manage-subscription-link" + ); + divRow.appendChild(manageSubscription); + + this.upgradeButton = document.createElement("button"); + this.upgradeButton.innerText = "Upgrade Plan"; + this.upgradeButton.addClass("quota-exceeded-dialog-upgrade-button"); + this.upgradeButton.addEventListener("click", this.onUpgradeButtonClick); + divMain.appendChild(this.upgradeButton); + + const badge = getBadge(120, API_PRICING_URL); + badge.addClass("quota-exceeded-dialog-badge"); + divMain.appendChild(badge); + return divMain; + } + + onOpen() { + const { contentEl } = this; + const divContainer = contentEl.createEl("div"); + divContainer.addClass("quota-exceeded-dialog-container"); + const inputDiv = this.createInputPanel(); + divContainer.appendChild(inputDiv); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/components/dialogs/SettingsDialog.ts b/src/components/dialogs/SettingsDialog.ts new file mode 100644 index 0000000..ae0f96c --- /dev/null +++ b/src/components/dialogs/SettingsDialog.ts @@ -0,0 +1,178 @@ +import { App, DropdownComponent, Modal, setIcon } from "obsidian"; +import { API_URL, API_MANAGEMENT_URL } from "src/utils/constants"; +import { langauges } from "src/utils/languages"; +import { getBadge } from "src/utils/utils"; + +export class SettingsDialog extends Modal { + private testKeyButton: HTMLButtonElement; + private APIKeyTextbox: HTMLInputElement; + private currentAPIKey: string; + private currentTranslateTo: string; + + private onTestKeyClick: (key: string) => void; + private onAPIKeyChange: (key: string) => void; + private onLanguageChange: (language: string) => void; + private txtTestResult: HTMLSpanElement; + private iconTestResult: HTMLSpanElement; + private divTestResult: HTMLDivElement; + private TestButtonContent = "Test API Key"; + constructor( + app: App, + { + currentAPIKey, + currentTranslateTo, + onTestKeyClick, + onAPIKeyChange, + onlanguageChange, + }: { + currentAPIKey: string; + currentTranslateTo: string; + onTestKeyClick: (key: string) => void; + onAPIKeyChange: (key: string) => void; + onlanguageChange: (langauge: string) => void; + } + ) { + super(app); + this.currentAPIKey = currentAPIKey; + this.currentTranslateTo = currentTranslateTo; + this.onTestKeyClick = onTestKeyClick; + this.onAPIKeyChange = onAPIKeyChange; + this.onLanguageChange = onlanguageChange; + } + + setTestStatus(status: string, icon: string) { + this.txtTestResult.innerText = status; + setIcon(this.iconTestResult, icon); + } + + setStatusVisiblity(isVisible: boolean) { + if (isVisible) { + this.divTestResult.style.display = "flex"; + } else { + this.divTestResult.style.display = "none"; + } + } + + setLoadingState(isLoading: boolean) { + if (isLoading) { + this.testKeyButton.setText("Sending ..."); + } else { + this.testKeyButton.setText(this.TestButtonContent); + } + } + + private createSettingsDiv(): HTMLDivElement { + const divMain = document.createElement("div"); + divMain.addClass("settings-dialog-main-div"); + + const titleText = document.createElement("h4"); + titleText.innerText = "Rapid API Key"; + titleText.addClass("settings-dialog-title"); + divMain.appendChild(titleText); + + const divAPIKey = document.createElement("div"); + divAPIKey.addClass("settings-dialog-api-key-div"); + divMain.appendChild(divAPIKey); + + this.APIKeyTextbox = document.createElement("input"); + this.APIKeyTextbox.value = this.currentAPIKey; + this.APIKeyTextbox.addClass("settings-dialog-api-textbox"); + divAPIKey.appendChild(this.APIKeyTextbox); + this.APIKeyTextbox.addEventListener("input", (event) => { + this.onAPIKeyChange(this.APIKeyTextbox.value); + }); + + const divTest = document.createElement("div"); + divTest.addClass("settings-dialog-test-div"); + divMain.appendChild(divTest); + + this.testKeyButton = document.createElement("button"); + this.testKeyButton.addClass("settings-dialog-test-key-button"); + this.testKeyButton.setText(this.TestButtonContent); + this.testKeyButton.addEventListener("click", () => { + this.onTestKeyClick(this.APIKeyTextbox.value); + }); + divTest.appendChild(this.testKeyButton); + this.divTestResult = document.createElement("div"); + this.divTestResult.addClass("settings-dialog-test-result-div"); + divTest.appendChild(this.divTestResult); + + this.iconTestResult = document.createElement("span"); + setIcon(this.iconTestResult, "badge-check"); + this.iconTestResult.addClass("settings-dialog-test-result-icon"); + this.divTestResult.appendChild(this.iconTestResult); + + this.txtTestResult = document.createElement("span"); + this.txtTestResult.addClass("settings-dialog-test-result-text"); + this.txtTestResult.innerText = "It Works Perfctly"; + this.divTestResult.appendChild(this.txtTestResult); + + const anchorElement = document.createElement("a"); + anchorElement.href = API_URL; + anchorElement.text = "Get your API key from here"; + anchorElement.addClass("settings-dialog-anchor"); + anchorElement.target = "_blank"; + divMain.appendChild(anchorElement); + + const badge = getBadge(140); + badge.addClass("settings-dialog-badge"); + divMain.appendChild(badge); + + const manageSubscription = document.createElement("a"); + manageSubscription.href = API_MANAGEMENT_URL; + manageSubscription.text = "Check Usage & Manage Subscription"; + manageSubscription.addClass("settings-dialog-manage-subscription"); + manageSubscription.target = "_blank"; + divMain.appendChild(manageSubscription); + + const hr = document.createElement("hr"); + hr.addClass("settings-dialog-hr"); + divMain.appendChild(hr); + + const languageDiv = this.createLanguageDiv(); + divMain.appendChild(languageDiv); + return divMain; + } + createLanguageDiv(): HTMLDivElement { + const divMain = document.createElement("div"); + divMain.addClass("settings-dialog-language-div"); + + const txtTitle = document.createElement("h4"); + txtTitle.innerText = "Translation"; + txtTitle.addClass("settings-dialog-language-title"); + divMain.appendChild(txtTitle); + + const divRow = document.createElement("div"); + divRow.addClass("settings-dialog-row-div"); + divMain.appendChild(divRow); + + const txtSubtitle = document.createElement("p"); + txtSubtitle.innerText = "Translate to"; + txtSubtitle.addClass("settings-dialog-language-subtitle"); + divRow.appendChild(txtSubtitle); + + const dropDown = new DropdownComponent(divRow); + dropDown.selectEl.addClass("settings-dialog-language-dropdown"); + + for (const [language] of langauges) { + dropDown.addOption(language, language); + } + dropDown.onChange((value) => this.onLanguageChange(value)); + dropDown.setValue(this.currentTranslateTo); + + return divMain; + } + + onOpen() { + const { contentEl } = this; + const divContainer = contentEl.createEl("div"); + divContainer.addClass("settings-dialog-container"); + + divContainer.appendChild(this.createSettingsDiv()); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/models/CustomResponse.ts b/src/models/CustomResponse.ts new file mode 100644 index 0000000..e6c8cea --- /dev/null +++ b/src/models/CustomResponse.ts @@ -0,0 +1,19 @@ +export enum Status { + Success = "success", + InternetDisconnected = "internetDisconnected", + ExceededQuota = "exceededQuota", + InvalidAPIKey = "invalidAPIKey ", + EmptyAPIKey = "emptyAPIKey ", + EmptyPrompt = "imptyPrompt", + UnknownError = "unknownError", + UserUnsubscribed = "userUnsubscribed", +} +export class CustomResponse { + status: Status; + body: string; + + constructor(status: Status, body: string) { + this.status = status; + this.body = body; + } +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 0000000..b2a14a1 --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1,5 @@ +export const API_URL = "https://rapidapi.com/obsidian-api-obsidian-api-default/api/obsidian-ai"; + +export const API_MANAGEMENT_URL = "https://rapidapi.com/developer/billing/subscriptions-and-usage"; + +export const API_PRICING_URL = "https://rapidapi.com/obsidian-api-obsidian-api-default/api/obsidian-ai/pricing"; diff --git a/src/utils/languages.ts b/src/utils/languages.ts new file mode 100644 index 0000000..8b9e947 --- /dev/null +++ b/src/utils/languages.ts @@ -0,0 +1,193 @@ +export const langauges = [ + ['Abkhazian', 'ab'], + ['Afar', 'aa'], + ['Afrikaans', 'af'], + ['Akan', 'ak'], + ['Albanian', 'sq'], + ['Amharic', 'am'], + ['Arabic', 'ar'], + ['Aragonese', 'an'], + ['Armenian', 'hy'], + ['Assamese', 'as'], + ['Avaric', 'av'], + ['Avestan', 'ae'], + ['Aymara', 'ay'], + ['Azerbaijani', 'az'], + ['Bambara', 'bm'], + ['Bashkir', 'ba'], + ['Basque', 'eu'], + ['Belarusian', 'be'], + ['Bengali (Bangla)', 'bn'], + ['Bihari', 'bh'], + ['Bislama', 'bi'], + ['Bosnian', 'bs'], + ['Breton', 'br'], + ['Bulgarian', 'bg'], + ['Burmese', 'my'], + ['Catalan', 'ca'], + ['Chamorro', 'ch'], + ['Chechen', 'ce'], + ['Chichewa, Chewa, Nyanja', 'ny'], + ['Chinese', 'zh'], + ['Chinese (Simplified)', 'zh-Hans'], + ['Chinese (Traditional)', 'zh-Hant'], + ['Chuvash', 'cv'], + ['Cornish', 'kw'], + ['Corsican', 'co'], + ['Cree', 'cr'], + ['Croatian', 'hr'], + ['Czech', 'cs'], + ['Danish', 'da'], + ['Divehi, Dhivehi, Maldivian', 'dv'], + ['Dutch', 'nl'], + ['Dzongkha', 'dz'], + ['English', 'en'], + ['Esperanto', 'eo'], + ['Estonian', 'et'], + ['Ewe', 'ee'], + ['Faroese', 'fo'], + ['Fijian', 'fj'], + ['Finnish', 'fi'], + ['French', 'fr'], + ['Fula, Fulah, Pulaar, Pular', 'ff'], + ['Galician', 'gl'], + ['Gaelic (Scottish)', 'gd'], + ['Gaelic (Manx)', 'gv'], + ['Georgian', 'ka'], + ['German', 'de'], + ['Greek', 'el'], + ['Greenlandic', 'kl'], + ['Guarani', 'gn'], + ['Gujarati', 'gu'], + ['Haitian Creole', 'ht'], + ['Hausa', 'ha'], + ['Hebrew', 'he'], + ['Herero', 'hz'], + ['Hindi', 'hi'], + ['Hiri Motu', 'ho'], + ['Hungarian', 'hu'], + ['Icelandic', 'is'], + ['Ido', 'io'], + ['Igbo', 'ig'], + ['Indonesian', 'id, in'], + ['Interlingua', 'ia'], + ['Interlingue', 'ie'], + ['Inuktitut', 'iu'], + ['Inupiak', 'ik'], + ['Irish', 'ga'], + ['Italian', 'it'], + ['Japanese', 'ja'], + ['Javanese', 'jv'], + ['Kalaallisut, Greenlandic', 'kl'], + ['Kannada', 'kn'], + ['Kanuri', 'kr'], + ['Kashmiri', 'ks'], + ['Kazakh', 'kk'], + ['Khmer', 'km'], + ['Kikuyu', 'ki'], + ['Kinyarwanda (Rwanda)', 'rw'], + ['Kirundi', 'rn'], + ['Kyrgyz', 'ky'], + ['Komi', 'kv'], + ['Kongo', 'kg'], + ['Korean', 'ko'], + ['Kurdish', 'ku'], + ['Kwanyama', 'kj'], + ['Lao', 'lo'], + ['Latin', 'la'], + ['Latvian (Lettish)', 'lv'], + ['Limburgish ( Limburger)', 'li'], + ['Lingala', 'ln'], + ['Lithuanian', 'lt'], + ['Luga-Katanga', 'lu'], + ['Luganda, Ganda', 'lg'], + ['Luxembourgish', 'lb'], + ['Manx', 'gv'], + ['Macedonian', 'mk'], + ['Malagasy', 'mg'], + ['Malay', 'ms'], + ['Malayalam', 'ml'], + ['Maltese', 'mt'], + ['Maori', 'mi'], + ['Marathi', 'mr'], + ['Marshallese', 'mh'], + ['Moldavian', 'mo'], + ['Mongolian', 'mn'], + ['Nauru', 'na'], + ['Navajo', 'nv'], + ['Ndonga', 'ng'], + ['Northern Ndebele', 'nd'], + ['Nepali', 'ne'], + ['Norwegian', 'no'], + ['Norwegian bokmål', 'nb'], + ['Norwegian nynorsk', 'nn'], + ['Nuosu', 'ii'], + ['Occitan', 'oc'], + ['Ojibwe', 'oj'], + ['Old Church Slavonic, Old Bulgarian', 'cu'], + ['Oriya', 'or'], + ['Oromo (Afaan Oromo)', 'om'], + ['Ossetian', 'os'], + ['Pāli', 'pi'], + ['Pashto, Pushto', 'ps'], + ['Persian (Farsi)', 'fa'], + ['Polish', 'pl'], + ['Portuguese', 'pt'], + ['Punjabi (Eastern)', 'pa'], + ['Quechua', 'qu'], + ['Romansh', 'rm'], + ['Romanian', 'ro'], + ['Russian', 'ru'], + ['Sami', 'se'], + ['Samoan', 'sm'], + ['Sango', 'sg'], + ['Sanskrit', 'sa'], + ['Serbian', 'sr'], + ['Serbo-Croatian', 'sh'], + ['Sesotho', 'st'], + ['Setswana', 'tn'], + ['Shona', 'sn'], + ['Sichuan Yi', 'ii'], + ['Sindhi', 'sd'], + ['Sinhalese', 'si'], + ['Siswati', 'ss'], + ['Slovak', 'sk'], + ['Slovenian', 'sl'], + ['Somali', 'so'], + ['Southern Ndebele', 'nr'], + ['Spanish', 'es'], + ['Sundanese', 'su'], + ['Swahili (Kiswahili)', 'sw'], + ['Swati', 'ss'], + ['Swedish', 'sv'], + ['Tagalog', 'tl'], + ['Tahitian', 'ty'], + ['Tajik', 'tg'], + ['Tamil', 'ta'], + ['Tatar', 'tt'], + ['Telugu', 'te'], + ['Thai', 'th'], + ['Tibetan', 'bo'], + ['Tigrinya', 'ti'], + ['Tonga', 'to'], + ['Tsonga', 'ts'], + ['Turkish', 'tr'], + ['Turkmen', 'tk'], + ['Twi', 'tw'], + ['Uyghur', 'ug'], + ['Ukrainian', 'uk'], + ['Urdu', 'ur'], + ['Uzbek', 'uz'], + ['Venda', 've'], + ['Vietnamese', 'vi'], + ['Volapük', 'vo'], + ['Wallon', 'wa'], + ['Welsh', 'cy'], + ['Wolof', 'wo'], + ['Western Frisian', 'fy'], + ['Xhosa', 'xh'], + ['Yiddish', 'yi, ji'], + ['Yoruba', 'yo'], + ['Zhuang, Chuang', 'za'], + ['Zulu', 'zu'], +]; \ No newline at end of file diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..53e0377 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,16 @@ +import { API_URL } from "./constants"; + +export function getBadge(width: number, link: string = API_URL) { + const anchorElement = document.createElement("a"); + anchorElement.href = link; + anchorElement.target = "_blank"; + anchorElement.style.display = "block"; + const imageElement = document.createElement("img"); + imageElement.src = + "https://storage.googleapis.com/rapidapi-documentation/connect-on-rapidapi-light.png"; + imageElement.width = width; + imageElement.alt = "Connect on RapidAPI"; + + anchorElement.appendChild(imageElement); + return anchorElement; +} diff --git a/styles.css b/styles.css index 71cc60f..21f742d 100644 --- a/styles.css +++ b/styles.css @@ -1,8 +1,628 @@ -/* +.copy-icon-button { + cursor: auto; +} +.copy-icon-button:hover { + cursor: pointer; +} -This CSS file will be included with your plugin, and -available in the app when your plugin is enabled. +.normal-modal-main-div { + padding-left: 24; + padding-right: 24; + display: flex; + flex-direction: column; + align-items: stretch; +} -If your plugin does not need CSS, delete this file. +.normal-modal-input-title-div { + display: flex; + flex-direction: row; + align-items: center; +} -*/ +.normal-modal-input-title-text { + margin-left: 8px; +} + +.normal-modal-input-textbox-div { + display: flex; + flex-direction: column; + align-items: stretch; + border-radius: 12px; +} + +.normal-modal-input-textbox { + padding: 14px 16px; + min-height: 100px; + resize: none; + font-size: 16px; + font-weight: 400; + border-radius: 8px; + line-height: 28px; +} + +.normal-modal-input-tip-div { + display: flex; + flex-direction: row; + margin-top: 18px; + align-items: start; + margin-left: auto; +} + +.normal-modal-input-tip-icon { + padding: 0px 4px; +} + +.normal-modal-input-send-button { + width: auto; + font-size: 14px; + min-height: 38px; + border-radius: 8px; + margin-top: 18px; + margin-left: auto; + margin-bottom: 12px; + font-size: 16px; +} + +.normal-modal-output-main-div { + padding-left: 24px; + padding-right: 24px; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.normal-modal-output-title { + margin-left: 8px; +} + +.normal-modal-output-textbox-div { + position: relative; + border-radius: 12px; + padding: 0px; + margin: 0px; +} + +.normal-modal-output-textbox { + padding: 14px 16px; + width: 100%; + height: 100%; + min-height: 100px; + resize: none; + font-size: 16px; + font-weight: 400; + border-radius: 8px; + line-height: 28px; +} + +.normal-modal-copy-button { + position: absolute; + right: 16px; + bottom: 16px; +} + +.normal-modal-output-insert-button { + width: auto; + min-height: 42px; + border-radius: 8px; + margin-top: 18px; + margin-left: auto; + margin-bottom: 12px; + font-size: 16px; +} + +.normal-modal-output-insert-button-div { + display: flex; + flex-direction: row; + align-items: center; +} + +.normal-modal-ouput-submit-icon { + margin: 4px 8px 0px 4px; +} + +.normal-modal-ouput-submit-text { + text-align: center; +} + +.selection-modal-icon-button { + width: auto; + min-height: 42px; + border-radius: 8px; + margin-top: 18px; + margin-bottom: 12px; + font-size: 16px; + display: flex; + flex-direction: row; + align-items: center; +} + +.selection-modal-icon-button-icon { + margin: 4px 8px 0px 4px; +} + +.selection-modal-icon-button-text { + text-align: center; +} + +.selection-modal-input-main-div { + display: flex; + flex-direction: column; + align-items: stretch; + padding-left: 24px; + padding-right: 24px; +} + +.selection-modal-input-title-div { + display: flex; + flex-direction: row; + align-items: center; +} + +.selection-modal-input-title { + margin-left: 8px; +} + +.selection-modal-input-selected-text-div { + font-size: 16px; + font-weight: 500; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + max-width: 500px; +} + +.selection-modal-input-textbox-div { + border-radius: 12px; + display: flex; + flex-direction: column; + align-items: stretch; + margin-top: 21px; +} + +.selection-modal-input-actions-div { + display: flex; + flex-direction: row; + align-items: start; +} + +.selection-modal-input-translate-button { + margin-left: 18px; +} + +.selection-modal-input-format-button { + margin-left: 18px; +} + +.selection-modal-input-textbox { + padding: 14px 16px; + resize: none; + max-height: 230px; + font-size: 16px; + font-weight: 400px; + border-radius: 8px; + line-height: 28px; + border-width: 1px; +} + +.selection-modal-send-button { + width: auto; + font-size: 14px; + min-height: 38px; + border-radius: 8px; + margin-top: 18px; + margin-left: auto; + margin-bottom: 12px; + font-size: 16px; +} + +.selection-modal-output-main-div { + padding-left: 24px; + padding-right: 24px; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.selection-modal-output-title { + margin-left: 8px; +} + +.selection-modal-output-textbox-div { + position: relative; + border-radius: 12px; + padding: 0px; +} + +.selection-modal-output-textbox { + padding: 14px 16px; + margin: 0px; + width: 100%; + height: 100%; + min-height: 100px; + resize: none; + font-size: 16px; + font-weight: 400; + border-radius: 8px; + line-height: 28px; +} + +.selection-modal-output-copy-button { + position: absolute; + right: 16px; + bottom: 16px; +} + +.selection-modal-output-insert-button { + display: flex; + flex-direction: row; + align-items: center; + width: auto; + min-height: 42px; + border-radius: 8px; + margin-top: 18px; + margin-left: auto; + margin-bottom: 12px; + font-size: 16px; +} + +.selection-modal-output-insert-icon { + margin: 4px 8px 0px 4px; +} + +.selection-modal-output-insert-text { + text-align: center; +} + +.selection-modal-output-tip-div { + display: flex; + flex-direction: row; + margin-top: 18px; + align-items: start; + margin-left: auto; +} + +.selection-modal-output-tip-icon { + padding: 0px 4px; + margin-top: 2px; +} + +.settings-tab-main-div { + padding-left: 24px; + padding-right: 24px; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.settings-tab-title { + margin-left: 8px; +} + +.settings-tab-key-div { + border-radius: 12px; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.settings-tab-key-textbox { + background: var(--background-primary-alt); + border: 1px solid; + border-color: var(--background-modifier-border); + font-size: 16px; + font-weight: 400; + border-radius: 8px; + line-height: 28px; + padding: 8px 16px; +} + +.settings-tab-test-key-div { + display: flex; + margin-top: 18px; + margin-right: auto; + margin-bottom: 12px; + align-items: center; + flex-direction: row; +} + +.settings-tab-test-key-button { + padding: 14px 28px; + min-height: 36px; + width: auto; + border-radius: 24px; + font-size: 14px; + font-weight: 500; +} + +.settings-tab-key-state-div { + display: none; + flex-direction: row; + align-items: center; + margin-left: 12px; +} + +.settings-tab-key-state-icon { + margin-top: 3.5px; +} + +.settings-tab-state-text { + margin: 4px 8px 0px 4px; + margin-bottom: 3px; +} + +.settings-tab-api-link { + margin-top: 14px; +} + +.settings-tab-badge { + margin-top: 12px; +} + +.settings-tab-manage-subscription { + margin-top: 21px; + text-decoration: underline; +} + +.settings-tab-hr { + margin-top: 28px; + margin-bottom: 8px; +} + +.settings-tab-language-div { + display: flex; + flex-direction: column; + align-items: start; + margin-bottom: 24px; +} + +.settings-tab-langauge-title { + margin-left: 8px; +} + +.settings-tab-language-subtiitle-div { + display: flex; + flex-direction: row; + align-items: center; +} + +.settings-tab-language-subtitle { + margin-left: 8px; +} + +.settings-tab-language-dropdown { + margin-left: 24px; + min-height: 38px; + font-size: 14px; + border-radius: 8px; +} + +.basic-dialog-main-div { + padding-left: 24px; + padding-right: 24px; + display: flex; + flex-direction: column; + align-items: center; +} + +.basic-dialog-main-title { + margin-left: 8px; +} + +.basic-dialog-main-subtitle { + margin-left: 8px; +} + +.basic-dialog-action-button { + width: auto; + min-width: 130px; + font-size: 14px; + min-height: 38px; + border-radius: 24px; + margin-top: 18px; + margin-bottom: 12px; + font-size: 16px; +} + +.basic-dialog-badge { + margin-right: auto; + margin-left: 10px; + margin-bottom: 8px; +} + +.missing-key-dialog-main-div { + padding-left: 24px; + padding-right: 24px; + display: flex; + flex-direction: column; + align-items: start; +} + +.missing-key-dialog-title { + margin-left: auto; + margin-right: auto; +} + +.missing-key-dialog-badge { + margin-right: auto; + margin-top: 14px; +} + +.missing-key-dialog-tip-text { + margin-top: 16px; +} + +.missing-key-dialog-action-button { + width: auto; + min-width: 130px; + font-size: 14px; + min-height: 38px; + border-radius: 24px; + margin-top: 18px; + margin-bottom: 12px; + font-size: 16px; +} + +.missing-key-dialog-main-container { + display: flex; + flex-direction: column; + align-items: stretch; +} + +.quota-exceeded-dialog-main-div { + padding-left: 24px; + padding-right: 24px; + display: flex; + flex-direction: column; + align-items: center; +} +.quota-exceeded-dialog-title { + margin-left: 8px; +} + +.quota-exceeded-dialog-subtitle { + margin-left: 8px; +} + +.quota-exceeded-dialog-manage-subscription-link { + text-decoration: underline; + color: #47a3fe; +} + +.quota-exceeded-dialog-upgrade-button { + width: auto; + min-width: 130px; + font-size: 14px; + min-height: 38px; + border-radius: 24px; + margin-top: 18px; + margin-bottom: 12px; + font-size: 16px; +} + +.quota-exceeded-dialog-badge { + margin-right: auto; + margin-left: -10px; + margin-bottom: 8px; +} + +.quota-exceeded-dialog-container { + display: flex; + flex-direction: column; + align-items: stretch; +} + +.settings-dialog-main-div { + padding-left: 24px; + padding-right: 24px; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.settings-dialog-title { + margin-left: 8px; +} + +.settings-dialog-api-key-div { + display: flex; + flex-direction: column; + align-items: stretch; + border-radius: 12px; +} + +.settings-dialog-api-textbox { + background: var(--background-primary-alt); + border: 1px solid; + border-color: var(--background-modifier-border); + font-size: 16px; + font-weight: 400; + border-radius: 8px; + line-height: 28px; + padding: 8px 16px; +} + +.settings-dialog-test-div { + display: flex; + flex-direction: row; + align-items: center; + margin-top: 18px; + margin-right: auto; + margin-bottom: 12px; +} + +.settings-dialog-test-key-button { + padding: 14px 28px; + min-height: 36px; + width: auto; + border-radius: 24px; + font-size: 14px; + font-weight: 500; +} + +.settings-dialog-test-result-div { + display: none; + flex-direction: row; + align-items: center; + margin-left: 12px; +} + +.settings-dialog-test-result-icon { + margin-top: 3.5px; +} + +.settings-dialog-test-result-text { + margin: 4px 8px 0px 4px; + margin-bottom: 3px; +} + +.settings-dialog-anchor{ + margin-top: 14px; +} + +.settings-dialog-badge{ + margin-top: 12px; +} + +.settings-dialog-manage-subscription{ + margin-top: 21px; + text-decoration: underline; +} + +.settings-dialog-hr{ + margin-top: 28px; + margin-bottom: 8px; +} + +.settings-dialog-language-div{ + display: flex; + flex-direction: column; + align-items: start; + margin-bottom: 24px; +} + +.settings-dialog-language-title{ + margin-left: 8px; +} + +.settings-dialog-language-subtitle{ + margin-left: 8px; +} + +.settings-dialog-row-div{ + display: flex; + flex-direction: row; + align-items: center; +} + +.settings-dialog-language-dropdown{ + margin-left: 24px; + min-height: 38px; + font-size: 14px; + border-radius: 8px; +} + +.settings-dialog-container{ + display: flex; + flex-direction: column; + align-items: stretch; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 2d6fbdf..87ce3bb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ "isolatedModules": true, "strictNullChecks": true, "lib": [ - "DOM", + "DOM", "ES5", "ES6", "ES7" @@ -21,4 +21,4 @@ "include": [ "**/*.ts" ] -} +} \ No newline at end of file