├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── dist ├── hyperapp-devtools.es.js ├── hyperapp-devtools.es.js.map ├── hyperapp-devtools.js ├── hyperapp-devtools.js.map ├── hyperapp-devtools.min.js ├── hyperapp-devtools.min.js.map └── src │ ├── actions │ ├── deleteRun.d.ts │ ├── execute.d.ts │ ├── index.d.ts │ ├── logCallEnd.d.ts │ ├── logCallStart.d.ts │ ├── logInit.d.ts │ ├── logMessage.d.ts │ ├── select.d.ts │ ├── setCallOverviewText.d.ts │ ├── setDetailsPaneExpanded.d.ts │ ├── setPaneDisplay.d.ts │ ├── setValueDisplay.d.ts │ ├── showPane.d.ts │ ├── timeTravel.d.ts │ ├── toggleCollapseRepeatingEvents.d.ts │ ├── toggleEvent.d.ts │ └── toggleRun.d.ts │ ├── api.d.ts │ ├── components │ ├── CallOverviewDetailsPane.d.ts │ ├── DebugPane.d.ts │ ├── DebugPaneContent.d.ts │ ├── DebugPaneToolbar.d.ts │ ├── DebuggerOptions.d.ts │ ├── Icon.d.ts │ ├── ObjectDetailsPane.d.ts │ ├── ObjectView.d.ts │ ├── RunEvent.d.ts │ ├── RunEventList.d.ts │ ├── RunsPane.d.ts │ ├── RunsPaneItem.d.ts │ ├── TogglePaneButton.d.ts │ └── index.d.ts │ ├── debug.d.ts │ ├── debuggedFunctions.d.ts │ ├── devtools.d.ts │ ├── enhanceActions.d.ts │ ├── immutable.d.ts │ ├── index.d.ts │ ├── selectors.d.ts │ ├── state.d.ts │ ├── utils.d.ts │ ├── valueDisplay.d.ts │ └── view.d.ts ├── examples ├── circular-state.html ├── counter.html ├── debug-function.html ├── error-in-action.html ├── error-in-function.html ├── hyperapp.js ├── index.html ├── long-names.html ├── nested-state.html └── todos.html ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── actions │ ├── deleteRun.ts │ ├── execute.ts │ ├── index.ts │ ├── logCallEnd.ts │ ├── logCallStart.ts │ ├── logInit.ts │ ├── logMessage.ts │ ├── select.ts │ ├── setCallOverviewText.ts │ ├── setDetailsPaneExpanded.ts │ ├── setPaneDisplay.ts │ ├── setValueDisplay.ts │ ├── showPane.ts │ ├── timeTravel.ts │ ├── toggleCollapseRepeatingEvents.ts │ ├── toggleEvent.ts │ └── toggleRun.ts ├── api.ts ├── components │ ├── CallOverviewDetailsPane.scss │ ├── CallOverviewDetailsPane.tsx │ ├── DebugPane.scss │ ├── DebugPane.tsx │ ├── DebugPaneContent.scss │ ├── DebugPaneContent.tsx │ ├── DebugPaneToolbar.scss │ ├── DebugPaneToolbar.tsx │ ├── DebuggerOptions.scss │ ├── DebuggerOptions.tsx │ ├── Icon.scss │ ├── Icon.tsx │ ├── ObjectDetailsPane.scss │ ├── ObjectDetailsPane.tsx │ ├── ObjectView.scss │ ├── ObjectView.tsx │ ├── RunEvent.scss │ ├── RunEvent.tsx │ ├── RunEventList.scss │ ├── RunEventList.tsx │ ├── RunsPane.scss │ ├── RunsPane.tsx │ ├── RunsPaneItem.scss │ ├── RunsPaneItem.tsx │ ├── TogglePaneButton.scss │ ├── TogglePaneButton.tsx │ ├── _variables.scss │ ├── index.scss │ └── index.ts ├── debug.ts ├── debuggedFunctions.ts ├── devtools.ts ├── enhanceActions.ts ├── immutable.ts ├── index.ts ├── selectors.ts ├── state.ts ├── utils.ts ├── valueDisplay.ts └── view.tsx └── tsconfig.json /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstart/hyperapp-devtools/08abd1ad56fd7719bcb967c204881150ba07be70/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .rpt2_cache 3 | _ignore 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hyperapp-devtools 2 | 3 | Developer tools for Hyperapp projects. 4 | These tools have been extracted from [hyperstart's](https://hyperstart.io) debugger. 5 | 6 | This is an higher order application (HOA) that records every action and allow the user to see input argument, output and state at every step. 7 | 8 | See it in action here: 9 | 10 | ![debugger in action](https://user-images.githubusercontent.com/8634093/39748206-c91f27d6-52af-11e8-8727-867f806190b9.gif) 11 | 12 | ## Installation 13 | 14 | Install it from npm: 15 | 16 | ``` 17 | npm install hyperapp-devtools --save-dev 18 | ``` 19 | 20 | Or get it directly from unpkg: 21 | 22 | ```html 23 | 24 | ``` 25 | 26 | ## Usage 27 | 28 | Just wrap your hyperapp: 29 | 30 | ```js 31 | import { h, app } from "hyperapp" 32 | import devtools from "hyperapp-devtools" 33 | 34 | const state = { 35 | count: 0 36 | } 37 | 38 | const actions = { 39 | down: value => state => ({ count: state.count - value }), 40 | up: value => state => ({ count: state.count + value }) 41 | } 42 | 43 | const view = (state, actions) => ( 44 |
45 |

{state.count}

46 | 47 | 48 |
49 | ) 50 | 51 | devtools(app)(state, actions, view, document.body) 52 | ``` 53 | 54 | ## Contributing 55 | 56 | Once you cloned the project and `npm install` the dependencies, you can run the examples with `npm start`. 57 | 58 | ## License 59 | 60 | GPL 61 | 62 | **TLDR** 63 | 64 | * You may use this to debug your own projects (open source, closed source, free, commercial, anything goes...) 65 | * If you distribute this as part of your product/project, the project must be GPL (if that's not OK, please contact us). 66 | -------------------------------------------------------------------------------- /dist/hyperapp-devtools.min.js: -------------------------------------------------------------------------------- 1 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(e.devtools={})}(this,function(e){"use strict";var n="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",t=function(){return n[Math.floor(Math.random()*n.length)]},u=function(){return Array.apply(null,Array(16)).map(t).join("")};function f(e,n){for(var t=[],r=[],a=arguments.length;2A)return t.substring(0,A-3)+"..."}return t}function N(e){var n=e.state,t=e.actions,r=e.run,a=e.events,o=e.indexInList,s=e.event;return f("a",{href:"",class:"item-link"+(function(e,n){var t=e.selectedEvent;if(!t||!n)return!1;var r=e.runsById[t.runId];return r&&r.eventsById[t.eventId]===n}(n,s)?" selected":""),onclick:function(e){e.preventDefault(),t.select({runId:r.id,eventId:s.id})}},function(e){var n=e.actions,t=e.run,r=e.event;if(!r.children||0===r.children.length)return f(k,{name:"empty"});var a=function(e){e.stopPropagation(),e.preventDefault(),n.toggleEvent({runId:t.id,eventId:r.id})};return r.collapsed?f(k,{name:"caret-right",onclick:a}):f(k,{name:"caret-bottom",onclick:a})}(e),f("span",{class:function(e){switch(e.type){case"init":return"";case"action":case"function":return e.error?"error":"";case"message":return e.level}}(s)},function(e){switch(e.type){case"init":return"Initial State";case"action":return e.name+"("+R(void 0===e.data?[]:[e.data])+")";case"function":return"function "+e.name+"("+R(e.args)+")";case"message":return"["+e.level+"] "+(n=e.message,void 0===t&&(t=30),n.length<=t?n:n.substr(0,t-2)+"...")}var n,t}(s)),n.collapseRepeatingEvents&&f("span",{class:"run-event-count"},function(e,n,t){for(var r=e.eventsById[n[t]],a=1,o=t-1;0<=o;){var s=e.eventsById[n[o]];if(s.name!==r.name||s.type!==r.type)return 1===a?"":" (x"+a+")";a++,o--}return 1===a?"":" (x"+a+")"}(r,a,o)))}function z(e){var u=e.state,d=e.actions,v=e.run,n=e.events;return 0===n.length?null:f("ul",{class:"run-event-list"},n.map(function(e,n){return t={state:u,actions:d,events:v.events,event:v.eventsById[e],indexInList:n,run:v},r=t.state,a=t.actions,o=t.run,s=t.events,i=t.indexInList,l=t.event,(c=o.eventsById[s[i+1]])&&c.name===l.name&&c.type===l.type&&r.collapseRepeatingEvents?null:f("li",{class:"run-event",key:i},N(t),l.children&&!l.collapsed&&z({state:r,actions:a,run:o,events:l.children}));var t,r,a,o,s,i,l,c}).reverse())}function M(e){var l=e.state,c=e.actions,n=e.runs,u=[],d=n.length-1;return n.forEach(function(e,n){var t,r,a,o,s,i;u.unshift((r=(t={state:l,actions:c,run:e,current:n===d}).state,a=t.actions,o=t.run,s=new Date(o.timestamp).toLocaleTimeString(),i=o.collapsed,f("li",{class:"run-pane-item",key:o.timestamp},f("h2",null,"Run - ",s),!i&&z({run:o,state:r,actions:a,events:o.events}))))}),f("div",{class:"runs-pane scrollable"},f("ul",{class:"runs-pane-runs scrollable-content"},u))}r(".run-event-list {\n list-style-type: none;\n margin: 0 0 0 0.6rem;\n padding: 0; }\n");function J(e){var n,t,r,a,o,s,i,l=e.state,c=e.actions;return f("div",{class:"hyperapp-devtools debug-pane"},(s=(o={state:l,actions:c}).state,i=o.actions,f("div",{class:"debug-pane-toolbar"},f("span",{class:"toolbar-section view-buttons"},f("button",{class:"fullscreen"===s.paneDisplay?"selected":"",onclick:function(){return i.setPaneDisplay("fullscreen")}},"Full Screen"),f("button",{class:"right"===s.paneDisplay?"selected":"",onclick:function(){return i.setPaneDisplay("right")}},"Right"),f("button",{class:"bottom"===s.paneDisplay?"selected":"",onclick:function(){return i.setPaneDisplay("bottom")}},"Bottom")),f("span",{class:"toolbar-section travel-button"},f("button",{onclick:function(){return i.timeTravel(s.selectedEvent)},disabled:!d(s)},"Travel to Action")),f("span",{class:"toolbar-section close-button"},f(k,{name:"cross",onclick:function(){return i.showPane(!1)}})))),p({state:l,actions:c}),(t=(n={state:l,actions:c}).state,r=n.actions,0===(a=t.runs.map(function(e){return t.runsById[e]})).length?f("div",{class:"debug-pane-content"},f("p",null,"No debug information found, please debug this project.")):f("div",{class:"debug-pane-content"},M({state:t,actions:r,runs:a}),T({state:t,actions:r}))))}r(".debug-pane {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: #2b303b;\n border: 1px solid #697080;\n color: #dbdbdb; }\n .debug-pane a {\n text-decoration: none; }\n");function L(e){var n=e.state,t=e.actions;return f("div",{class:"hyperapp-devtools toggle-pane-button"},f("button",{onclick:function(){return t.showPane(!n.paneShown)}},"Devtools"))}function _(e,n){return e.paneShown?f("div",{class:function(e){switch(e){case"fullscreen":return"devtools-overlay";case"right":return"devtools-overlay align-right";case"bottom":return"devtools-overlay align-bottom"}}(e.paneDisplay)},J({state:e,actions:n}),L({state:e,actions:n})):L({state:e,actions:n})}r(".toggle-pane-button {\n position: fixed;\n right: 2%;\n bottom: 2%; }\n");var F={runs:[],runsById:{},paneDisplay:"right",valueDisplay:"state",paneShown:!1,selectedEvent:null,collapseRepeatingEvents:!0,detailsPaneExpandedPaths:{}},V=Object.assign||function(e){for(var n,t=1,r=arguments.length;t { ... } or use a named function.');if("function"!=typeof t)throw new Error("Can only debug a function but got "+typeof t+".");var a=Y(t,r);return function(e,n){if(H[e])throw new Error('There is already a function registered with name "'+e+'".');H[e]=n}(r,a),a},Object.defineProperty(e,"__esModule",{value:!0})}); 2 | //# sourceMappingURL=hyperapp-devtools.min.js.map 3 | -------------------------------------------------------------------------------- /dist/src/actions/deleteRun.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const deleteRun: (id: string) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/execute.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const execute: (payload: api.ExecutePayload) => (state: api.State) => void; 3 | -------------------------------------------------------------------------------- /dist/src/actions/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./deleteRun"; 2 | export * from "./execute"; 3 | export * from "./logCallEnd"; 4 | export * from "./logCallStart"; 5 | export * from "./logInit"; 6 | export * from "./logMessage"; 7 | export * from "./select"; 8 | export * from "./setCallOverviewText"; 9 | export * from "./setDetailsPaneExpanded"; 10 | export * from "./setPaneDisplay"; 11 | export * from "./setValueDisplay"; 12 | export * from "./showPane"; 13 | export * from "./timeTravel"; 14 | export * from "./toggleCollapseRepeatingEvents"; 15 | export * from "./toggleEvent"; 16 | export * from "./toggleRun"; 17 | -------------------------------------------------------------------------------- /dist/src/actions/logCallEnd.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const logCallEnd: (payload: api.LogCallEndPayload) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/logCallStart.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const logCallStart: (payload: api.LogCallStartPayload) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/logInit.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const logInit: (payload: api.LogInitPayload) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/logMessage.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const logMessage: (payload: api.LogMessagePayload) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/select.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const select: (selectedEvent: api.SelectedEvent) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/setCallOverviewText.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const setCallOverviewText: (callOverviewText: string) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/setDetailsPaneExpanded.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const setDetailsPaneExpanded: (payload: api.SetDetailsPaneExpandedPayload) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/setPaneDisplay.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const setPaneDisplay: (paneDisplay: api.PaneDisplay) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/setValueDisplay.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const setValueDisplay: (valueDisplay: api.ValueDisplay) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/showPane.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const showPane: (paneShown: boolean) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/timeTravel.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const timeTravel: (selectedEvent: api.SelectedEvent) => (state: api.State) => void; 3 | -------------------------------------------------------------------------------- /dist/src/actions/toggleCollapseRepeatingEvents.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const toggleCollapseRepeatingEvents: () => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/toggleEvent.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const toggleEvent: (payload: api.ToggleEventPayload) => (state: api.State) => Partial; 3 | -------------------------------------------------------------------------------- /dist/src/actions/toggleRun.d.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | export declare const toggleRun: (id: string) => (state: api.State) => { 3 | runsById: { 4 | [x: string]: api.Run; 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /dist/src/api.d.ts: -------------------------------------------------------------------------------- 1 | export interface StringMap { 2 | [key: string]: V; 3 | } 4 | export declare type EventType = "function" | "action" | "init" | "message"; 5 | export declare type AppEvent = InitEvent | ActionEvent | FunctionEvent | MessageEvent; 6 | export interface BaseEvent { 7 | id: string; 8 | type: EventType; 9 | name: string; 10 | children?: string[]; 11 | collapsed?: boolean; 12 | parent?: string; 13 | } 14 | export interface InitEvent extends BaseEvent { 15 | type: "init"; 16 | state: any; 17 | } 18 | export interface ActionEvent extends BaseEvent { 19 | type: "action"; 20 | data: any; 21 | result?: any; 22 | error?: any; 23 | stateBefore: any; 24 | stateAfter?: any; 25 | } 26 | export interface FunctionEvent extends BaseEvent { 27 | type: "function"; 28 | args: any[]; 29 | result?: any; 30 | error?: any; 31 | returnedBy?: string; 32 | } 33 | export declare type LogLevel = "info" | "warn" | "error"; 34 | export interface MessageEvent extends BaseEvent { 35 | type: "message"; 36 | level: LogLevel; 37 | message: any; 38 | } 39 | export interface Run { 40 | id: string; 41 | events: string[]; 42 | eventsById: StringMap; 43 | timestamp: number; 44 | collapsed: boolean; 45 | currentEvent?: string; 46 | currentState?: any; 47 | interop: any; 48 | } 49 | export interface SelectedEvent { 50 | runId: string; 51 | eventId: string; 52 | } 53 | export declare type PaneDisplay = "fullscreen" | "right" | "bottom"; 54 | export declare type ValueDisplay = "state" | "result" | "args" | "message" | "data" | "call-overview" | "debugger-state"; 55 | export interface State { 56 | runs: string[]; 57 | runsById: StringMap; 58 | selectedEvent: SelectedEvent | null; 59 | collapseRepeatingEvents: boolean; 60 | valueDisplay: ValueDisplay; 61 | detailsPaneExpandedPaths: StringMap; 62 | paneDisplay: PaneDisplay; 63 | paneShown: boolean; 64 | callOverviewText?: string; 65 | } 66 | export interface LogInitPayload { 67 | runId: string; 68 | timestamp: number; 69 | state: any; 70 | interop: any; 71 | } 72 | export interface LogMessagePayload { 73 | runId: string; 74 | eventId: string; 75 | level: LogLevel; 76 | message: any; 77 | } 78 | export interface LogCallStartPayload { 79 | runId?: string; 80 | eventId: string; 81 | type: "function" | "action"; 82 | name: string; 83 | args: any[]; 84 | } 85 | export interface LogCallEndPayload { 86 | runId?: string; 87 | eventId: string; 88 | result?: any; 89 | error?: any; 90 | } 91 | export interface ToggleEventPayload { 92 | runId: string; 93 | eventId: string; 94 | } 95 | export interface SetDetailsPaneExpandedPayload { 96 | path: string; 97 | expanded: boolean; 98 | } 99 | export interface ExecutePayload { 100 | type: "function" | "action"; 101 | runId?: string; 102 | name: string; 103 | args: any[]; 104 | } 105 | export interface Actions { 106 | logInit(payload: LogInitPayload): any; 107 | logMessage(payload: LogMessagePayload): any; 108 | logCallStart(payload: LogCallStartPayload): any; 109 | logCallEnd(payload: LogCallEndPayload): any; 110 | toggleRun(run: string): any; 111 | toggleEvent(payload: ToggleEventPayload): any; 112 | toggleCollapseRepeatingEvents(): any; 113 | setDetailsPaneExpanded(payload: SetDetailsPaneExpandedPayload): any; 114 | showPane(shown: boolean): any; 115 | setPaneDisplay(paneDisplay: PaneDisplay): any; 116 | setValueDisplay(valueDisplay: ValueDisplay): any; 117 | select(action: SelectedEvent | null): any; 118 | timeTravel(action: SelectedEvent): any; 119 | execute(payload: ExecutePayload): any; 120 | deleteRun(id: string): any; 121 | setCallOverviewText(text: string): any; 122 | } 123 | export declare const injectedSetState = "$__SET_STATE"; 124 | -------------------------------------------------------------------------------- /dist/src/components/CallOverviewDetailsPane.d.ts: -------------------------------------------------------------------------------- 1 | import { State, Actions, ActionEvent, FunctionEvent } from "../api"; 2 | import "./CallOverviewDetailsPane.scss"; 3 | export interface CallOverviewDetailsPaneProps { 4 | state: State; 5 | actions: Actions; 6 | event: ActionEvent | FunctionEvent; 7 | } 8 | export declare function CallOverviewDetailsPane(props: CallOverviewDetailsPaneProps): JSX.Element; 9 | -------------------------------------------------------------------------------- /dist/src/components/DebugPane.d.ts: -------------------------------------------------------------------------------- 1 | import { State, Actions } from "../api"; 2 | import "./DebugPane.scss"; 3 | export interface DebugPaneProps { 4 | state: State; 5 | actions: Actions; 6 | } 7 | export declare function DebugPane(props: DebugPaneProps): JSX.Element; 8 | -------------------------------------------------------------------------------- /dist/src/components/DebugPaneContent.d.ts: -------------------------------------------------------------------------------- 1 | import "./DebugPaneContent.scss"; 2 | import { State, Actions } from "../api"; 3 | export interface DebugPaneContentProps { 4 | state: State; 5 | actions: Actions; 6 | } 7 | export declare function DebugPaneContent(props: DebugPaneContentProps): JSX.Element; 8 | -------------------------------------------------------------------------------- /dist/src/components/DebugPaneToolbar.d.ts: -------------------------------------------------------------------------------- 1 | import "./DebugPaneToolbar.scss"; 2 | import { State, Actions } from "../api"; 3 | export interface DebugPaneToolbarProps { 4 | state: State; 5 | actions: Actions; 6 | } 7 | export declare function DebugPaneToolbar(props: DebugPaneToolbarProps): JSX.Element; 8 | -------------------------------------------------------------------------------- /dist/src/components/DebuggerOptions.d.ts: -------------------------------------------------------------------------------- 1 | import "./DebuggerOptions.scss"; 2 | import { State, Actions } from "../api"; 3 | export interface DebuggerOptionsProps { 4 | state: State; 5 | actions: Actions; 6 | } 7 | export declare function DebuggerOptions(props: DebuggerOptionsProps): JSX.Element; 8 | -------------------------------------------------------------------------------- /dist/src/components/Icon.d.ts: -------------------------------------------------------------------------------- 1 | import "./Icon.scss"; 2 | export declare type IconName = "caret-right" | "caret-bottom" | "cross" | "empty"; 3 | export interface IconProps { 4 | name: IconName; 5 | class?: string; 6 | onclick?: any; 7 | } 8 | export declare function Icon(props: IconProps): JSX.Element; 9 | -------------------------------------------------------------------------------- /dist/src/components/ObjectDetailsPane.d.ts: -------------------------------------------------------------------------------- 1 | import { State, Actions } from "../api"; 2 | import "./ObjectDetailsPane.scss"; 3 | export interface ObjectDetailsPaneProps { 4 | state: State; 5 | actions: Actions; 6 | } 7 | export declare function ObjectDetailsPane(props: ObjectDetailsPaneProps): JSX.Element; 8 | -------------------------------------------------------------------------------- /dist/src/components/ObjectView.d.ts: -------------------------------------------------------------------------------- 1 | import "./ObjectView.scss"; 2 | export interface ObjectViewProps { 3 | value: any; 4 | expanded(path: string, expanded?: boolean): boolean; 5 | } 6 | export declare function ObjectView(props: ObjectViewProps): JSX.Element; 7 | -------------------------------------------------------------------------------- /dist/src/components/RunEvent.d.ts: -------------------------------------------------------------------------------- 1 | import "./RunEvent.scss"; 2 | import { State, Actions, Run, AppEvent } from "../api"; 3 | export interface RunEventProps { 4 | state: State; 5 | actions: Actions; 6 | run: Run; 7 | event: AppEvent; 8 | events: string[]; 9 | indexInList: number; 10 | } 11 | export declare function RunEvent(props: RunEventProps): any; 12 | -------------------------------------------------------------------------------- /dist/src/components/RunEventList.d.ts: -------------------------------------------------------------------------------- 1 | import { State, Actions, Run } from "../api"; 2 | import "./RunEventList.scss"; 3 | export interface RunEventListProps { 4 | state: State; 5 | actions: Actions; 6 | run: Run; 7 | events: string[]; 8 | } 9 | export declare function RunEventList(props: RunEventListProps): any; 10 | -------------------------------------------------------------------------------- /dist/src/components/RunsPane.d.ts: -------------------------------------------------------------------------------- 1 | import "./RunsPane.scss"; 2 | import { State, Actions, Run } from "../api"; 3 | export interface RunsPaneProps { 4 | state: State; 5 | actions: Actions; 6 | runs: Run[]; 7 | } 8 | export declare function RunsPane(props: RunsPaneProps): JSX.Element; 9 | -------------------------------------------------------------------------------- /dist/src/components/RunsPaneItem.d.ts: -------------------------------------------------------------------------------- 1 | import "./RunsPaneItem.scss"; 2 | import { State, Actions, Run } from "../api"; 3 | export interface RunsPaneItemProps { 4 | state: State; 5 | actions: Actions; 6 | run: Run; 7 | current: boolean; 8 | } 9 | export declare function RunsPaneItem(props: RunsPaneItemProps): JSX.Element; 10 | -------------------------------------------------------------------------------- /dist/src/components/TogglePaneButton.d.ts: -------------------------------------------------------------------------------- 1 | import { State, Actions } from "../api"; 2 | import "./TogglePaneButton.scss"; 3 | export interface TogglePaneButtonProps { 4 | state: State; 5 | actions: Actions; 6 | } 7 | export declare function TogglePaneButton(props: TogglePaneButtonProps): JSX.Element; 8 | -------------------------------------------------------------------------------- /dist/src/components/index.d.ts: -------------------------------------------------------------------------------- 1 | import "./index.scss"; 2 | export * from "./DebugPane"; 3 | export * from "./TogglePaneButton"; 4 | -------------------------------------------------------------------------------- /dist/src/debug.d.ts: -------------------------------------------------------------------------------- 1 | export declare function debug(nameOrValue: T | string, value?: T): T; 2 | -------------------------------------------------------------------------------- /dist/src/debuggedFunctions.d.ts: -------------------------------------------------------------------------------- 1 | export declare function registerDebuggedFunction(name: string, fn: any): void; 2 | export declare function isRegistered(name: string): boolean; 3 | export declare function getRegistered(name: string): any; 4 | -------------------------------------------------------------------------------- /dist/src/devtools.d.ts: -------------------------------------------------------------------------------- 1 | import { Actions } from "./api"; 2 | export interface View { 3 | (state: any, actions: any): any; 4 | } 5 | export interface HypperApp { 6 | (state: any, actions: any, view: View, container: Element | null): any; 7 | } 8 | export declare function getDevtoolsApp(): Actions; 9 | export declare function devtools(app: App): App; 10 | export default devtools; 11 | -------------------------------------------------------------------------------- /dist/src/enhanceActions.d.ts: -------------------------------------------------------------------------------- 1 | import { Actions } from "./api"; 2 | export declare function enhanceActions(hoaActions: Actions, runId: string, actions: any, prefix?: string): any; 3 | export default enhanceActions; 4 | -------------------------------------------------------------------------------- /dist/src/immutable.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Path: Array 3 | */ 4 | export declare type Path = Array; 5 | /** 6 | * Get the value at the given path in the given target, or undefined if path doesn't exists. 7 | */ 8 | export declare function get(target: T, path: Path): R; 9 | /** 10 | * Immutable set: set the value at the given path in the given target and returns a new target. 11 | * Creates the necessary objects/arrays if the path doesn't exist. 12 | */ 13 | export declare function set(target: T, path: Path, value: V): R; 14 | /** 15 | * Immutable merge: merges the given value and the existing value (if any) at the path in the target using Object.assign() and return a new target. 16 | * Creates the necessary objects/arrays if the path doesn't exist. 17 | */ 18 | export declare function merge(target: T, path: Path, value: V): R; 19 | -------------------------------------------------------------------------------- /dist/src/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./debug"; 2 | import devtools from "./devtools"; 3 | export { devtools }; 4 | -------------------------------------------------------------------------------- /dist/src/selectors.d.ts: -------------------------------------------------------------------------------- 1 | import { AppEvent, State, Run, SelectedEvent, ActionEvent, FunctionEvent } from "./api"; 2 | export declare function isValueDisplayExpanded(state: State, path: string): boolean; 3 | export declare function getLatestRunId(state: State): string; 4 | export declare function getRun(state: State, runId: string): Run; 5 | export declare function isSelectedEvent(state: State, event: AppEvent): boolean; 6 | export declare function getSelectedEvent(state: State, event?: SelectedEvent): AppEvent | null; 7 | export declare function getLatestRun(state: State): Run; 8 | export declare function canTravelToSelectedEvent(state: State): boolean; 9 | export declare function getCallText(event: ActionEvent | FunctionEvent): string; 10 | export declare function getArgsFromCallText(event: ActionEvent | FunctionEvent, text: string): any[]; 11 | -------------------------------------------------------------------------------- /dist/src/state.d.ts: -------------------------------------------------------------------------------- 1 | import { State } from "./api"; 2 | export declare const state: State; 3 | -------------------------------------------------------------------------------- /dist/src/utils.d.ts: -------------------------------------------------------------------------------- 1 | export declare const guid: () => any; 2 | export declare function truncate(value: string, maxLength?: number): string; 3 | export declare function getErrorMessage(error: any): string; 4 | -------------------------------------------------------------------------------- /dist/src/valueDisplay.d.ts: -------------------------------------------------------------------------------- 1 | import { AppEvent, StringMap, ValueDisplay } from "./api"; 2 | export declare const VALUE_DISPLAYS: StringMap; 3 | export declare function sanitizeValueDisplay(valueDisplay: ValueDisplay, event: AppEvent): ValueDisplay; 4 | -------------------------------------------------------------------------------- /dist/src/view.d.ts: -------------------------------------------------------------------------------- 1 | import { State, Actions } from "./api"; 2 | export declare function view(state: State, actions: Actions): JSX.Element; 3 | -------------------------------------------------------------------------------- /examples/circular-state.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Circular references in state 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |  Back to index 19 | 20 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /examples/counter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Counter example with debugger 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |  Back to index 19 | 20 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/debug-function.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Counter example debug function 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |  Back to index 19 | 20 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/error-in-action.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Error in an action 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |  Back to index 19 | 20 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /examples/error-in-function.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Error in a function 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |  Back to index 19 | 20 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/hyperapp.js: -------------------------------------------------------------------------------- 1 | ;(function(global, factory) { 2 | typeof exports === "object" && typeof module !== "undefined" 3 | ? factory(exports) 4 | : typeof define === "function" && define.amd 5 | ? define(["exports"], factory) 6 | : factory((global.hyperapp = {})) 7 | })(this, function(exports) { 8 | "use strict" 9 | 10 | function h(name, attributes) { 11 | var rest = [] 12 | var children = [] 13 | var length = arguments.length 14 | 15 | while (length-- > 2) rest.push(arguments[length]) 16 | 17 | while (rest.length) { 18 | var node = rest.pop() 19 | if (node && node.pop) { 20 | for (length = node.length; length--; ) { 21 | rest.push(node[length]) 22 | } 23 | } else if (node != null && node !== true && node !== false) { 24 | children.push(node) 25 | } 26 | } 27 | 28 | return typeof name === "function" 29 | ? name(attributes || {}, children) 30 | : { 31 | nodeName: name, 32 | attributes: attributes || {}, 33 | children: children, 34 | key: attributes && attributes.key 35 | } 36 | } 37 | 38 | function app(state, actions, view, container) { 39 | var map = [].map 40 | var rootElement = (container && container.children[0]) || null 41 | var oldNode = rootElement && recycleElement(rootElement) 42 | var lifecycle = [] 43 | var skipRender 44 | var isRecycling = true 45 | var globalState = clone(state) 46 | var wiredActions = wireStateToActions([], globalState, clone(actions)) 47 | 48 | scheduleRender() 49 | 50 | return wiredActions 51 | 52 | function recycleElement(element) { 53 | return { 54 | nodeName: element.nodeName.toLowerCase(), 55 | attributes: {}, 56 | children: map.call(element.childNodes, function(element) { 57 | return element.nodeType === 3 // Node.TEXT_NODE 58 | ? element.nodeValue 59 | : recycleElement(element) 60 | }) 61 | } 62 | } 63 | 64 | function resolveNode(node) { 65 | return typeof node === "function" 66 | ? resolveNode(node(globalState, wiredActions)) 67 | : node != null 68 | ? node 69 | : "" 70 | } 71 | 72 | function render() { 73 | skipRender = !skipRender 74 | 75 | var node = resolveNode(view) 76 | 77 | if (container && !skipRender) { 78 | rootElement = patch(container, rootElement, oldNode, (oldNode = node)) 79 | } 80 | 81 | isRecycling = false 82 | 83 | while (lifecycle.length) lifecycle.pop()() 84 | } 85 | 86 | function scheduleRender() { 87 | if (!skipRender) { 88 | skipRender = true 89 | setTimeout(render) 90 | } 91 | } 92 | 93 | function clone(target, source) { 94 | var out = {} 95 | 96 | for (var i in target) out[i] = target[i] 97 | for (var i in source) out[i] = source[i] 98 | 99 | return out 100 | } 101 | 102 | function setPartialState(path, value, source) { 103 | var target = {} 104 | if (path.length) { 105 | target[path[0]] = 106 | path.length > 1 107 | ? setPartialState(path.slice(1), value, source[path[0]]) 108 | : value 109 | return clone(source, target) 110 | } 111 | return value 112 | } 113 | 114 | function getPartialState(path, source) { 115 | var i = 0 116 | while (i < path.length) { 117 | source = source[path[i++]] 118 | } 119 | return source 120 | } 121 | 122 | function wireStateToActions(path, state, actions) { 123 | for (var key in actions) { 124 | typeof actions[key] === "function" 125 | ? (function(key, action) { 126 | actions[key] = function(data) { 127 | var result = action(data) 128 | 129 | if (typeof result === "function") { 130 | result = result(getPartialState(path, globalState), actions) 131 | } 132 | 133 | if ( 134 | result && 135 | result !== (state = getPartialState(path, globalState)) && 136 | !result.then // !isPromise 137 | ) { 138 | scheduleRender( 139 | (globalState = setPartialState( 140 | path, 141 | clone(state, result), 142 | globalState 143 | )) 144 | ) 145 | } 146 | 147 | return result 148 | } 149 | })(key, actions[key]) 150 | : wireStateToActions( 151 | path.concat(key), 152 | (state[key] = clone(state[key])), 153 | (actions[key] = clone(actions[key])) 154 | ) 155 | } 156 | 157 | return actions 158 | } 159 | 160 | function getKey(node) { 161 | return node ? node.key : null 162 | } 163 | 164 | function eventListener(event) { 165 | return event.currentTarget.events[event.type](event) 166 | } 167 | 168 | function updateAttribute(element, name, value, oldValue, isSvg) { 169 | if (name === "key") { 170 | } else if (name === "style") { 171 | for (var i in clone(oldValue, value)) { 172 | var style = value == null || value[i] == null ? "" : value[i] 173 | if (i[0] === "-") { 174 | element[name].setProperty(i, style) 175 | } else { 176 | element[name][i] = style 177 | } 178 | } 179 | } else { 180 | if (name[0] === "o" && name[1] === "n") { 181 | name = name.slice(2) 182 | 183 | if (element.events) { 184 | if (!oldValue) oldValue = element.events[name] 185 | } else { 186 | element.events = {} 187 | } 188 | 189 | element.events[name] = value 190 | 191 | if (value) { 192 | if (!oldValue) { 193 | element.addEventListener(name, eventListener) 194 | } 195 | } else { 196 | element.removeEventListener(name, eventListener) 197 | } 198 | } else if (name in element && name !== "list" && !isSvg) { 199 | element[name] = value == null ? "" : value 200 | } else if (value != null && value !== false) { 201 | element.setAttribute(name, value) 202 | } 203 | 204 | if (value == null || value === false) { 205 | element.removeAttribute(name) 206 | } 207 | } 208 | } 209 | 210 | function createElement(node, isSvg) { 211 | var element = 212 | typeof node === "string" || typeof node === "number" 213 | ? document.createTextNode(node) 214 | : (isSvg = isSvg || node.nodeName === "svg") 215 | ? document.createElementNS( 216 | "http://www.w3.org/2000/svg", 217 | node.nodeName 218 | ) 219 | : document.createElement(node.nodeName) 220 | 221 | var attributes = node.attributes 222 | if (attributes) { 223 | if (attributes.oncreate) { 224 | lifecycle.push(function() { 225 | attributes.oncreate(element) 226 | }) 227 | } 228 | 229 | for (var i = 0; i < node.children.length; i++) { 230 | element.appendChild( 231 | createElement( 232 | (node.children[i] = resolveNode(node.children[i])), 233 | isSvg 234 | ) 235 | ) 236 | } 237 | 238 | for (var name in attributes) { 239 | updateAttribute(element, name, attributes[name], null, isSvg) 240 | } 241 | } 242 | 243 | return element 244 | } 245 | 246 | function updateElement(element, oldAttributes, attributes, isSvg) { 247 | for (var name in clone(oldAttributes, attributes)) { 248 | if ( 249 | attributes[name] !== 250 | (name === "value" || name === "checked" 251 | ? element[name] 252 | : oldAttributes[name]) 253 | ) { 254 | updateAttribute( 255 | element, 256 | name, 257 | attributes[name], 258 | oldAttributes[name], 259 | isSvg 260 | ) 261 | } 262 | } 263 | 264 | var cb = isRecycling ? attributes.oncreate : attributes.onupdate 265 | if (cb) { 266 | lifecycle.push(function() { 267 | cb(element, oldAttributes) 268 | }) 269 | } 270 | } 271 | 272 | function removeChildren(element, node) { 273 | var attributes = node.attributes 274 | if (attributes) { 275 | for (var i = 0; i < node.children.length; i++) { 276 | removeChildren(element.childNodes[i], node.children[i]) 277 | } 278 | 279 | if (attributes.ondestroy) { 280 | attributes.ondestroy(element) 281 | } 282 | } 283 | return element 284 | } 285 | 286 | function removeElement(parent, element, node) { 287 | function done() { 288 | parent.removeChild(removeChildren(element, node)) 289 | } 290 | 291 | var cb = node.attributes && node.attributes.onremove 292 | if (cb) { 293 | cb(element, done) 294 | } else { 295 | done() 296 | } 297 | } 298 | 299 | function patch(parent, element, oldNode, node, isSvg) { 300 | if (node === oldNode) { 301 | } else if (oldNode == null || oldNode.nodeName !== node.nodeName) { 302 | var newElement = createElement(node, isSvg) 303 | parent.insertBefore(newElement, element) 304 | 305 | if (oldNode != null) { 306 | removeElement(parent, element, oldNode) 307 | } 308 | 309 | element = newElement 310 | } else if (oldNode.nodeName == null) { 311 | element.nodeValue = node 312 | } else { 313 | updateElement( 314 | element, 315 | oldNode.attributes, 316 | node.attributes, 317 | (isSvg = isSvg || node.nodeName === "svg") 318 | ) 319 | 320 | var oldKeyed = {} 321 | var newKeyed = {} 322 | var oldElements = [] 323 | var oldChildren = oldNode.children 324 | var children = node.children 325 | 326 | for (var i = 0; i < oldChildren.length; i++) { 327 | oldElements[i] = element.childNodes[i] 328 | 329 | var oldKey = getKey(oldChildren[i]) 330 | if (oldKey != null) { 331 | oldKeyed[oldKey] = [oldElements[i], oldChildren[i]] 332 | } 333 | } 334 | 335 | var i = 0 336 | var k = 0 337 | 338 | while (k < children.length) { 339 | var oldKey = getKey(oldChildren[i]) 340 | var newKey = getKey((children[k] = resolveNode(children[k]))) 341 | 342 | if (newKeyed[oldKey]) { 343 | i++ 344 | continue 345 | } 346 | 347 | if (newKey != null && newKey === getKey(oldChildren[i + 1])) { 348 | if (oldKey == null) { 349 | removeElement(element, oldElements[i], oldChildren[i]) 350 | } 351 | i++ 352 | continue 353 | } 354 | 355 | if (newKey == null || isRecycling) { 356 | if (oldKey == null) { 357 | patch(element, oldElements[i], oldChildren[i], children[k], isSvg) 358 | k++ 359 | } 360 | i++ 361 | } else { 362 | var keyedNode = oldKeyed[newKey] || [] 363 | 364 | if (oldKey === newKey) { 365 | patch(element, keyedNode[0], keyedNode[1], children[k], isSvg) 366 | i++ 367 | } else if (keyedNode[0]) { 368 | patch( 369 | element, 370 | element.insertBefore(keyedNode[0], oldElements[i]), 371 | keyedNode[1], 372 | children[k], 373 | isSvg 374 | ) 375 | } else { 376 | patch(element, oldElements[i], null, children[k], isSvg) 377 | } 378 | 379 | newKeyed[newKey] = children[k] 380 | k++ 381 | } 382 | } 383 | 384 | while (i < oldChildren.length) { 385 | if (getKey(oldChildren[i]) == null) { 386 | removeElement(element, oldElements[i], oldChildren[i]) 387 | } 388 | i++ 389 | } 390 | 391 | for (var i in oldKeyed) { 392 | if (!newKeyed[i]) { 393 | removeElement(element, oldKeyed[i][0], oldKeyed[i][1]) 394 | } 395 | } 396 | } 397 | return element 398 | } 399 | } 400 | 401 | exports.h = h 402 | exports.app = app 403 | 404 | Object.defineProperty(exports, "__esModule", { value: true }) 405 | }) 406 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Devtools Examples 8 | 9 | 10 | 11 | 12 |

Devtools examples

13 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/long-names.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Counter example with debugger 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Note: this is example is meant to show how the devtools handles overflow, it is not meant to represent a functional/usefull 16 | app. 17 |

18 |
19 |
20 |
21 |  Back to index 22 | 23 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/nested-state.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Counter example with debugger 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |  Back to index 19 | 20 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /examples/todos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Counter example with debugger 8 | 9 | 10 | 11 | 12 | 13 | 45 | 46 | 47 | 48 |
49 |
50 |
51 |  Back to index 52 | 53 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperapp-devtools", 3 | "version": "0.3.0", 4 | "description": "Developer tools for Hyperapp projects", 5 | "keywords": [ 6 | "hyperapp", 7 | "devtools", 8 | "debug" 9 | ], 10 | "author": "Anthony Ferrando ", 11 | "license": "MIT", 12 | "main": "dist/hyperapp-devtools.js", 13 | "minified:main": "dist/hyperapp-devtools.min.js", 14 | "jsnext:main": "dist/hyperapp-devtools.es.js", 15 | "module": "dist/hyperapp-devtools.es.js", 16 | "typings": "dist/src/index.d.ts", 17 | "scripts": { 18 | "clean": "rimraf dist .rpt2_cache", 19 | "start": "rollup -c -w --serve", 20 | "build": "npm run clean && npm run build:main && npm run build:min && npm run build:es", 21 | "build:main": "rollup -c && rimraf .rpt2_cache", 22 | "build:min": "rollup -c --min && rimraf .rpt2_cache", 23 | "build:es": "rollup -c --es && rimraf .rpt2_cache", 24 | "release": "npm run build && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish" 25 | }, 26 | "dependencies": { 27 | "codemirror": "^5.37.0", 28 | "hyperapp": "^1.2.5" 29 | }, 30 | "devDependencies": { 31 | "minimist": "^1.2.0", 32 | "node-sass": "4.9.0", 33 | "rimraf": "2.6.2", 34 | "rollup": "0.50.0", 35 | "rollup-plugin-commonjs": "8.2.6", 36 | "rollup-plugin-node-resolve": "3.0.0", 37 | "rollup-plugin-postcss": "^1.4.0", 38 | "rollup-plugin-serve": "0.4.2", 39 | "rollup-plugin-typescript2": "0.8.0", 40 | "rollup-plugin-uglify": "2.0.1", 41 | "typescript": "^2.7.2" 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "git+https://github.com/hyperstart/hyperapp-devtools.git" 46 | }, 47 | "bugs": { 48 | "url": "https://github.com/hyperstart/hyperapp-devtools/issues" 49 | }, 50 | "homepage": "https://github.com/hyperstart/hyperapp-devtools#readme", 51 | "prettier": { 52 | "semi": false 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | const minimist = require("minimist") 2 | 3 | const commonjs = require("rollup-plugin-commonjs") 4 | const nodeResolve = require("rollup-plugin-node-resolve") 5 | const typescript = require("rollup-plugin-typescript2") 6 | const uglify = require("rollup-plugin-uglify") 7 | const postcss = require("rollup-plugin-postcss") 8 | const serve = require("rollup-plugin-serve") 9 | 10 | const options = minimist(process.argv.slice(2), { 11 | boolean: ["min", "es", "serve"] 12 | }) 13 | 14 | const plugins = [ 15 | nodeResolve({ 16 | extensions: [".ts", ".js", ".json"], 17 | jsnext: true 18 | }), 19 | commonjs(), 20 | typescript({ 21 | clean: true, 22 | exclude: ["*.d.ts", "**/*.d.ts", "*.test.*", "**/*.test.*"] 23 | }), 24 | postcss({ 25 | plugins: [] 26 | }) 27 | ] 28 | if (options.min) { 29 | plugins.push(uglify()) 30 | } 31 | if (options.serve) { 32 | plugins.push( 33 | serve({ 34 | open: true, 35 | contentBase: ["examples", "dist"] 36 | }) 37 | ) 38 | } 39 | 40 | export default { 41 | input: "src/index.ts", 42 | output: { 43 | file: options.min 44 | ? "dist/hyperapp-devtools.min.js" 45 | : options.es 46 | ? "dist/hyperapp-devtools.es.js" 47 | : "dist/hyperapp-devtools.js", 48 | format: options.es ? "es" : "umd", 49 | name: "devtools", 50 | sourcemap: true 51 | }, 52 | plugins 53 | } 54 | -------------------------------------------------------------------------------- /src/actions/deleteRun.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const deleteRun = (id: string) => ( 4 | state: api.State 5 | ): Partial => { 6 | const runsById = { ...state.runsById } 7 | delete runsById[id] 8 | const runs = state.runs.filter(s => s !== id) 9 | return { runs, runsById } 10 | } 11 | -------------------------------------------------------------------------------- /src/actions/execute.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | import { get } from "../immutable" 3 | import { getRun } from "../selectors" 4 | import { getRegistered } from "../debuggedFunctions" 5 | 6 | function executeAction(payload: api.ExecutePayload, state: api.State) { 7 | const { runId, name, args } = payload 8 | 9 | const run = getRun(state, runId) 10 | const action = get(run.interop, name.split(".")) 11 | 12 | if (!action) throw new Error(`No action found with name "${name}".`) 13 | 14 | action(args[0]) 15 | } 16 | 17 | function executeFunction(payload: api.ExecutePayload, state: api.State) { 18 | const { name, args } = payload 19 | 20 | const fn = getRegistered(name) 21 | fn(...args) 22 | } 23 | 24 | export const execute = (payload: api.ExecutePayload) => (state: api.State) => { 25 | const { type } = payload 26 | 27 | if (type === "action") { 28 | executeAction(payload, state) 29 | } else { 30 | executeFunction(payload, state) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/actions/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./deleteRun" 2 | export * from "./execute" 3 | export * from "./logCallEnd" 4 | export * from "./logCallStart" 5 | export * from "./logInit" 6 | export * from "./logMessage" 7 | export * from "./select" 8 | export * from "./setCallOverviewText" 9 | export * from "./setDetailsPaneExpanded" 10 | export * from "./setPaneDisplay" 11 | export * from "./setValueDisplay" 12 | export * from "./showPane" 13 | export * from "./timeTravel" 14 | export * from "./toggleCollapseRepeatingEvents" 15 | export * from "./toggleEvent" 16 | export * from "./toggleRun" 17 | -------------------------------------------------------------------------------- /src/actions/logCallEnd.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | import { merge } from "../immutable" 3 | import { getLatestRunId, getCallText } from "../selectors" 4 | import { sanitizeValueDisplay } from "../valueDisplay" 5 | 6 | export const logCallEnd = (payload: api.LogCallEndPayload) => ( 7 | state: api.State 8 | ): Partial => { 9 | const { runId = getLatestRunId(state), eventId, result, error } = payload 10 | 11 | const runsById = { ...state.runsById } 12 | const run = { ...runsById[runId] } 13 | runsById[runId] = run 14 | 15 | run.eventsById = { ...run.eventsById } 16 | const event = { ...run.eventsById[eventId] } 17 | run.eventsById[eventId] = event 18 | let valueDisplay = state.valueDisplay 19 | // update the event 20 | if (event.type === "action" || event.type === "function") { 21 | if (result) { 22 | event.result = result 23 | 24 | if (event.type === "action" && !result.then) { 25 | // update the run's current state 26 | const path = event.name.split(".") 27 | path.pop() 28 | const stateAfter = merge(event.stateBefore, path, event.result) 29 | event.stateAfter = stateAfter 30 | run.currentState = stateAfter 31 | } 32 | } 33 | if (error) { 34 | event.error = error 35 | } 36 | } 37 | 38 | // update the current event of the run 39 | run.currentEvent = 40 | eventId === run.currentEvent ? event.parent : run.currentEvent 41 | 42 | const selectedEvent: api.SelectedEvent = { 43 | runId: run.id, 44 | eventId 45 | } 46 | 47 | valueDisplay = sanitizeValueDisplay(valueDisplay, event) 48 | const callOverviewText = getCallText(event as any) 49 | 50 | return { runsById, selectedEvent, valueDisplay, callOverviewText } 51 | } 52 | -------------------------------------------------------------------------------- /src/actions/logCallStart.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | import { getLatestRunId } from "../selectors" 3 | 4 | function getEvent( 5 | state: api.State, 6 | run: api.Run, 7 | payload: api.LogCallStartPayload 8 | ): api.AppEvent { 9 | const { args, eventId, name, runId, type } = payload 10 | if (type === "action") { 11 | return { 12 | type: "action", 13 | id: eventId, 14 | name, 15 | data: args && args.length > 0 ? args[0] : undefined, 16 | parent: run.currentEvent, 17 | children: [], 18 | collapsed: false, 19 | stateBefore: run.currentState 20 | } 21 | } 22 | 23 | return { 24 | type: "function", 25 | id: eventId, 26 | name, 27 | args, 28 | children: [], 29 | collapsed: false, 30 | parent: run.currentEvent 31 | } 32 | } 33 | 34 | export const logCallStart = (payload: api.LogCallStartPayload) => ( 35 | state: api.State 36 | ): Partial => { 37 | const { runId = getLatestRunId(state), eventId } = payload 38 | const runsById = { ...state.runsById } 39 | const run = { ...runsById[runId] } 40 | runsById[runId] = run 41 | run.eventsById[eventId] = getEvent(state, run, payload) 42 | const parentId = run.currentEvent 43 | if (parentId) { 44 | // append the event to the parent 45 | const parent = { ...run.eventsById[parentId] } 46 | run.eventsById[parentId] = parent 47 | parent.children = parent.children.concat(eventId) 48 | } else { 49 | // append the event to the run 50 | run.events = run.events.concat(eventId) 51 | } 52 | run.currentEvent = eventId 53 | 54 | return { runsById } 55 | } 56 | -------------------------------------------------------------------------------- /src/actions/logInit.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const logInit = (payload: api.LogInitPayload) => ( 4 | state: api.State 5 | ): Partial => { 6 | const { runId, interop, timestamp } = payload 7 | const runs = state.runs.concat(runId) 8 | const runsById = { ...state.runsById } 9 | const initEvent: api.InitEvent = { 10 | id: runId, 11 | type: "init", 12 | name: "Initial State", 13 | state: payload.state 14 | } 15 | runsById[runId] = { 16 | id: runId, 17 | events: [runId], 18 | eventsById: { [runId]: initEvent }, 19 | currentState: payload.state, 20 | timestamp, 21 | interop, 22 | collapsed: false 23 | } 24 | return { 25 | runs, 26 | runsById, 27 | selectedEvent: { 28 | runId, 29 | eventId: runId 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/actions/logMessage.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const logMessage = (payload: api.LogMessagePayload) => ( 4 | state: api.State 5 | ): Partial => { 6 | const { runId, eventId, level, message } = payload 7 | 8 | const runsById = { ...state.runsById } 9 | const run = { ...runsById[runId] } 10 | runsById[runId] = run 11 | run.events = run.events.concat(eventId) 12 | run.eventsById = { 13 | ...run.eventsById, 14 | [eventId]: { 15 | type: "message", 16 | level, 17 | message, 18 | name: level, 19 | id: eventId, 20 | parent: run.currentEvent 21 | } 22 | } 23 | 24 | return { 25 | runsById, 26 | selectedEvent: { 27 | runId, 28 | eventId 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/actions/select.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | import { getSelectedEvent, getCallText } from "../selectors" 3 | import { sanitizeValueDisplay } from "../valueDisplay" 4 | 5 | function getCallOverviewText(state: api.State, event: api.AppEvent): string { 6 | if (event.type === "action" || event.type === "function") { 7 | return getCallText(event) 8 | } 9 | return state.callOverviewText 10 | } 11 | 12 | export const select = (selectedEvent: api.SelectedEvent | null) => ( 13 | state: api.State 14 | ): Partial => { 15 | const event = getSelectedEvent(state, selectedEvent) 16 | 17 | return { 18 | selectedEvent, 19 | valueDisplay: sanitizeValueDisplay(state.valueDisplay, event), 20 | callOverviewText: getCallOverviewText(state, event) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/actions/setCallOverviewText.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const setCallOverviewText = (callOverviewText: string) => ( 4 | state: api.State 5 | ): Partial => { 6 | return { callOverviewText } 7 | } 8 | -------------------------------------------------------------------------------- /src/actions/setDetailsPaneExpanded.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | import { set } from "../immutable" 3 | 4 | export const setDetailsPaneExpanded = ( 5 | payload: api.SetDetailsPaneExpandedPayload 6 | ) => (state: api.State): Partial => { 7 | const { path, expanded } = payload 8 | return { 9 | detailsPaneExpandedPaths: { 10 | ...state.detailsPaneExpandedPaths, 11 | [path]: expanded 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/actions/setPaneDisplay.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const setPaneDisplay = (paneDisplay: api.PaneDisplay) => ( 4 | state: api.State 5 | ): Partial => ({ 6 | paneDisplay 7 | }) 8 | -------------------------------------------------------------------------------- /src/actions/setValueDisplay.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const setValueDisplay = (valueDisplay: api.ValueDisplay) => ( 4 | state: api.State 5 | ): Partial => ({ 6 | valueDisplay 7 | }) 8 | -------------------------------------------------------------------------------- /src/actions/showPane.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const showPane = (paneShown: boolean) => ( 4 | state: api.State 5 | ): Partial => ({ 6 | paneShown 7 | }) 8 | -------------------------------------------------------------------------------- /src/actions/timeTravel.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | import { getSelectedEvent, getRun } from "../selectors" 3 | 4 | export const timeTravel = (selectedEvent: api.SelectedEvent) => ( 5 | state: api.State 6 | ) => { 7 | const run = getRun(state, selectedEvent.runId) 8 | if (!run) { 9 | return 10 | } 11 | 12 | const event = getSelectedEvent(state, selectedEvent) 13 | if (event) { 14 | if (event.type === "action" && event.stateAfter) { 15 | run.interop[api.injectedSetState](event.stateAfter) 16 | return 17 | } 18 | if (event.type === "init") { 19 | run.interop[api.injectedSetState](event.state) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/actions/toggleCollapseRepeatingEvents.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const toggleCollapseRepeatingEvents = () => ( 4 | state: api.State 5 | ): Partial => ({ 6 | collapseRepeatingEvents: !state.collapseRepeatingEvents 7 | }) 8 | -------------------------------------------------------------------------------- /src/actions/toggleEvent.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | import { get, set } from "../immutable" 3 | 4 | export const toggleEvent = (payload: api.ToggleEventPayload) => ( 5 | state: api.State 6 | ): Partial => { 7 | const { runId, eventId } = payload 8 | 9 | // const collapsed = state.runsById[runId].eventsById[eventId].collapsed 10 | const collapsed = get(state.runsById, [ 11 | runId, 12 | "eventsById", 13 | eventId, 14 | "collapsed" 15 | ]) 16 | // state.runsById[runId].eventsById[eventId].collapsed = !collapsed 17 | return { 18 | runsById: set( 19 | state.runsById, 20 | [runId, "eventsById", eventId, "collapsed"], 21 | !collapsed 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/actions/toggleRun.ts: -------------------------------------------------------------------------------- 1 | import * as api from "../api" 2 | 3 | export const toggleRun = (id: string) => (state: api.State) => { 4 | const runsById = { ...state.runsById } 5 | runsById[id] = { ...runsById[id], collapsed: !runsById[id].collapsed } 6 | return { runsById } 7 | } 8 | -------------------------------------------------------------------------------- /src/api.ts: -------------------------------------------------------------------------------- 1 | export interface StringMap { 2 | [key: string]: V 3 | } 4 | 5 | export type EventType = "function" | "action" | "init" | "message" 6 | 7 | export type AppEvent = InitEvent | ActionEvent | FunctionEvent | MessageEvent 8 | 9 | export interface BaseEvent { 10 | id: string 11 | type: EventType 12 | name: string 13 | children?: string[] 14 | collapsed?: boolean 15 | parent?: string 16 | } 17 | 18 | export interface InitEvent extends BaseEvent { 19 | type: "init" 20 | state: any 21 | } 22 | 23 | export interface ActionEvent extends BaseEvent { 24 | type: "action" 25 | data: any 26 | result?: any 27 | error?: any 28 | stateBefore: any 29 | stateAfter?: any 30 | } 31 | 32 | export interface FunctionEvent extends BaseEvent { 33 | type: "function" 34 | args: any[] 35 | result?: any 36 | error?: any 37 | returnedBy?: string 38 | } 39 | 40 | export type LogLevel = "info" | "warn" | "error" 41 | 42 | export interface MessageEvent extends BaseEvent { 43 | type: "message" 44 | level: LogLevel 45 | message: any 46 | } 47 | 48 | export interface Run { 49 | id: string 50 | events: string[] 51 | eventsById: StringMap 52 | timestamp: number 53 | collapsed: boolean 54 | currentEvent?: string 55 | currentState?: any 56 | interop: any 57 | } 58 | 59 | export interface SelectedEvent { 60 | runId: string 61 | eventId: string 62 | } 63 | 64 | export type PaneDisplay = "fullscreen" | "right" | "bottom" 65 | 66 | export type ValueDisplay = 67 | | "state" 68 | | "result" 69 | | "args" 70 | | "message" 71 | | "data" 72 | | "call-overview" 73 | | "debugger-state" 74 | 75 | export interface State { 76 | runs: string[] 77 | runsById: StringMap 78 | selectedEvent: SelectedEvent | null 79 | collapseRepeatingEvents: boolean 80 | valueDisplay: ValueDisplay 81 | detailsPaneExpandedPaths: StringMap 82 | paneDisplay: PaneDisplay 83 | paneShown: boolean 84 | callOverviewText?: string 85 | } 86 | 87 | // # Actions 88 | 89 | export interface LogInitPayload { 90 | runId: string 91 | timestamp: number 92 | state: any 93 | interop: any 94 | } 95 | 96 | export interface LogMessagePayload { 97 | runId: string 98 | eventId: string 99 | level: LogLevel 100 | message: any 101 | } 102 | 103 | export interface LogCallStartPayload { 104 | // use latest if not set. 105 | runId?: string 106 | eventId: string 107 | type: "function" | "action" 108 | name: string 109 | args: any[] 110 | } 111 | 112 | export interface LogCallEndPayload { 113 | runId?: string 114 | eventId: string 115 | result?: any 116 | error?: any 117 | } 118 | 119 | export interface ToggleEventPayload { 120 | runId: string 121 | eventId: string 122 | } 123 | 124 | export interface SetDetailsPaneExpandedPayload { 125 | path: string 126 | expanded: boolean 127 | } 128 | 129 | export interface ExecutePayload { 130 | type: "function" | "action" 131 | runId?: string 132 | name: string 133 | args: any[] 134 | } 135 | 136 | export interface Actions { 137 | logInit(payload: LogInitPayload) 138 | logMessage(payload: LogMessagePayload) 139 | logCallStart(payload: LogCallStartPayload) 140 | logCallEnd(payload: LogCallEndPayload) 141 | toggleRun(run: string) 142 | toggleEvent(payload: ToggleEventPayload) 143 | toggleCollapseRepeatingEvents() 144 | setDetailsPaneExpanded(payload: SetDetailsPaneExpandedPayload) 145 | showPane(shown: boolean) 146 | setPaneDisplay(paneDisplay: PaneDisplay) 147 | setValueDisplay(valueDisplay: ValueDisplay) 148 | select(action: SelectedEvent | null) 149 | timeTravel(action: SelectedEvent) 150 | execute(payload: ExecutePayload) 151 | deleteRun(id: string) 152 | setCallOverviewText(text: string) 153 | } 154 | 155 | export const injectedSetState = "$__SET_STATE" 156 | -------------------------------------------------------------------------------- /src/components/CallOverviewDetailsPane.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | .call-overview-details-pane { 4 | display: flex; 5 | flex-direction: column; 6 | padding: 0.3rem; 7 | min-height: 0; 8 | 9 | h3 { 10 | margin: 0.3rem 0rem; 11 | } 12 | 13 | .call-section { 14 | display: flex; 15 | flex-direction: column; 16 | flex: 0 0 11rem; 17 | padding: 0.3rem; 18 | 19 | .call-text-area { 20 | flex: 0 0 7rem; 21 | } 22 | 23 | .call-text-action { 24 | display: flex; 25 | justify-content: space-between; 26 | 27 | .call-text-error { 28 | font-size: 0.8rem; 29 | color: $text-error-color; 30 | } 31 | } 32 | } 33 | 34 | .response-section { 35 | display: flex; 36 | flex-direction: column; 37 | flex: 1 1 100%; 38 | min-height: 0; 39 | 40 | .result-pane { 41 | display: flex; 42 | flex-direction: column; 43 | border: 1px solid $border-color; 44 | flex: 1 1 100%; 45 | min-height: 0; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/components/CallOverviewDetailsPane.tsx: -------------------------------------------------------------------------------- 1 | import { h } from "hyperapp" 2 | 3 | import { State, Actions, ActionEvent, FunctionEvent } from "../api" 4 | import { 5 | isValueDisplayExpanded, 6 | getCallText, 7 | getArgsFromCallText 8 | } from "../selectors" 9 | import { ObjectView } from "./ObjectView" 10 | 11 | import "./CallOverviewDetailsPane.scss" 12 | import { getErrorMessage } from "../utils" 13 | 14 | interface CallProps extends CallOverviewDetailsPaneProps { 15 | args?: any[] 16 | error?: string 17 | } 18 | 19 | // # getCallProps 20 | 21 | function getCallProps(props: CallOverviewDetailsPaneProps): CallProps { 22 | const { state, actions, event } = props 23 | try { 24 | const args = getArgsFromCallText(event, state.callOverviewText) 25 | return { state, actions, event, args } 26 | } catch (e) { 27 | const error = getErrorMessage(e) 28 | return { state, actions, event, error } 29 | } 30 | } 31 | 32 | // # CallTextArea 33 | 34 | function CallTextArea(props: CallProps) { 35 | const { state, actions, event } = props 36 | return ( 37 |