Tera Documentation
{
"config": {
"base_url": "/",
"mode": "build",
"title": "Phosphor",
"description": "Things we learned while building Phosphor",
"languages": {},
"default_language": "en",
"generate_feed": true,
"generate_feeds": true,
"feed_filenames": [
"atom.xml"
],
"taxonomies": [],
"author": null,
"build_search_index": true,
"extra": {
"logo_svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"108\" height=\"26\" fill=\"none\" viewBox=\"0 0 174 42\">\n<g fill=\"currentColor\">\n<path d=\"M.4 32.6c1.9 0 3-.9 3.8-3.9l4.6-22c.7-3-.7-4-2.5-4v-.5H19c9.2 0 11 5.5 10 10.1-1 4.8-4.8 9.5-16.5 9l.1-.5c7.3.4 10.5-3.9 11.3-8.4.9-4.3-.3-9.4-6.2-9.4h-3L9.2 28.7c-.7 3 1.2 3.9 3.7 3.9v.6H.5v-.6Z\"/><path d=\"M34.5 30.5c0-1.3.9-2.7 2.5-2.7 1.5 0 2.5 1.2 2.3 3-.2 1.2.3 1.6 1 1.5 1.7-.2 4.6-4.2 4.7-10.7 0-6.4-2-8.6-3.6-8.6-2.9 0-7.8 8-9.8 17.9l-.5 2.3h-4.7l5.7-27c.6-2.6 0-3.4-2-3.4v-.6c2.6-.2 5-.5 7.7-2.2l.3.3-.8 4-4 18.1C36 16 40 10 43.9 10c3.4 0 5.4 3.5 5.1 8.4-.3 6.2-4.8 15.2-10.8 15.2-2.4 0-3.6-1.6-3.6-3Zm15.9-9.2c1.6-7 7.4-11 12.6-11 5.2 0 9 5 7.3 12-1.6 7.2-7.4 11.3-12.5 11.3-5.5 0-9-5.2-7.4-12.3Zm7.9 11.5c2.7 0 5.6-4.1 7-11.1 1.4-7 .3-10.8-2.7-10.7-3 0-6 4.3-7.3 11.1-1.4 7 0 10.8 3 10.8Zm11.4-3.3c-.4-1.6.2-3 1.4-3.4a2.2 2.2 0 0 1 3 1.3c.5 1.4-.7 2.4-.6 3.8.2 1 1.2 1.9 3 1.8 1.8 0 3.5-1 4-3 .4-2-1-3.8-3.7-6.5-3-3-4.4-5.2-3.9-8.1.7-3 3.5-5.1 7.3-5.2 3-.1 5.9 1.2 6.5 3.6.5 1.5 0 3-1.4 3.4a2.1 2.1 0 0 1-2.8-1.3c-.5-1.6.8-2.5.6-3.5-.2-.9-1.1-1.7-2.6-1.6a3.8 3.8 0 0 0-3.7 3.2c-.2 1.7.5 3 3.1 5.5 2.7 2.6 5.2 5 4.5 8.5-.7 3.8-4 5.6-7.7 5.6-2.8 0-6.2-1.3-7-4.2Zm17.4 12c1.7 0 3-1 3-4v-22c0-2-.8-2.8-2.9-2.8V12c2.4-.2 5-.7 7.3-1.7l.4.2v4.6a7.7 7.7 0 0 1 7.1-4.8c5.3 0 9 5 9 11.4s-4.5 11.8-10.3 11.8A7.4 7.4 0 0 1 95 31v6.5c0 3 1.6 4 3.7 4v.5H87.1v-.6Zm13.3-8.7c3.3 0 5.7-3.7 5.7-9.4 0-6.9-3-10.5-6.5-10.5-2.4 0-4 1.6-4.7 3.7v7.6c0 4.8 2 8.6 5.5 8.6Z\"/><path d=\"M125 32.6c2.2 0 3.8-.9 3.4-3.9l-1.4-10c-.5-3.6-1.9-5.7-4.6-5.7-2.3 0-4 2.2-4.3 4.8v10.9c0 3 1.3 3.9 3 3.9v.6h-10.9v-.6c1.8 0 3.1-.8 3.1-3.9v-23c0-2.2-.9-3-2.9-3v-.5c2.3-.2 5-.6 7.3-1.7l.4.2V16c.8-3 3.3-5.6 6.7-5.6 3.7 0 6.2 2.5 7 8.2l1.5 10.2c.4 3 1.7 3.9 3.5 3.9v.5h-11.7v-.5ZM134.4 21.8a11 11 0 0 1 11.1-11.5c6 0 11.2 4.9 11.2 11.6 0 6.8-5 11.7-11 11.7-6.2 0-11.3-5.1-11.3-11.8Zm12.6 11c3.7-.6 5.3-5.7 4.5-12-.8-6-3.8-10.1-7.4-9.6-3.7.5-5.3 5.6-4.5 11.6.8 6.2 3.7 10.4 7.4 10Z\"/><path d=\"M155.9 32.6c1.8 0 3-.9 3-4v-13c0-2.2-.8-2.9-2.8-3v-.5a21.2 21.2 0 0 0 7.3-1.7l.4.2v4.8c.7-2.5 2.6-5 5.4-5 2.1 0 3.5 1.5 3.5 3.1 0 1.4-1 2.7-2.6 2.7s-2-1.4-2.4-2.3c-.3-.7-.5-1-1-1-1.4 0-2.7 2-3 4.2v11.6c0 3 1.8 3.9 4 3.9v.6H156v-.6Z\"/>\n</g>\n</svg>\n",
"drafts": true,
"sections": [
"Getting Started",
"Managing Complexity",
"Moving Quickly",
"Understanding Quickly",
"Architecture Patterns",
"Interactive Demos",
"Developer Tools",
"Advanced Topics"
],
"author": "Phosphor"
},
"markdown": {
"highlight_code": true,
"error_on_missing_highlight": false,
"highlight_theme": "base16-ocean-dark",
"highlight_themes_css": [],
"render_emoji": false,
"external_links_class": null,
"external_links_target_blank": false,
"external_links_no_follow": false,
"external_links_no_referrer": false,
"smart_punctuation": false,
"definition_list": false,
"bottom_footnotes": false,
"extra_syntaxes_and_themes": [],
"lazy_async_image": false,
"insert_anchor_links": "none",
"github_alerts": false
},
"search": {
"index_format": "elasticlunr_javascript"
},
"generate_sitemap": true,
"generate_robots_txt": true,
"exclude_paginated_pages_in_sitemap": "none"
},
"current_path": "/tight-javascriptify/",
"current_url": "/tight-javascriptify/",
"lang": "en",
"page": {
"relative_path": "tight-javascriptify.md",
"colocated_path": null,
"content": "<h1 id=\"tight-javascriptify-extensible-value-serialization\">Tight Javascriptify: Extensible Value Serialization <div data-loc=\"content/tight-javascriptify.md:7\" class=\"heading-src\">⋅</div></h1>\n<p>Serialize any JavaScript value to a readable string with hooks for custom transformations. Handles circular refs, Maps, Sets, Errors, and more.</p>\n<h2 id=\"basic-usage\">Basic Usage <div data-loc=\"content/tight-javascriptify.md:11\" class=\"heading-src\">⋅</div></h2>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#b48ead;\">import </span><span>{ </span><span style=\"color:#bf616a;\">tightJavaScriptify </span><span>} </span><span style=\"color:#b48ead;\">from </span><span>"</span><span style=\"color:#a3be8c;\">@phosphor/utils</span><span>";\n</span><span>\n</span><span style=\"color:#8fa1b3;\">tightJavaScriptify</span><span>({ user: "</span><span style=\"color:#a3be8c;\">alice</span><span>", id: </span><span style=\"color:#d08770;\">42 </span><span>});\n</span><span style=\"color:#65737e;\">// → {user:alice,id:42}\n</span><span>\n</span><span style=\"color:#8fa1b3;\">tightJavaScriptify</span><span>(new Map([["</span><span style=\"color:#a3be8c;\">key</span><span>", "</span><span style=\"color:#a3be8c;\">value</span><span>"]]));\n</span><span style=\"color:#65737e;\">// → {$Map(1):[["key","value"]]}\n</span><span>\n</span><span style=\"color:#8fa1b3;\">tightJavaScriptify</span><span>(new Error("</span><span style=\"color:#a3be8c;\">failed</span><span>"));\n</span><span style=\"color:#65737e;\">// → {name:Error,message:failed,stack:...}\n</span></code></pre>\n<h2 id=\"built-in-type-support\">Built-in Type Support <div data-loc=\"content/tight-javascriptify.md:26\" class=\"heading-src\">⋅</div></h2>\n<div class=\"codeblock\" data-loc=\"content/tight-javascriptify.md:28\">\n \n <div class=\"codeblock-content\" data-id=\"builtInPreHookForJsTypes\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/tight-javascriptify.ts:16\"><code><span class=\"line\"><span style=\"color:#31748F\">function</span><span style=\"color:#EBBCBA\"> builtInPreHookForJsTypes</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">key</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">,</span><span style=\"color:#C4A7E7;font-style:italic\"> value</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> unknown</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> null</span><span style=\"color:#31748F\"> |</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#EBBCBA;font-style:italic\"> value</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> unknown</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> Convert Map/Set to a standard object structure so that JSON.stringify can handle them</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\"> instanceof</span><span style=\"color:#9CCFD8\"> Map</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> entries</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> Array</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">from</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">entries</span><span style=\"color:#E0DEF4\">())</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> value</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> [</span><span style=\"color:#F6C177\">`$Map(</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">size</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">)`</span><span style=\"color:#E0DEF4\">]</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> entries</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\"> instanceof</span><span style=\"color:#9CCFD8\"> Set</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> values</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> Array</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">from</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> value</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> [</span><span style=\"color:#F6C177\">`$Set(</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">size</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">)`</span><span style=\"color:#E0DEF4\">]</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> values</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\"> instanceof</span><span style=\"color:#9CCFD8\"> Uint8Array</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> value</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> [</span><span style=\"color:#F6C177\">`$Uint8Array(</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">)`</span><span style=\"color:#E0DEF4\">]</span><span style=\"color:#908CAA\">:</span><span style=\"color:#EBBCBA\"> uint8ArrayToUtf8String</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">}</span><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#31748F\"> instanceof</span><span style=\"color:#9CCFD8\"> Date</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> value</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> $Date</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> value</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">toISOString</span><span style=\"color:#E0DEF4\">() </span><span style=\"color:#908CAA\">}</span><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#EBBCBA\"> null</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span></code></pre>\n </div>\n \n</div>\n<p>Automatically handles:</p>\n<ul>\n<li><strong>Map/Set</strong> → <code>{$Map(n): entries}</code> / <code>{$Set(n): values}</code></li>\n<li><strong>Date</strong> → <code>{$Date: \"2025-10-21T...\"}</code></li>\n<li><strong>Uint8Array</strong> → <code>{$Uint8Array(n): \"utf8 string\"}</code></li>\n<li><strong>Error</strong> → <code>{name, message, stack}</code></li>\n<li><strong>Function</strong> → <code>\"functionName\"</code> or truncated toString()</li>\n<li><strong>Circular refs</strong> → <code>[Circular? key: Object]</code></li>\n</ul>\n<h2 id=\"extensible-hooks\">Extensible Hooks <div data-loc=\"content/tight-javascriptify.md:39\" class=\"heading-src\">⋅</div></h2>\n<p>Add custom transformations with <strong>preHooks</strong>, <strong>hooks</strong>, or <strong>postHooks</strong>:</p>\n<div class=\"codeblock\" data-loc=\"content/tight-javascriptify.md:43\">\n \n <div class=\"codeblock-content\" data-id=\"applyHooks\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/tight-javascriptify.ts:49\"><code><span class=\"line\"><span style=\"color:#908CAA;font-style:italic\">/**</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * Applies each hook in sequence. The first hook that returns a non-null object</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * wins. If none return anything, returns undefined.</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> */</span></span>\n<span class=\"line\"><span style=\"color:#31748F\">function</span><span style=\"color:#EBBCBA\"> applyHooks</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">key</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">,</span><span style=\"color:#C4A7E7;font-style:italic\"> value</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> unknown</span><span style=\"color:#908CAA\">,</span><span style=\"color:#C4A7E7;font-style:italic\"> hooks</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> TightJavaScriptifyHook</span><span style=\"color:#E0DEF4\">[]</span><span style=\"color:#908CAA\">,</span><span style=\"color:#C4A7E7;font-style:italic\"> seen</span><span style=\"color:#31748F\"> =</span><span style=\"color:#31748F\"> new</span><span style=\"color:#EBBCBA\"> WeakMap</span><span style=\"color:#E0DEF4\">()</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> unknown</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> let</span><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> value</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#EBBCBA\">isObject</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">seen</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">has</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#31748F\">return</span><span style=\"color:#F6C177\"> `[Circular? </span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">seen</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">get</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">]`</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> seen</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">set</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#908CAA\">,</span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">key</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">: </span><span style=\"color:#908CAA\">${</span><span style=\"color:#EBBCBA\">toString</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">hooks</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#31748F\"> ></span><span style=\"color:#EBBCBA\"> 0</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> for</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#31748F\">const</span><span style=\"color:#E0DEF4;font-style:italic\"> hook</span><span style=\"color:#31748F\"> of</span><span style=\"color:#E0DEF4;font-style:italic\"> hooks</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> result</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> hook</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">replacer</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">key</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">result</span><span style=\"color:#31748F\"> !=</span><span style=\"color:#EBBCBA\"> null</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> result</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> toJSON</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">Array</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">isArray</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> for</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#31748F\">let</span><span style=\"color:#E0DEF4;font-style:italic\"> i</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> 0</span><span style=\"color:#908CAA\">;</span><span style=\"color:#E0DEF4;font-style:italic\"> i</span><span style=\"color:#31748F\"> <</span><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#908CAA\">;</span><span style=\"color:#E0DEF4;font-style:italic\"> i</span><span style=\"color:#31748F\">++</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#E0DEF4\">[</span><span style=\"color:#E0DEF4;font-style:italic\">i</span><span style=\"color:#E0DEF4\">] </span><span style=\"color:#31748F\">=</span><span style=\"color:#EBBCBA\"> applyHooks</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#EBBCBA\">String</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">i</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#E0DEF4\">[</span><span style=\"color:#E0DEF4;font-style:italic\">i</span><span style=\"color:#E0DEF4\">]</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> hooks</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> seen</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> else</span><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#31748F\"> &&</span><span style=\"color:#31748F\"> typeof</span><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#F6C177\"> \"object\"</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> result</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Record</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">string</span><span style=\"color:#908CAA\">,</span><span style=\"color:#9CCFD8\"> unknown</span><span style=\"color:#908CAA\">></span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> {};</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> for</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#31748F\">const</span><span style=\"color:#908CAA\"> [</span><span style=\"color:#E0DEF4;font-style:italic\">subKey</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> subValue</span><span style=\"color:#908CAA\">]</span><span style=\"color:#31748F\"> of</span><span style=\"color:#E0DEF4;font-style:italic\"> Object</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">entries</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">current</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> result</span><span style=\"color:#E0DEF4\">[</span><span style=\"color:#E0DEF4;font-style:italic\">subKey</span><span style=\"color:#E0DEF4\">] </span><span style=\"color:#31748F\">=</span><span style=\"color:#EBBCBA\"> applyHooks</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">subKey</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> subValue</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> hooks</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> seen</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#E0DEF4;font-style:italic\"> result</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#E0DEF4;font-style:italic\"> current</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span></code></pre>\n </div>\n \n</div>\n<h3 id=\"example-custom-class\">Example: Custom Class <div data-loc=\"content/tight-javascriptify.md:45\" class=\"heading-src\">⋅</div></h3>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#b48ead;\">class </span><span style=\"color:#ebcb8b;\">UserId </span><span style=\"color:#eff1f5;\">{\n</span><span style=\"color:#eff1f5;\"> </span><span style=\"color:#b48ead;\">constructor</span><span>(</span><span style=\"color:#b48ead;\">public </span><span style=\"color:#bf616a;\">id</span><span>: </span><span style=\"color:#eff1f5;\">string</span><span>) </span><span style=\"color:#eff1f5;\">{}\n</span><span style=\"color:#eff1f5;\">}\n</span><span>\n</span><span style=\"color:#bf616a;\">tightJavaScriptify</span><span>.</span><span style=\"color:#bf616a;\">hooks</span><span>.</span><span style=\"color:#96b5b4;\">push</span><span>({\n</span><span> name: "</span><span style=\"color:#a3be8c;\">UserId</span><span>",\n</span><span> </span><span style=\"color:#8fa1b3;\">replacer</span><span>: (</span><span style=\"color:#bf616a;\">key</span><span>, </span><span style=\"color:#bf616a;\">value</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">if </span><span>(</span><span style=\"color:#bf616a;\">value </span><span>instanceof UserId) {\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span>{ value: { $UserId: </span><span style=\"color:#bf616a;\">value</span><span>.id } };\n</span><span> }\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span style=\"color:#d08770;\">null</span><span>;\n</span><span> },\n</span><span>});\n</span><span>\n</span><span style=\"color:#8fa1b3;\">tightJavaScriptify</span><span>({ user: new UserId("</span><span style=\"color:#a3be8c;\">u123</span><span>") });\n</span><span style=\"color:#65737e;\">// → {user:{$UserId:u123}}\n</span></code></pre>\n<h3 id=\"example-redact-secrets\">Example: Redact Secrets <div data-loc=\"content/tight-javascriptify.md:66\" class=\"heading-src\">⋅</div></h3>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#bf616a;\">tightJavaScriptify</span><span>.</span><span style=\"color:#bf616a;\">preHooks</span><span>.</span><span style=\"color:#96b5b4;\">push</span><span>({\n</span><span> name: "</span><span style=\"color:#a3be8c;\">RedactAPIKeys</span><span>",\n</span><span> </span><span style=\"color:#8fa1b3;\">replacer</span><span>: (</span><span style=\"color:#bf616a;\">key</span><span>, </span><span style=\"color:#bf616a;\">value</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">if </span><span>(</span><span style=\"color:#bf616a;\">key </span><span>=== "</span><span style=\"color:#a3be8c;\">apiKey</span><span>" && typeof </span><span style=\"color:#bf616a;\">value </span><span>=== "</span><span style=\"color:#a3be8c;\">string</span><span>") {\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span>{ value: </span><span style=\"color:#bf616a;\">value</span><span>.</span><span style=\"color:#96b5b4;\">slice</span><span>(</span><span style=\"color:#d08770;\">0</span><span>, </span><span style=\"color:#d08770;\">4</span><span>) + "</span><span style=\"color:#a3be8c;\">...</span><span>" };\n</span><span> }\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span style=\"color:#d08770;\">null</span><span>;\n</span><span> },\n</span><span>});\n</span><span>\n</span><span style=\"color:#8fa1b3;\">tightJavaScriptify</span><span>({ apiKey: "</span><span style=\"color:#a3be8c;\">sk_live_abc123xyz</span><span>" });\n</span><span style=\"color:#65737e;\">// → {apiKey:sk_l...}\n</span></code></pre>\n<h3 id=\"hook-execution-order\">Hook Execution Order <div data-loc=\"content/tight-javascriptify.md:83\" class=\"heading-src\">⋅</div></h3>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#65737e;\">// Single-pass traversal applies hooks in order:\n</span><span>[\n</span><span> ...</span><span style=\"color:#bf616a;\">tightJavaScriptify</span><span>.</span><span style=\"color:#bf616a;\">preHooks</span><span>, </span><span style=\"color:#65737e;\">// Built-in JS types (Map/Set/Date)\n</span><span> ...</span><span style=\"color:#bf616a;\">extraHooks</span><span>, </span><span style=\"color:#65737e;\">// Per-call custom hooks\n</span><span> ...</span><span style=\"color:#bf616a;\">tightJavaScriptify</span><span>.</span><span style=\"color:#bf616a;\">hooks</span><span>, </span><span style=\"color:#65737e;\">// Global user hooks\n</span><span> ...</span><span style=\"color:#bf616a;\">tightJavaScriptify</span><span>.</span><span style=\"color:#bf616a;\">postHooks</span><span>, </span><span style=\"color:#65737e;\">// Error/Function fallbacks\n</span><span>];\n</span></code></pre>\n<h2 id=\"per-call-hooks\">Per-Call Hooks <div data-loc=\"content/tight-javascriptify.md:95\" class=\"heading-src\">⋅</div></h2>\n<p>Pass one-off hooks without mutating global state:</p>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">redactEmail </span><span>= {\n</span><span> name: "</span><span style=\"color:#a3be8c;\">RedactEmail</span><span>",\n</span><span> </span><span style=\"color:#8fa1b3;\">replacer</span><span>: (</span><span style=\"color:#bf616a;\">key</span><span>: string, </span><span style=\"color:#bf616a;\">value</span><span>: unknown) </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">if </span><span>(</span><span style=\"color:#bf616a;\">key </span><span>=== "</span><span style=\"color:#a3be8c;\">email</span><span>") </span><span style=\"color:#b48ead;\">return </span><span>{ value: "</span><span style=\"color:#a3be8c;\">***</span><span>" };\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span style=\"color:#d08770;\">null</span><span>;\n</span><span> },\n</span><span>};\n</span><span>\n</span><span style=\"color:#8fa1b3;\">tightJavaScriptify</span><span>({ email: "</span><span style=\"color:#a3be8c;\">alice@example.com</span><span>" }, [</span><span style=\"color:#bf616a;\">redactEmail</span><span>]);\n</span><span style=\"color:#65737e;\">// → {email:***}\n</span></code></pre>\n<h2 id=\"full-source\">Full Source <div data-loc=\"content/tight-javascriptify.md:112\" class=\"heading-src\">⋅</div></h2>\n<div class=\"codeblock\" data-loc=\"content/tight-javascriptify.md:114\">\n \n <div class=\"codeblock-content\" data-id=\"tight-javascriptify\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/tight-javascriptify.ts:84\"><code><span class=\"line\"><span style=\"color:#908CAA;font-style:italic\">/**</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * Serializes a value to a \"tight\" JavaScript-ish string.</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * By default, it handles circular objects, Errors, etc. If you wish to add</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * custom transformations, push a new hook to `tightJavaScriptify.hooks`.</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> *</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * Performance optimization: This implementation performs a single traversal of the data</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * structure while maintaining the order of hook application (preHooks -> extraHooks -></span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * hooks -> postHooks). This avoids multiple recursive traversals of the same structure.</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> *</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * Example usage:</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * ```ts</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * tightJavaScriptify.hooks.push({</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * name: \"myHook\",</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * replacer: (key, value) => {</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * if (isMySpecialObject(value)) {</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * return { value: transformMyObject(value) };</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * }</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * return null;</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * }</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * })</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * const result = tightJavaScriptify(myData);</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> *</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * // For custom preHooks:</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * tightJavaScriptify.preHooks.push({</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * name: \"replaceDates\",</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * replacer: (key, value) => {</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * if (value instanceof Date) {</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * return { value: { $Date: value.toISOString() } };</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * }</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * return null;</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * }</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * });</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> *</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * // We also have a default builtInPreHookForMapAndSet that handles Map/Set</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * // You can remove it if you wish to override map or set transformations:</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * tightJavaScriptify.preHooks = tightJavaScriptify.preHooks.filter(h => h.name !== \"builtInMapSetHook\");</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * ```</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> */</span></span>\n<span class=\"line\"><span style=\"color:#31748F\">function</span><span style=\"color:#EBBCBA\"> tightJavaScriptify</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">value</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> unknown</span><span style=\"color:#908CAA\">,</span><span style=\"color:#C4A7E7;font-style:italic\"> extraHooks</span><span style=\"color:#31748F\">?:</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#9CCFD8\">Falsey</span><span style=\"color:#31748F\"> |</span><span style=\"color:#9CCFD8\"> TightJavaScriptifyHook</span><span style=\"color:#E0DEF4\">)[]</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> let</span><span style=\"color:#E0DEF4;font-style:italic\"> traversed</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> toJSON</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">value</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> combinedHooks</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4\"> [</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> ...</span><span style=\"color:#E0DEF4;font-style:italic\">tightJavaScriptify</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">preHooks</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> ...</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">extraHooks</span><span style=\"color:#31748F\"> ??</span><span style=\"color:#E0DEF4\"> [])</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> ...</span><span style=\"color:#E0DEF4;font-style:italic\">tightJavaScriptify</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">hooks</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> ...</span><span style=\"color:#E0DEF4;font-style:italic\">tightJavaScriptify</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">postHooks</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> ]</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">filter</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">isTruthy</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> Single traversal applying all hooks in sequence</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> traversed</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> applyHooks</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\"\"</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> traversed</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> combinedHooks</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> try {</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> traversed.hooked = combinedHooks.map((h) => h.name).join(\" -> \");</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> } catch {}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">traversed</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#EBBCBA\"> undefined</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#31748F\">return</span><span style=\"color:#F6C177\"> \"undefined\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">traversed</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#EBBCBA\"> null</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#31748F\">return</span><span style=\"color:#F6C177\"> \"null\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> result</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#EBBCBA\">tightJsonStringify</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">traversed</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#31748F\">??</span><span style=\"color:#F6C177\"> \"undefined\"</span><span style=\"color:#E0DEF4\">)</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> Convert quoted property keys to unquoted if valid</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> .</span><span style=\"color:#EBBCBA\">replace</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">/</span><span style=\"color:#908CAA\">(</span><span style=\"color:#31748F\">\\\\?</span><span style=\"color:#F6C177\">\"</span><span style=\"color:#908CAA\">)([</span><span style=\"color:#31748F\">^\"</span><span style=\"color:#908CAA\">]</span><span style=\"color:#31748F\">+</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">\\1</span><span style=\"color:#F6C177\">:/</span><span style=\"color:#31748F\">g</span><span style=\"color:#908CAA\">,</span><span style=\"color:#F6C177\"> \"$2:\"</span><span style=\"color:#E0DEF4\">)</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> Turn our placeholder UNDEFINED back into \"undefined\"</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> .</span><span style=\"color:#EBBCBA\">replace</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">UNDEFINED_RE</span><span style=\"color:#908CAA\">,</span><span style=\"color:#F6C177\"> \"undefined\"</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#E0DEF4;font-style:italic\"> result</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span></code></pre>\n </div>\n \n</div>\n<h2 id=\"performance\">Performance <div data-loc=\"content/tight-javascriptify.md:116\" class=\"heading-src\">⋅</div></h2>\n<p>Single-pass traversal with hook composition avoids multiple recursive walks. Hooks execute sequentially until one returns a transformed value.</p>\n<h2 id=\"use-cases\">Use Cases <div data-loc=\"content/tight-javascriptify.md:120\" class=\"heading-src\">⋅</div></h2>\n<ul>\n<li><strong>DevString serialization</strong> – Capture complex context in dev messages</li>\n<li><strong>Logging</strong> – Readable structured logs without circular ref errors</li>\n<li><strong>Debugging</strong> – Quick object inspection with custom formatters</li>\n<li><strong>Test snapshots</strong> – Consistent serialization across types</li>\n</ul>\n",
"permalink": "/tight-javascriptify/",
"slug": "tight-javascriptify",
"ancestors": [
"_index.md"
],
"title": "Tight Javascriptify: Extensible Value Serialization",
"description": null,
"updated": null,
"date": "2025-10-21",
"year": 2025,
"month": 10,
"day": 21,
"taxonomies": {},
"authors": [],
"extra": {},
"path": "/tight-javascriptify/",
"components": [
"tight-javascriptify"
],
"summary": null,
"toc": [
{
"level": 1,
"id": "tight-javascriptify-extensible-value-serialization",
"permalink": "/tight-javascriptify/#tight-javascriptify-extensible-value-serialization",
"title": "Tight Javascriptify: Extensible Value Serialization ⋅",
"children": [
{
"level": 2,
"id": "basic-usage",
"permalink": "/tight-javascriptify/#basic-usage",
"title": "Basic Usage ⋅",
"children": []
},
{
"level": 2,
"id": "built-in-type-support",
"permalink": "/tight-javascriptify/#built-in-type-support",
"title": "Built-in Type Support ⋅",
"children": []
},
{
"level": 2,
"id": "extensible-hooks",
"permalink": "/tight-javascriptify/#extensible-hooks",
"title": "Extensible Hooks ⋅",
"children": [
{
"level": 3,
"id": "example-custom-class",
"permalink": "/tight-javascriptify/#example-custom-class",
"title": "Example: Custom Class ⋅",
"children": []
},
{
"level": 3,
"id": "example-redact-secrets",
"permalink": "/tight-javascriptify/#example-redact-secrets",
"title": "Example: Redact Secrets ⋅",
"children": []
},
{
"level": 3,
"id": "hook-execution-order",
"permalink": "/tight-javascriptify/#hook-execution-order",
"title": "Hook Execution Order ⋅",
"children": []
}
]
},
{
"level": 2,
"id": "per-call-hooks",
"permalink": "/tight-javascriptify/#per-call-hooks",
"title": "Per-Call Hooks ⋅",
"children": []
},
{
"level": 2,
"id": "full-source",
"permalink": "/tight-javascriptify/#full-source",
"title": "Full Source ⋅",
"children": []
},
{
"level": 2,
"id": "performance",
"permalink": "/tight-javascriptify/#performance",
"title": "Performance ⋅",
"children": []
},
{
"level": 2,
"id": "use-cases",
"permalink": "/tight-javascriptify/#use-cases",
"title": "Use Cases ⋅",
"children": []
}
]
}
],
"word_count": 295,
"reading_time": 2,
"assets": [],
"draft": true,
"lang": "en",
"lower": {
"relative_path": "devstate-extensible-debug-renderer.md",
"colocated_path": null,
"content": "<h1 id=\"devstate-extensible-debug-renderer\">DevState: Extensible Debug Renderer <div data-loc=\"content/devstate-extensible-debug-renderer.md:7\" class=\"heading-src\">⋅</div></h1>\n<p>Render complex runtime data structures with type-specific handlers. Register custom renderers to format atoms, queries, and domain objects without touching the core.</p>\n<h2 id=\"registry-pattern\">Registry Pattern <div data-loc=\"content/devstate-extensible-debug-renderer.md:11\" class=\"heading-src\">⋅</div></h2>\n<p>Define custom renderers with type guards:</p>\n<div class=\"codeblock\" data-loc=\"content/devstate-extensible-debug-renderer.md:15\">\n \n <div class=\"codeblock-content\" data-id=\"define-renderer\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/dev/DevState.tsx:198\"><code><span class=\"line\"><span style=\"color:#31748F\">export</span><span style=\"color:#31748F\"> function</span><span style=\"color:#EBBCBA\"> defineRenderer</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">T</span><span style=\"color:#31748F\"> extends</span><span style=\"color:#9CCFD8\"> UnknownObject</span><span style=\"color:#908CAA\">>(</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> test</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">data</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> UnknownObject</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#C4A7E7;font-style:italic\"> data</span><span style=\"color:#31748F\"> is</span><span style=\"color:#9CCFD8\"> T</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#C4A7E7;font-style:italic\"> render</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Renderer</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">T</span><span style=\"color:#908CAA\">>,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> RegistryItem</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">any</span><span style=\"color:#908CAA\">></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4;font-style:italic\"> test</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> render</span><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span></code></pre>\n </div>\n \n</div>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"color:#65737e;\">// Match by type predicate\n</span><span style=\"color:#8fa1b3;\">defineRenderer</span><span>(\n</span><span> (</span><span style=\"color:#bf616a;\">data</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span style=\"color:#8fa1b3;\">isAtom</span><span>(</span><span style=\"color:#bf616a;\">data</span><span>),\n</span><span> ({ </span><span style=\"color:#bf616a;\">data</span><span>, </span><span style=\"color:#bf616a;\">showPath</span><span>, </span><span style=\"color:#bf616a;\">r </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">value </span><span>= </span><span style=\"color:#8fa1b3;\">useAtomValue</span><span>(</span><span style=\"color:#bf616a;\">data</span><span>);\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span><</span><span style=\"color:#ebcb8b;\">r.Unknown </span><span style=\"color:#d08770;\">name</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span>.</span><span style=\"color:#96b5b4;\">toString</span><span>()</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">data</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">value</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">showPath</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">showPath</span><span style=\"color:#ab7967;\">} </span><span>/>;\n</span><span> },\n</span><span>);\n</span></code></pre>\n<p>String-based renderers parse and transform:</p>\n<div class=\"codeblock\" data-loc=\"content/devstate-extensible-debug-renderer.md:30\">\n \n <div class=\"codeblock-content\" data-id=\"define-string-renderer\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/dev/DevState.tsx:207\"><code><span class=\"line\"><span style=\"color:#31748F\">export</span><span style=\"color:#31748F\"> function</span><span style=\"color:#EBBCBA\"> defineStringRenderer</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">T</span><span style=\"color:#908CAA\">>(</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> parse</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">data</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> null</span><span style=\"color:#31748F\"> |</span><span style=\"color:#9CCFD8\"> undefined</span><span style=\"color:#31748F\"> |</span><span style=\"color:#9CCFD8\"> T</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#C4A7E7;font-style:italic\"> render</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Renderer</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">T</span><span style=\"color:#908CAA\">>,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> StringRegistryItem</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">any</span><span style=\"color:#908CAA\">></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4;font-style:italic\"> parse</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> render</span><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span></code></pre>\n </div>\n \n</div>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"color:#65737e;\">// Parse UIDs from strings\n</span><span style=\"color:#8fa1b3;\">defineStringRenderer</span><span>(\n</span><span> (</span><span style=\"color:#bf616a;\">data</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span>(</span><span style=\"color:#bf616a;\">World</span><span>.</span><span style=\"color:#8fa1b3;\">isUID</span><span>(</span><span style=\"color:#bf616a;\">data</span><span>) ? </span><span style=\"color:#bf616a;\">data </span><span>: </span><span style=\"color:#d08770;\">null</span><span>),\n</span><span> ({ </span><span style=\"color:#bf616a;\">data</span><span>, </span><span style=\"color:#bf616a;\">r</span><span>, </span><span style=\"color:#bf616a;\">showPath </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span>(\n</span><span> <</span><span style=\"color:#ebcb8b;\">r.Custom </span><span style=\"color:#d08770;\">rawValue</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">icon</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">Ta</span><span>.</span><span style=\"color:#bf616a;\">IconBox</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">showPath</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">showPath</span><span style=\"color:#ab7967;\">}</span><span>>\n</span><span> <</span><span style=\"color:#ebcb8b;\">UIDElement </span><span style=\"color:#d08770;\">uid</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span style=\"color:#ab7967;\">} </span><span>/>\n</span><span> </</span><span style=\"color:#ebcb8b;\">r.Custom</span><span>>\n</span><span> ),\n</span><span>);\n</span></code></pre>\n<h2 id=\"renderer-components\">Renderer Components <div data-loc=\"content/devstate-extensible-debug-renderer.md:44\" class=\"heading-src\">⋅</div></h2>\n<p>Built-in primitives handle common cases:</p>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">r</span><span>: RendererComponents = {\n</span><span> Array: <</span><span style=\"color:#ebcb8b;\">Array </span><span style=\"color:#d08770;\">data</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">items</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">Items</span><span>" />,\n</span><span> Object: <</span><span style=\"color:#ebcb8b;\">Object </span><span style=\"color:#d08770;\">data</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">obj</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">Config</span><span>" </span><span style=\"color:#d08770;\">commaSeparatedOmitKeys</span><span>="</span><span style=\"color:#a3be8c;\">internal,_private</span><span>" />,\n</span><span> Unknown: <</span><span style=\"color:#ebcb8b;\">Unknown </span><span style=\"color:#d08770;\">data</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">value</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">Result</span><span>" />,\n</span><span> Placeholder: <</span><span style=\"color:#ebcb8b;\">Placeholder </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">WeakMap</span><span>" />,\n</span><span> </span><span style=\"color:#8fa1b3;\">Custom</span><span>: (\n</span><span> <</span><span style=\"color:#ebcb8b;\">Custom </span><span style=\"color:#d08770;\">icon</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">Ta</span><span>.</span><span style=\"color:#bf616a;\">Icon</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">Type</span><span>">\n</span><span> ...\n</span><span> </</span><span style=\"color:#ebcb8b;\">Custom</span><span>>\n</span><span> ),\n</span><span>};\n</span></code></pre>\n<p>Use <code>commaSeparatedOmitKeys</code> to filter object keys without memoizing the data object.</p>\n<h2 id=\"integration\">Integration <div data-loc=\"content/devstate-extensible-debug-renderer.md:64\" class=\"heading-src\">⋅</div></h2>\n<p>Register renderers at app root:</p>\n<div class=\"codeblock\" data-loc=\"content/devstate-extensible-debug-renderer.md:68\">\n \n <div class=\"codeblock-content\" data-id=\"provide-renderers\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/dev/app-dev-state-renderers.tsx:156\"><code><span class=\"line\"><span style=\"color:#31748F\">export</span><span style=\"color:#31748F\"> const</span><span style=\"color:#EBBCBA;font-style:italic\"> ProvideAppDevStateRenderers</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> ({</span><span style=\"color:#C4A7E7;font-style:italic\"> children</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#EBBCBA;font-style:italic\"> children</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> React</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">ReactNode</span><span style=\"color:#908CAA\"> })</span><span style=\"color:#31748F\"> =></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#E0DEF4\"> (</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86\"> <</span><span style=\"color:#9CCFD8\">ProvideDevStateRenderers</span><span style=\"color:#C4A7E7;font-style:italic\"> registry</span><span style=\"color:#31748F\">=</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\">RENDERERS</span><span style=\"color:#908CAA\">}</span><span style=\"color:#C4A7E7;font-style:italic\"> stringRegistry</span><span style=\"color:#31748F\">=</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\">STRING_RENDERERS</span><span style=\"color:#908CAA\">}</span><span style=\"color:#C4A7E7;font-style:italic\"> orderedKeys</span><span style=\"color:#31748F\">=</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\">KEY_ORDER_PREFERENCE</span><span style=\"color:#908CAA\">}</span><span style=\"color:#6E6A86\">></span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4;font-style:italic\">children</span><span style=\"color:#908CAA\">}</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86\"> </</span><span style=\"color:#9CCFD8\">ProvideDevStateRenderers</span><span style=\"color:#6E6A86\">></span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> )</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">};</span></span></code></pre>\n </div>\n \n</div>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">RENDERERS</span><span>: RegistryItem<any>[] = [\n</span><span> </span><span style=\"color:#8fa1b3;\">defineRenderer</span><span>(\n</span><span> (</span><span style=\"color:#bf616a;\">thing</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span style=\"color:#bf616a;\">thing </span><span>instanceof DevString,\n</span><span> ({ </span><span style=\"color:#bf616a;\">data</span><span>, </span><span style=\"color:#bf616a;\">r </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span><</span><span style=\"color:#ebcb8b;\">r.Custom </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">DevString</span><span>">...</</span><span style=\"color:#ebcb8b;\">r.Custom</span><span>>,\n</span><span> ),\n</span><span> </span><span style=\"color:#8fa1b3;\">defineRenderer</span><span>(\n</span><span> </span><span style=\"color:#8fa1b3;\">objectPredicateMacro</span><span><Queryable>(["</span><span style=\"color:#a3be8c;\">label</span><span>", "</span><span style=\"color:#a3be8c;\">hash</span><span>"], (</span><span style=\"color:#bf616a;\">d</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span style=\"color:#bf616a;\">d</span><span>.</span><span style=\"color:#bf616a;\">_tag </span><span>=== "</span><span style=\"color:#a3be8c;\">db</span><span>"),\n</span><span> ({ </span><span style=\"color:#bf616a;\">data</span><span>, </span><span style=\"color:#bf616a;\">r </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span><</span><span style=\"color:#ebcb8b;\">LiveQueryRenderer </span><span style=\"color:#d08770;\">query</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">r</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">r</span><span style=\"color:#ab7967;\">} </span><span>/>,\n</span><span> ),\n</span><span>];\n</span><span>\n</span><span style=\"color:#b48ead;\">export const </span><span style=\"color:#8fa1b3;\">ProvideAppDevStateRenderers </span><span>= ({ </span><span style=\"color:#bf616a;\">children </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span>(\n</span><span> <</span><span style=\"color:#ebcb8b;\">ProvideDevStateRenderers\n</span><span> </span><span style=\"color:#d08770;\">registry</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">RENDERERS</span><span style=\"color:#ab7967;\">}\n</span><span> </span><span style=\"color:#d08770;\">stringRegistry</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">STRING_RENDERERS</span><span style=\"color:#ab7967;\">}\n</span><span> </span><span style=\"color:#d08770;\">orderedKeys</span><span>=</span><span style=\"color:#ab7967;\">{</span><span>["</span><span style=\"color:#a3be8c;\">devInfo</span><span>", "</span><span style=\"color:#a3be8c;\">name</span><span>", "</span><span style=\"color:#a3be8c;\">source</span><span>"]</span><span style=\"color:#ab7967;\">}\n</span><span> >\n</span><span> </span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">children</span><span style=\"color:#ab7967;\">}\n</span><span> </</span><span style=\"color:#ebcb8b;\">ProvideDevStateRenderers</span><span>>\n</span><span>);\n</span></code></pre>\n<h2 id=\"real-examples\">Real Examples <div data-loc=\"content/devstate-extensible-debug-renderer.md:93\" class=\"heading-src\">⋅</div></h2>\n<p><strong>Jotai Atoms</strong>: Read atom value and render live</p>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"color:#8fa1b3;\">defineRenderer</span><span>(\n</span><span> (</span><span style=\"color:#bf616a;\">thing</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span style=\"color:#8fa1b3;\">isAtom</span><span>(</span><span style=\"color:#bf616a;\">thing</span><span>),\n</span><span> ({ </span><span style=\"color:#bf616a;\">data</span><span>, </span><span style=\"color:#bf616a;\">r </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">value </span><span>= </span><span style=\"color:#8fa1b3;\">useAtomValue</span><span>(</span><span style=\"color:#bf616a;\">data</span><span>);\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span><</span><span style=\"color:#ebcb8b;\">r.Unknown </span><span style=\"color:#d08770;\">name</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span>.</span><span style=\"color:#bf616a;\">debugLabel</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">data</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">value</span><span style=\"color:#ab7967;\">} </span><span>/>;\n</span><span> },\n</span><span>);\n</span></code></pre>\n<p><strong>DevString with location links</strong>:</p>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"color:#8fa1b3;\">defineRenderer</span><span>(\n</span><span> (</span><span style=\"color:#bf616a;\">thing</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span style=\"color:#bf616a;\">thing </span><span>instanceof DevString,\n</span><span> ({ </span><span style=\"color:#bf616a;\">data</span><span>, </span><span style=\"color:#bf616a;\">r</span><span>, </span><span style=\"color:#bf616a;\">showPath </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">const </span><span>{ </span><span style=\"color:#bf616a;\">context</span><span>, </span><span style=\"color:#bf616a;\">message </span><span>} = </span><span style=\"color:#bf616a;\">data</span><span>.</span><span style=\"color:#8fa1b3;\">toJSON</span><span>();\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span>(\n</span><span> <</span><span style=\"color:#ebcb8b;\">r.Custom </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">DevString</span><span>" </span><span style=\"color:#d08770;\">nameChild</span><span>=</span><span style=\"color:#ab7967;\">{</span><span><</span><span style=\"color:#ebcb8b;\">DevStringLink </span><span style=\"color:#d08770;\">reason</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span style=\"color:#ab7967;\">} </span><span>/></span><span style=\"color:#ab7967;\">}</span><span>>\n</span><span> </span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">message</span><span>.</span><span style=\"color:#8fa1b3;\">map</span><span>((</span><span style=\"color:#bf616a;\">part</span><span>, </span><span style=\"color:#bf616a;\">i</span><span>) </span><span style=\"color:#b48ead;\">=>\n</span><span> typeof </span><span style=\"color:#bf616a;\">part </span><span>=== "</span><span style=\"color:#a3be8c;\">string</span><span>" ? <</span><span style=\"color:#bf616a;\">span</span><span>></span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">part</span><span style=\"color:#ab7967;\">}</span><span></</span><span style=\"color:#bf616a;\">span</span><span>> : <</span><span style=\"color:#ebcb8b;\">r.Unknown </span><span style=\"color:#d08770;\">data</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">part</span><span style=\"color:#ab7967;\">} </span><span style=\"color:#d08770;\">showPath</span><span>=</span><span style=\"color:#ab7967;\">{</span><span>["</span><span style=\"color:#a3be8c;\">msg</span><span>"]</span><span style=\"color:#ab7967;\">} </span><span>/>,\n</span><span> )</span><span style=\"color:#ab7967;\">}\n</span><span> </span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span>.</span><span style=\"color:#bf616a;\">cause </span><span>&& <</span><span style=\"color:#ebcb8b;\">r.Unknown </span><span style=\"color:#d08770;\">name</span><span>="</span><span style=\"color:#a3be8c;\">Reason</span><span>" </span><span style=\"color:#d08770;\">data</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">data</span><span>.</span><span style=\"color:#bf616a;\">cause</span><span style=\"color:#ab7967;\">} </span><span>/></span><span style=\"color:#ab7967;\">}\n</span><span> </</span><span style=\"color:#ebcb8b;\">r.Custom</span><span>>\n</span><span> );\n</span><span> },\n</span><span>);\n</span></code></pre>\n<h2 id=\"key-features\">Key Features <div data-loc=\"content/devstate-extensible-debug-renderer.md:126\" class=\"heading-src\">⋅</div></h2>\n<ul>\n<li><strong>Type-safe matching</strong>: Type guards ensure correct data shape</li>\n<li><strong>Composable</strong>: Renderers use <code>r.*</code> components to recurse</li>\n<li><strong>React hooks</strong>: Use atoms, queries, state inside renderers</li>\n<li><strong>Depth tracking</strong>: Automatic collapse at configurable depth</li>\n<li><strong>Circular detection</strong>: Prevents infinite recursion</li>\n<li><strong>Ordered keys</strong>: Control property display order globally</li>\n</ul>\n",
"permalink": "/devstate-extensible-debug-renderer/",
"slug": "devstate-extensible-debug-renderer",
"ancestors": [
"_index.md"
],
"title": "DevState: Extensible Debug Renderer",
"description": null,
"updated": null,
"date": "2025-10-21",
"year": 2025,
"month": 10,
"day": 21,
"taxonomies": {},
"authors": [],
"extra": {},
"path": "/devstate-extensible-debug-renderer/",
"components": [
"devstate-extensible-debug-renderer"
],
"summary": null,
"toc": [
{
"level": 1,
"id": "devstate-extensible-debug-renderer",
"permalink": "/devstate-extensible-debug-renderer/#devstate-extensible-debug-renderer",
"title": "DevState: Extensible Debug Renderer ⋅",
"children": [
{
"level": 2,
"id": "registry-pattern",
"permalink": "/devstate-extensible-debug-renderer/#registry-pattern",
"title": "Registry Pattern ⋅",
"children": []
},
{
"level": 2,
"id": "renderer-components",
"permalink": "/devstate-extensible-debug-renderer/#renderer-components",
"title": "Renderer Components ⋅",
"children": []
},
{
"level": 2,
"id": "integration",
"permalink": "/devstate-extensible-debug-renderer/#integration",
"title": "Integration ⋅",
"children": []
},
{
"level": 2,
"id": "real-examples",
"permalink": "/devstate-extensible-debug-renderer/#real-examples",
"title": "Real Examples ⋅",
"children": []
},
{
"level": 2,
"id": "key-features",
"permalink": "/devstate-extensible-debug-renderer/#key-features",
"title": "Key Features ⋅",
"children": []
}
]
}
],
"word_count": 237,
"reading_time": 2,
"assets": [],
"draft": true,
"lang": "en",
"lower": null,
"higher": null,
"translations": [],
"backlinks": []
},
"higher": {
"relative_path": "click-to-source.md",
"colocated_path": null,
"content": "<h1 id=\"click-to-source-embedding-runtime-locations\">Click to Source: Embedding Runtime Locations <div data-loc=\"content/click-to-source.md:10\" class=\"heading-src\">⋅</div></h1>\n\n<p>Build-time transforms inject source locations into runtime code. Alt+Click any element to jump to its source file.</p>\n<h2 id=\"try-it\">Try It <div data-loc=\"content/click-to-source.md:19\" class=\"heading-src\">⋅</div></h2>\n<div data-loc=\"content/click-to-source.md:21\" id=\"click-to-source-demo\">\nHold Alt and hover over any button, then click to view its source. The mock console shows what file would open, and the viewer displays the source code.\n</div>\n<script src=\"/js/click-to-source-demo.entrypoint.js\" type=\"module\"></script>\n<h2 id=\"react-component-locations\">React Component Locations <div data-loc=\"content/click-to-source.md:26\" class=\"heading-src\">⋅</div></h2>\n<p>Transform <code>$</code> prop shorthand into <code>data-loc</code> attributes:</p>\n<div class=\"codeblock\" data-loc=\"content/click-to-source.md:30\">\n \n <div class=\"codeblock-content\" data-id=\"react-loc-transform\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"tools/bun-dev-and-react-$-className-loc.mts:35\"><code><span class=\"line\"><span style=\"color:#31748F\">if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">enableReact$Loc</span><span style=\"color:#31748F\"> &&</span><span style=\"color:#E0DEF4;font-style:italic\"> path</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">endsWith</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\".tsx\"</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> for</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#31748F\">const</span><span style=\"color:#E0DEF4;font-style:italic\"> match</span><span style=\"color:#31748F\"> of</span><span style=\"color:#E0DEF4;font-style:italic\"> code</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">matchAll</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">CLASSNAME_$_RE</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> index</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> match</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">index</span><span style=\"color:#31748F\">!</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#908CAA\"> [</span><span style=\"color:#E0DEF4;font-style:italic\">_</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> pre</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> post</span><span style=\"color:#908CAA\">]</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> match</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4;font-style:italic\"> line</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> column</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> indexToLineAndColumn</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">code</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> pre</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> link</span><span style=\"color:#31748F\"> =</span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">path</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">slice</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">inCodebase</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> IN_CODEBASE_SLICE</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">:</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">line</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">:</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">column</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> let</span><span style=\"color:#E0DEF4;font-style:italic\"> dataAttrs</span><span style=\"color:#31748F\"> =</span><span style=\"color:#F6C177\"> `data-loc=</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">JSON</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">stringify</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">link</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">pre</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">startsWith</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\"<\"</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> dataAttrs</span><span style=\"color:#31748F\"> =</span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">dataAttrs</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\"> data-name=</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">JSON</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">stringify</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">pre</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">split</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\" \"</span><span style=\"color:#E0DEF4\">)[</span><span style=\"color:#EBBCBA\">0</span><span style=\"color:#E0DEF4\">]</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">slice</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#EBBCBA\">1</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">trim</span><span style=\"color:#E0DEF4\">())</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">post</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#F6C177\"> \"=\"</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> string</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">overwrite</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> pre</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> _</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#31748F\"> -</span><span style=\"color:#E0DEF4;font-style:italic\"> post</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#908CAA\">,</span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">dataAttrs</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\"> className`</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> else</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> string</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">overwrite</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> pre</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> _</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#31748F\"> -</span><span style=\"color:#E0DEF4;font-style:italic\"> post</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> dataAttrs</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span></code></pre>\n </div>\n \n</div>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span> </span><span style=\"color:#65737e;\">// Input:\n</span><span> <</span><span style=\"color:#bf616a;\">div </span><span style=\"color:#d08770;\">$</span><span>="</span><span style=\"color:#a3be8c;\">card</span><span>">Content</</span><span style=\"color:#bf616a;\">div</span><span>>\n</span><span>\n</span><span> </span><span style=\"color:#65737e;\">// Output (at build):\n</span><span> <</span><span style=\"color:#bf616a;\">div </span><span style=\"color:#d08770;\">data-loc</span><span>="</span><span style=\"color:#a3be8c;\">components/Card.tsx:26:7</span><span>" </span><span style=\"color:#d08770;\">className</span><span>="</span><span style=\"color:#a3be8c;\">card</span><span>">Content</</span><span style=\"color:#bf616a;\">div</span><span>>\n</span></code></pre>\n<p>Runtime handler walks React fiber tree and opens the file:</p>\n<div class=\"codeblock\" data-loc=\"content/click-to-source.md:42\">\n \n <div class=\"codeblock-content\" data-id=\"click-to-source-handler\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/dev/click-to-source.client.ts:156\"><code><span class=\"line\"><span style=\"color:#31748F\">const</span><span style=\"color:#EBBCBA;font-style:italic\"> getPath</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">fiber</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Fiber</span><span style=\"color:#908CAA\">,</span><span style=\"color:#C4A7E7;font-style:italic\"> element</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> HTMLElement</span><span style=\"color:#31748F\"> |</span><span style=\"color:#9CCFD8\"> undefined</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#31748F\"> |</span><span style=\"color:#9CCFD8\"> undefined</span><span style=\"color:#31748F\"> =></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> First check for data-loc attribute if element is provided</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">element</span><span style=\"color:#31748F\">?.</span><span style=\"color:#E0DEF4;font-style:italic\">dataset</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">loc</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#E0DEF4;font-style:italic\"> element</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">dataset</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">loc</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> source</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> fiber</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">_debugSource</span><span style=\"color:#31748F\"> ??</span><span style=\"color:#E0DEF4;font-style:italic\"> fiber</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">_debugInfo</span><span style=\"color:#31748F\"> ??</span><span style=\"color:#E0DEF4;font-style:italic\"> fiber</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">_source</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#31748F\">!</span><span style=\"color:#E0DEF4;font-style:italic\">source</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#31748F\">return</span><span style=\"color:#EBBCBA\"> undefined</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4;font-style:italic\"> fileName</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> lineNumber</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> 1</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> columnNumber</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> 1</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> source</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">fileName</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">:</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">lineNumber</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">:</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">columnNumber</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">};</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\">const</span><span style=\"color:#EBBCBA;font-style:italic\"> getLayersForElement</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">element</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> HTMLElement</span><span style=\"color:#908CAA\">,</span><span style=\"color:#C4A7E7;font-style:italic\"> root</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> ComponentLayer</span><span style=\"color:#E0DEF4\">[] </span><span style=\"color:#31748F\">=></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> let</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> getReactInstanceForElement</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">element</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> layers</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> ComponentLayer</span><span style=\"color:#E0DEF4\">[] </span><span style=\"color:#31748F\">=</span><span style=\"color:#E0DEF4\"> []</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> while</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">instance</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> Try to find the DOM element for this fiber to check for data-loc</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> fiberElement</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">stateNode</span><span style=\"color:#31748F\"> instanceof</span><span style=\"color:#9CCFD8\"> HTMLElement</span><span style=\"color:#31748F\"> ?</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">stateNode</span><span style=\"color:#31748F\"> :</span><span style=\"color:#EBBCBA\"> undefined</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> path</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> getPath</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">instance</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> fiberElement</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">path</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> name</span><span style=\"color:#31748F\"> =</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> typeof</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">type</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#F6C177\"> \"string\"</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> ?</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">type</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> :</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">type</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">displayName</span><span style=\"color:#31748F\"> ??</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">type</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">name</span><span style=\"color:#31748F\"> ??</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">type</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">render</span><span style=\"color:#31748F\">?.</span><span style=\"color:#E0DEF4;font-style:italic\">name</span><span style=\"color:#31748F\"> ??</span><span style=\"color:#F6C177\"> \"undefined\"</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> layers</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">push</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> name</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4\"> path</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> path</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">replace</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">`</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">root</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">/`</span><span style=\"color:#908CAA\">,</span><span style=\"color:#F6C177\"> \"\"</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">}</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> instance</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">_debugOwner</span><span style=\"color:#31748F\"> ??</span><span style=\"color:#EBBCBA\"> undefined</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#E0DEF4;font-style:italic\"> layers</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">};</span></span></code></pre>\n </div>\n \n</div>\n<h2 id=\"devstring-locations\">DevString Locations <div data-loc=\"content/click-to-source.md:44\" class=\"heading-src\">⋅</div></h2>\n<p>Tagged templates automatically capture call-site locations:</p>\n<div class=\"codeblock\" data-loc=\"content/click-to-source.md:48\">\n \n <div class=\"codeblock-content\" data-id=\"devstring-transform\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"tools/bun-dev-and-react-$-className-loc.mts:23\"><code><span class=\"line\"><span style=\"color:#31748F\">if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">enableDevLoc</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> for</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#31748F\">const</span><span style=\"color:#E0DEF4;font-style:italic\"> match</span><span style=\"color:#31748F\"> of</span><span style=\"color:#E0DEF4;font-style:italic\"> code</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">matchAll</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">DEV_RE</span><span style=\"color:#E0DEF4\">)) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> index</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> match</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">index</span><span style=\"color:#31748F\">!</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4;font-style:italic\"> line</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> column</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> indexToLineAndColumn</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">code</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> index</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#908CAA\"> [</span><span style=\"color:#E0DEF4;font-style:italic\">_</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> fn</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> message</span><span style=\"color:#908CAA\">]</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> match</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> link</span><span style=\"color:#31748F\"> =</span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">path</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">slice</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">inCodebase</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> IN_CODEBASE_SLICE</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">:</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">line</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">:</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">column</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> string</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">overwrite</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">index</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> index</span><span style=\"color:#31748F\"> +</span><span style=\"color:#E0DEF4;font-style:italic\"> _</span><span style=\"color:#31748F\">.</span><span style=\"color:#9CCFD8\">length</span><span style=\"color:#908CAA\">,</span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">fn</span><span style=\"color:#908CAA\">}</span><span style=\"color:#31748F\">\\`</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">message</span><span style=\"color:#908CAA\">}</span><span style=\"color:#31748F\">\\`</span><span style=\"color:#F6C177\">.ctx({ loc: </span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">JSON</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">stringify</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">link</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\"> })`</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span></code></pre>\n </div>\n \n</div>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#65737e;\">// Input:\n</span><span style=\"color:#8fa1b3;\">handler</span><span>(</span><span style=\"color:#8fa1b3;\">dev</span><span>`</span><span style=\"color:#a3be8c;\">User pressed X</span><span>`);\n</span><span>\n</span><span style=\"color:#65737e;\">// Output (at build):\n</span><span style=\"color:#8fa1b3;\">handler</span><span>(</span><span style=\"color:#8fa1b3;\">dev</span><span>`</span><span style=\"color:#a3be8c;\">User pressed X</span><span>`.</span><span style=\"color:#8fa1b3;\">ctx</span><span>({ loc: "</span><span style=\"color:#a3be8c;\">Card.tsx:83:12</span><span>" }));\n</span></code></pre>\n<p><strong>Usage:</strong></p>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#b48ead;\">function </span><span style=\"color:#8fa1b3;\">deleteCard</span><span>(</span><span style=\"color:#bf616a;\">reason</span><span>: DevString) {\n</span><span> </span><span style=\"color:#ebcb8b;\">console</span><span>.</span><span style=\"color:#96b5b4;\">log</span><span>("</span><span style=\"color:#a3be8c;\">Called from:</span><span>", </span><span style=\"color:#bf616a;\">reason</span><span>.</span><span style=\"color:#8fa1b3;\">toJSON</span><span>().</span><span style=\"color:#bf616a;\">context</span><span>.</span><span style=\"color:#bf616a;\">loc</span><span>);\n</span><span>}\n</span><span>\n</span><span style=\"color:#8fa1b3;\">deleteCard</span><span>(</span><span style=\"color:#8fa1b3;\">dev</span><span>`</span><span style=\"color:#a3be8c;\">User clicked delete</span><span>`);\n</span><span style=\"color:#65737e;\">// Automatically knows source location\n</span></code></pre>\n<p>DevStrings compose with <code>.because()</code> to build audit trails:</p>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">rootEvent </span><span>= </span><span style=\"color:#8fa1b3;\">dev</span><span>`</span><span style=\"color:#a3be8c;\">keydown from root</span><span>`;\n</span><span style=\"color:#8fa1b3;\">handler</span><span>(</span><span style=\"color:#bf616a;\">rootEvent</span><span>.</span><span style=\"color:#8fa1b3;\">because</span><span>(</span><span style=\"color:#8fa1b3;\">dev</span><span>`</span><span style=\"color:#a3be8c;\">Looking for action handler</span><span>`));\n</span><span style=\"color:#65737e;\">// Creates chain: "keydown from root → Looking for action handler"\n</span></code></pre>\n<h2 id=\"editor-integration\">Editor Integration <div data-loc=\"content/click-to-source.md:77\" class=\"heading-src\">⋅</div></h2>\n<p>Local HTTP endpoint opens files:</p>\n<div class=\"codeblock\" data-loc=\"content/click-to-source.md:81\">\n \n <div class=\"codeblock-content\" data-id=\"open-in-editor\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"scripts/lib/dev/openInDevEditor.ts:1\"><code><span class=\"line\"><span style=\"color:#31748F\">let</span><span style=\"color:#E0DEF4;font-style:italic\"> lastOpenedFile</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#31748F\"> |</span><span style=\"color:#9CCFD8\"> null</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> null</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\">/**</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * uses our launch-editor endpoint to open the file in the dev's editor</span></span>\n<span class=\"line\"><span style=\"color:#6E6A86;font-style:italic\"> * this has been set up as a vite plugin.</span></span>\n<span class=\"line\"><span style=\"color:#908CAA;font-style:italic\"> */</span></span>\n<span class=\"line\"><span style=\"color:#31748F\">export</span><span style=\"color:#31748F\"> const</span><span style=\"color:#EBBCBA;font-style:italic\"> openInDevEditor</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">loc</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">lastOpenedFile</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#E0DEF4;font-style:italic\"> loc</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#31748F\">return</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> lastOpenedFile</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> loc</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> setTimeout</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">lastOpenedFile</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> null</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span><span style=\"color:#EBBCBA\"> 500</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> void</span><span style=\"color:#EBBCBA\"> fetch</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">`http://localhost:5090/__open-in-editor?file=</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">loc</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">catch</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">error</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> console</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">error</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\"Failed to open in editor\"</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> error</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">};</span></span></code></pre>\n </div>\n \n</div>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#8fa1b3;\">openInDevEditor</span><span>("</span><span style=\"color:#a3be8c;\">Card.tsx:26:7</span><span>");\n</span><span> ↓\n</span><span style=\"color:#8fa1b3;\">fetch</span><span>("</span><span style=\"color:#a3be8c;\">http://localhost:5090/__open-in-editor?file=Card.tsx:26:7</span><span>");\n</span><span> ↓\n</span><span style=\"color:#65737e;\">// Editor opens at that line\n</span></code></pre>\n<h2 id=\"setup\">Setup <div data-loc=\"content/click-to-source.md:91\" class=\"heading-src\">⋅</div></h2>\n<p><strong>Build plugin:</strong></p>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#b48ead;\">import </span><span>{ </span><span style=\"color:#bf616a;\">bunDevStringAndReact$ClassNameLoc </span><span>} </span><span style=\"color:#b48ead;\">from </span><span>"</span><span style=\"color:#a3be8c;\">./bun-dev-and-react-$-className-loc.mts</span><span>";\n</span><span>\n</span><span style=\"color:#b48ead;\">await </span><span style=\"color:#bf616a;\">Bun</span><span>.</span><span style=\"color:#8fa1b3;\">build</span><span>({\n</span><span> plugins: [\n</span><span> </span><span style=\"color:#8fa1b3;\">bunDevStringAndReact$ClassNameLoc</span><span>({\n</span><span> enableReact$Loc: </span><span style=\"color:#d08770;\">true</span><span>,\n</span><span> enableDevLoc: </span><span style=\"color:#d08770;\">true</span><span>,\n</span><span> }),\n</span><span> ],\n</span><span>});\n</span></code></pre>\n<p><strong>Runtime:</strong></p>\n<pre data-lang=\"typescript\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-typescript \"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#b48ead;\">import </span><span>{ </span><span style=\"color:#bf616a;\">initClickToSource </span><span>} </span><span style=\"color:#b48ead;\">from </span><span>"</span><span style=\"color:#a3be8c;\">./click-to-source.client.ts</span><span>";\n</span><span>\n</span><span style=\"color:#b48ead;\">if </span><span>(</span><span style=\"color:#b48ead;\">import</span><span>.meta.</span><span style=\"color:#bf616a;\">env</span><span>.</span><span style=\"color:#bf616a;\">DEV</span><span>) {\n</span><span> </span><span style=\"color:#8fa1b3;\">initClickToSource</span><span>();\n</span><span>}\n</span></code></pre>\n",
"permalink": "/click-to-source/",
"slug": "click-to-source",
"ancestors": [
"_index.md"
],
"title": "Click to Source: Embedding Runtime Locations",
"description": null,
"updated": null,
"date": "2025-10-20",
"year": 2025,
"month": 10,
"day": 20,
"taxonomies": {},
"authors": [],
"extra": {
"nav_section": "Moving Quickly",
"nav_order": 1
},
"path": "/click-to-source/",
"components": [
"click-to-source"
],
"summary": null,
"toc": [
{
"level": 1,
"id": "click-to-source-embedding-runtime-locations",
"permalink": "/click-to-source/#click-to-source-embedding-runtime-locations",
"title": "Click to Source: Embedding Runtime Locations ⋅",
"children": [
{
"level": 2,
"id": "try-it",
"permalink": "/click-to-source/#try-it",
"title": "Try It ⋅",
"children": []
},
{
"level": 2,
"id": "react-component-locations",
"permalink": "/click-to-source/#react-component-locations",
"title": "React Component Locations ⋅",
"children": []
},
{
"level": 2,
"id": "devstring-locations",
"permalink": "/click-to-source/#devstring-locations",
"title": "DevString Locations ⋅",
"children": []
},
{
"level": 2,
"id": "editor-integration",
"permalink": "/click-to-source/#editor-integration",
"title": "Editor Integration ⋅",
"children": []
},
{
"level": 2,
"id": "setup",
"permalink": "/click-to-source/#setup",
"title": "Setup ⋅",
"children": []
}
]
}
],
"word_count": 255,
"reading_time": 2,
"assets": [],
"draft": false,
"lang": "en",
"lower": null,
"higher": null,
"translations": [],
"backlinks": []
},
"translations": [],
"backlinks": []
},
"zola_version": "0.21.0"
}