<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: naugtur</title>
    <description>The latest articles on DEV Community by naugtur (@naugtur).</description>
    <link>https://dev.to/naugtur</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F247817%2Ff7fb04ee-1431-41aa-a06e-52aa5c8a1e47.jpeg</url>
      <title>DEV Community: naugtur</title>
      <link>https://dev.to/naugtur</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/naugtur"/>
    <language>en</language>
    <item>
      <title>Is this my last meet.js Summit?</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Mon, 26 Jan 2026 14:07:51 +0000</pubDate>
      <link>https://dev.to/naugtur/is-this-my-last-meetjs-summit-1o5k</link>
      <guid>https://dev.to/naugtur/is-this-my-last-meetjs-summit-1o5k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Betteridge's Law of Headlines&lt;br&gt;
states that any headline ending in a question mark can almost always be answered with "no". &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://summit.meetjs.pl/2026/" rel="noopener noreferrer"&gt;https://summit.meetjs.pl/2026/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But it's how I'm thinking about it here and now. As the last meet.js Summit in that shape and format I'll ever organize. A 1-day conference that in the pre-covid world was so easy to pull off that even the clueless me could do it.&lt;br&gt;
(acknowledgement: it was never just me, it was a team effort, and I was the main organizer of only 3 out of 9 - seems like I take 4 years to recover before I want to organize another one again) &lt;/p&gt;

&lt;p&gt;Back when I organized my first two, getting sponsors was a matter of sending 15 emails to get half of them to join.&lt;br&gt;
In 2018 I partnered with a charity for the first time to do the ticket sales. Based on feedback from previous years the main problem with tickets was that they ran out too fast. We had to come up with tricks to prevent selling out in 2h.&lt;br&gt;
Getting a 50% discount on a venue to sit 500 was a matter of asking and mentioning it's for charity.&lt;/p&gt;

&lt;p&gt;Coming back after covid I almost cancelled the 2022 one. A month before the event we didn't even sell 200 out of the 500 tickets we had. Turns out that's the new reality. &lt;/p&gt;

&lt;p&gt;I think we're witnessing the dawn of the local conference. Not because there's no need for them. People still benefit tremendously from physically getting together with other nerds. It's getting easier for the ones who understand that to go to one of the biggest popular conferences abroad. Meanwhile, the conference budgets at companies are getting cut and the expectations are changing.&lt;/p&gt;

&lt;p&gt;So while it's great to band together with some incredible people and organize one last Summit - single track, one day celebration of being together with hundreds of other devs, 15 years into the existence of meet.js - I can already see it changing.&lt;/p&gt;

&lt;p&gt;Instead of creating a platform for local speakers to shine, we're trying to create an agenda that will be the most useful for attendees in the new circumstances. (Don't worry, we'll have local speakers and they'll shine) &lt;br&gt;
Instead of announcing it and letting the news spread organically, we're doing social media and marketing (well, not me, I still suck at these)&lt;br&gt;
Instead of doing just talks, we're trying other formats.&lt;/p&gt;

&lt;p&gt;This Summit will be special, with the hit of nostalgia and pride in how long it all lasted. I hope to see everyone once again, before we finally wrangle AI or it eats us and our neat programming hobby.&lt;/p&gt;

&lt;p&gt;If you've been skipping on events for a while because life or kids or you don't feel like it anymore - this is the one time to break the habit and go. If enough of us do it, it'll be a real reunion.&lt;/p&gt;

&lt;p&gt;And that's the biggest expectation that this event is aiming to fulfill. But it's an expectation that's not on the organizers to take care of. So good luck to you I guess.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post might grow in time. Come back in a few days.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Don't we all look forward to code-review full time?</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Sat, 17 Jan 2026 21:15:36 +0000</pubDate>
      <link>https://dev.to/naugtur/dont-we-all-look-forward-to-code-review-full-time-1la5</link>
      <guid>https://dev.to/naugtur/dont-we-all-look-forward-to-code-review-full-time-1la5</guid>
      <description>&lt;p&gt;I remember the time when getting your tests to pass and finishing up a pull request was not even half the calendar time it took to ship code because it had to be reviewed. And getting a review was not trivial. Somehow everyone wanted to do other things and convincing them to review a pull request was part of doing the work.&lt;/p&gt;

&lt;p&gt;Wait, that was yesterday!&lt;/p&gt;

&lt;p&gt;Now with coding agents producing up to an order of magnitude more code it's not a problem though, because we've suddenly fell in love with the process of reviewing code. Right? Right...?&lt;/p&gt;

&lt;p&gt;I mean, isn't it dreadful that you not only have to do code review for your peers but also for what you're making now too?&lt;/p&gt;

&lt;p&gt;But why is reviewing code not sparking the same joy as writing it? &lt;/p&gt;

&lt;p&gt;There's many reasons, but I want to focus on one. The friction in building the mental model.&lt;/p&gt;

&lt;p&gt;The process of understanding how code works is really one of building a mental model that represents the logic encoded in the program. Mental models are structures. Building a structure "from the ground up" is much easier than floating bits in space until it's rigid, if we take a physical metaphor. And that's my point - reading the code of a finished changeset is much less convenient for creating a mental model than experiencing various fragments of code going together in a reasonable order.&lt;/p&gt;

&lt;p&gt;Which brings me to my point - AI coding agents would be much better if they gave us the experience of a pair programmer instead of an experience of an intern turning in every result as if it was a take-home assignment.&lt;/p&gt;

&lt;p&gt;So imagine giving the agent a prompt or a spec and instead of getting a non-stop flow of tokens appear in the project files, being told a relatable story of how the logic flows through the change.&lt;/p&gt;

&lt;p&gt;Code appearing in a logical order, with live spoken commentary. You don't have to read 2 places at once. Human modalities (reading and listening) are utilized optimally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Let's start by creating the function with its arguments and defining input types.&lt;/li&gt;
&lt;li&gt;Now we're adding validation same as the function above&lt;/li&gt;
&lt;li&gt;Since that's reusable, let's extract it to the utils file&lt;/li&gt;
&lt;li&gt;We're now implementing the functionality split into 3 steps. &lt;/li&gt;
&lt;li&gt;Step 1 will call out to the implementation over there... &lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sort of presentation of the code would not only match the natural process in which the human builds the mental model, it would also eliminate the context switching and distractions creeping in while the agent is working.&lt;/p&gt;

&lt;p&gt;It should also scale to orchestrating multiple agents, where the work progresses while the leading agent schedules the work, controls the results and enqueues the walkthrough/explanation for the human in the loop.&lt;/p&gt;

&lt;p&gt;And then the obvious next step is to handle instant feedback and discussion, like a peer programmer would.&lt;/p&gt;

&lt;p&gt;I hope someone build this  :D&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codequality</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The missing link</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Tue, 23 Sep 2025 16:21:04 +0000</pubDate>
      <link>https://dev.to/naugtur/the-missing-link-3ejk</link>
      <guid>https://dev.to/naugtur/the-missing-link-3ejk</guid>
      <description>&lt;p&gt;Here's a riddle I posted&lt;/p&gt;

&lt;p&gt;Name the environment in which this code doesn't throw&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;globalThis&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addEventListener&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;globalThis&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addEventListener&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrototypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;where are we?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's in the script
&lt;/h2&gt;

&lt;p&gt;The script first ensures that &lt;code&gt;addEventListener&lt;/code&gt; is in &lt;code&gt;globalThis&lt;/code&gt;. But &lt;code&gt;in&lt;/code&gt; means as own property or anywhere on the prototype. So let's find it on the prototype by iterating down. We throw when found. &lt;br&gt;
Somehow, we run out of truthy prototypes before we find one that has an own property named &lt;code&gt;addEventListener&lt;/code&gt;. &lt;br&gt;
Last - as a helpful tip, the code uses &lt;code&gt;alert&lt;/code&gt; and it works.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's the environment
&lt;/h2&gt;

&lt;p&gt;Normally, when you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;globalThis&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addEventListener&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; has addEventListener`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; does NOT have addEventListener`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrototypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[object Window] does NOT have addEventListener
[object Window] does NOT have addEventListener
[object WindowProperties] does NOT have addEventListener
[object EventTarget] has addEventListener
[object Object] does NOT have addEventListener
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there's one magical place in the browser where that's not necessarily the case.&lt;/p&gt;

&lt;p&gt;When you create an extension, you can define a &lt;code&gt;contentscript&lt;/code&gt; that exists to let you interact with the &lt;code&gt;document&lt;/code&gt; of a website open in the browser. It's supposed to be isolated from the website's realm though, so that you have your own global context. &lt;/p&gt;

&lt;p&gt;The browsers took very different approaches to implementing the isolation. The Firefox implementation is changing the prototype chain  of the global and limiting it to window and its prototype, with nothing else visible via code, but with field lookup reaching down the prototype chain further. &lt;/p&gt;

&lt;p&gt;The same while loop gets us this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[object Window] does NOT have addEventListener
[object Window] does NOT have addEventListener
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But still,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addEventListener&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm not sure why the behavior is like that, but if I replace &lt;code&gt;globalThis&lt;/code&gt; with &lt;code&gt;window&lt;/code&gt;, I get a different list of prototypes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[object Window] does NOT have addEventListener
[object Window] does NOT have addEventListener
[object EventTarget] does NOT have addEventListener
[object EventTarget] has addEventListener
[object Object] does NOT have addEventListener
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And while I can understand cutting of a bit of prototype as a means of isolation, if it stays on &lt;code&gt;window&lt;/code&gt;, that's harder to explain.&lt;/p&gt;

&lt;p&gt;Somebody tell me what's going on :)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;update&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we've established that in Firefox contentscript this is true:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;globalThis&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using devtools, if you look into the &lt;code&gt;globalThis&lt;/code&gt; reference, it's being called &lt;code&gt;Sandbox&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For my usecase I was tempted to do &lt;code&gt;globalThis = window&lt;/code&gt; and move on, but that doesn't work. &lt;code&gt;globalThis.globalThis = window&lt;/code&gt; does have the expected result of replacing globalThis tho :D &lt;/p&gt;

&lt;p&gt;I didn't do it yet, because I don't know how much I'd break with it. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I will keep updating this&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>Sometimes the best thing to do is an explicit nothing</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Wed, 27 Aug 2025 09:07:34 +0000</pubDate>
      <link>https://dev.to/naugtur/sometimes-the-best-thing-to-do-is-an-explicit-nothing-2i71</link>
      <guid>https://dev.to/naugtur/sometimes-the-best-thing-to-do-is-an-explicit-nothing-2i71</guid>
      <description>&lt;p&gt;This is a long story about why I wrote this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  react-dom under LavaMoat
&lt;/h2&gt;

&lt;p&gt;While working on getting a project to work under &lt;a href="https://www.npmjs.com/package/@lavamoat/webpack" rel="noopener noreferrer"&gt;&lt;code&gt;@lavamoat/webpack&lt;/code&gt;&lt;/a&gt; I stumbled upon an issue where the whole thing would hang in Firefox (on my colleague's mac it would hang the entire browser)&lt;br&gt;
After a bunch of inspector sorcery I found out that the app is throwing &lt;code&gt;TypeError: can't redefine non-configurable property "event"&lt;/code&gt; faster than the browser can put together stacktraces for the errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9371ih4250jtldczez7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9371ih4250jtldczez7.png" alt=" " width="800" height="858"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The culprit for that was a line in react-dom&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fobq5snl14wh72q94lpjx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fobq5snl14wh72q94lpjx.png" alt=" " width="547" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's worth noting that contrary to what the comment says, Firefox implemented &lt;code&gt;window.event&lt;/code&gt; in 2019 so me finding this takes me a step closer to an Archeology major.&lt;br&gt;
Did I mention &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/event" rel="noopener noreferrer"&gt;&lt;code&gt;window.event&lt;/code&gt; is deprecated&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;But why are we getting an error in Firefox and not in Chrome despite them both implementing &lt;code&gt;window.event&lt;/code&gt; ?&lt;/p&gt;
&lt;h3&gt;
  
  
  The emulation LavaMoat does
&lt;/h3&gt;

&lt;p&gt;This section assumes you already know basics of what LavaMoat does from &lt;a href="https://lavamoat.github.io/about/runtime-environment/" rel="noopener noreferrer"&gt;lavamoat.github.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When providing a new global for each package with just the specified fields, we need to make sure that they actually work. And in the browser it's fairly common to have fields on &lt;code&gt;window&lt;/code&gt; that demand being on &lt;code&gt;window&lt;/code&gt; because there's hidden "internal slots" on the objects the functions check.&lt;/p&gt;

&lt;p&gt;What?&lt;br&gt;&lt;br&gt;
Let me explain with a code snippet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some functions demand that their &lt;code&gt;this&lt;/code&gt; is the &lt;code&gt;window&lt;/code&gt;. But the whole point of LavaMoat is to not give the real &lt;code&gt;window&lt;/code&gt; with all globals to every package in dependencies. &lt;/p&gt;

&lt;p&gt;So we need to give packages functions that wrap around functions and get/set pairs to then internally &lt;em&gt;unwrap&lt;/em&gt; to run the actual native implementation with the right &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So far so good.&lt;/p&gt;

&lt;p&gt;But then there's scuttling.&lt;/p&gt;

&lt;p&gt;In case a package gets enough references passed to it that it can reach the real &lt;code&gt;window&lt;/code&gt;, after LavaMoat makes copies of all globals it's destroying everything on the actual &lt;code&gt;globalThis&lt;/code&gt; by replacing it with a non-configurable getter that throws an error. &lt;/p&gt;

&lt;p&gt;Cool, huh?&lt;/p&gt;

&lt;p&gt;So that leaves us with react-dom running under LavaMoat with a policy that allows it write to &lt;code&gt;window.event&lt;/code&gt; while the real &lt;code&gt;window.event&lt;/code&gt; is long gone. Why the error tho? &lt;/p&gt;

&lt;h2&gt;
  
  
  window.event behavior
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;window.event&lt;/code&gt; is implemented with a setter that replaces itself with the value first time it's called. Why? Don't ask me, I didn't come up with it.&lt;/p&gt;

&lt;p&gt;Let me repeat that in JavaScript in case you know it better than English ;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we replace the original setter with the scuttling one (that's set to be &lt;code&gt;configurable: false&lt;/code&gt;) the original setter (that we still have a copy of) will fail to overwrite the value.&lt;/p&gt;

&lt;p&gt;Again, let me repeat that in JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;es&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOwnPropertyDescriptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;es&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fails silently in Chrome and loudly in FF&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If spec was supposed to cover all details of the standard implementation it would have to go into detail infinitely.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Wait, what?
&lt;/h2&gt;

&lt;p&gt;How is that a conclusion?&lt;/p&gt;

&lt;p&gt;Ok, last step you need before you'll understand.&lt;/p&gt;

&lt;p&gt;These are the setters in Chrome and Firefox respectively&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzmn0t7lx49whd7e3kte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzmn0t7lx49whd7e3kte.png" alt=" " width="473" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrw7rleji5u2z5sqjvue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrw7rleji5u2z5sqjvue.png" alt=" " width="532" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Can you spot the difference between the two setters?&lt;/p&gt;

&lt;p&gt;🎉 The one with &lt;code&gt;arguments&lt;/code&gt; and &lt;code&gt;caller&lt;/code&gt; is a sloppy mode function, so when it fails a defineProperty, it doesn't throw. 🎉&lt;/p&gt;

&lt;p&gt;And this tiny detail in an implementation of an old deprecated property that react-dom keeps alive in its codebase in case someone uses a 20+ years old event handler in react is enough to make an entire project explode in one browser and work in another.&lt;/p&gt;

&lt;p&gt;Takes me back to the early 2000s &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion, for real this time
&lt;/h2&gt;

&lt;p&gt;Now if you look at this line again, you should know what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;a getter is called on &lt;code&gt;event&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;its return value is passed to the setter&lt;/li&gt;
&lt;li&gt;the setter replaces &lt;code&gt;window.event&lt;/code&gt; with a value property&lt;/li&gt;
&lt;li&gt;LavaMoat sees a value and avoids wrapping/unwrapping it at all&lt;/li&gt;
&lt;li&gt;when code in a package does &lt;code&gt;window.event = {}&lt;/code&gt; it won't leak to the real global&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Update
&lt;/h2&gt;

&lt;p&gt;I defaulted to assign the current value to the &lt;code&gt;window.event&lt;/code&gt; to minimize the fragility if it becomes something else in the future. After some conversations under the links to this I posted to socials I think I'll go with &lt;code&gt;window.event = undefined&lt;/code&gt; for LavaMoat, because there's a risk that it might capture an actual event object with references I don't want available to some of the packages.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>All ways to get a DOM element reference</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Wed, 21 May 2025 12:07:48 +0000</pubDate>
      <link>https://dev.to/naugtur/all-ways-to-get-a-dom-element-reference-57e2</link>
      <guid>https://dev.to/naugtur/all-ways-to-get-a-dom-element-reference-57e2</guid>
      <description>&lt;p&gt;An attempt to build a complete list of all the ways a DOM node could be created or accessed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A study in ambient authority&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The target audience of this post is mostly my future self. No warranty of any kind, no claims this is complete.&lt;/p&gt;

&lt;p&gt;Also, note that Gal Weizman probably has more comprehensive research on the topic but this is intentionally dense and narrow in scope. Also, it's easier for me to dig up my post than message Gal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating DOM nodes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Standard API&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Namespaced element&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElementNS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.w3.org/1999/xhtml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// HTML parsing APIs&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DOMParser&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Range API&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRange&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;createContextualFragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Template element&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// iframe with srcdoc (creates a new DOM tree)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;iframe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcdoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// access via iframe.contentDocument.body.firstChild&lt;/span&gt;

&lt;span class="c1"&gt;// XSLTProcessor (rare, but possible)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;xslt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DOMParser&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`&amp;lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"&amp;gt;
     &amp;lt;xsl:template match="/"&amp;gt;&amp;lt;div xmlns="http://www.w3.org/1999/xhtml"/&amp;gt;&amp;lt;/xsl:template&amp;gt;
   &amp;lt;/xsl:stylesheet&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;XSLTProcessor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nx"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importStylesheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xslt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transformToFragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// document.implementation.createDocument (XML, but can create elements)&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.w3.org/1999/xhtml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.implementation.createHTMLDocument&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHTMLDocument&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Custom Elements (constructor, if not banned)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDiv&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLDivElement&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt; &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyDiv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyDiv&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Using importNode (cloning from another document)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHTMLDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Using cloneNode on a template&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finding existing DOM nodes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Standard selectors&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myDiv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myClass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myDivName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Traversal APIs&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastChild&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;childNodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextSibling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousSibling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousElementSibling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// TreeWalker&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTreeWalker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NodeFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SHOW_ELEMENT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;nextNode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// NodeIterator&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNodeIterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NodeFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SHOW_ELEMENT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;nextNode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Range API&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRange&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startContainer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Event target (from an event handler)&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Shadow DOM&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;shadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="nx"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Selection API&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSelection&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;anchorNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Active element&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// OwnerDocument&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ownerDocument&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ParentNode API&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Custom Elements (via lifecycle callbacks)&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// HTMLCollection/NodeList iteration&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* node is a reference */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// iframe content&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;iframe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contentDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// window.frameElement&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frameElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.currentScript&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentScript&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.scripts&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scripts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// document.forms, document.images, document.links, document.anchors&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anchors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// document.head, document.body, document.documentElement&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.defaultView (returns window, but can access DOM via window.document)&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.adoptNode (returns a reference to the adopted node)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adoptNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// document.importNode (returns a reference to the imported node)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// document.elementFromPoint&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elementFromPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// document.elementsFromPoint&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elementsFromPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// document.scrollingElement&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollingElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.pointerLockElement&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pointerLockElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.fullscreenElement&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullscreenElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// document.getRootNode&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRootNode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// document.getSelection&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSelection&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;focusNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// MutationObserver (callback receives references to added/removed nodes)&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MutationObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;mutations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mutations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addedNodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;childList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// CSSStyleSheet.ownerNode&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;styleSheets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;ownerNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// HTMLTableElement.rows/cells&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;table&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// HTMLFormElement.elements&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// HTMLSelectElement.options&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// HTMLMapElement.areas&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;areas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// HTMLMediaElement.textTracks/cues&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textTracks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;cues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// SVG-specific: getElementById, getElementsByTagName, etc. on SVGSVGElement&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svgDiv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// XPath&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;XPathResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FIRST_ORDERED_NODE_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;singleNodeValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Globally Available DOM API Types
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Node Types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node&lt;/li&gt;
&lt;li&gt;Element&lt;/li&gt;
&lt;li&gt;Document&lt;/li&gt;
&lt;li&gt;DocumentFragment&lt;/li&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;li&gt;Comment&lt;/li&gt;
&lt;li&gt;CDATASection         // XML documents only&lt;/li&gt;
&lt;li&gt;ProcessingInstruction&lt;/li&gt;
&lt;li&gt;DocumentType&lt;/li&gt;
&lt;li&gt;Attr&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Element Subclasses
&lt;/h3&gt;

&lt;h4&gt;
  
  
  HTML Elements (all inherit from &lt;code&gt;HTMLElement&lt;/code&gt;)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;HTMLElement&lt;/li&gt;
&lt;li&gt;HTMLAnchorElement&lt;/li&gt;
&lt;li&gt;HTMLAreaElement&lt;/li&gt;
&lt;li&gt;HTMLAudioElement&lt;/li&gt;
&lt;li&gt;HTMLBaseElement&lt;/li&gt;
&lt;li&gt;HTMLBodyElement&lt;/li&gt;
&lt;li&gt;HTMLBRElement&lt;/li&gt;
&lt;li&gt;HTMLButtonElement&lt;/li&gt;
&lt;li&gt;HTMLCanvasElement&lt;/li&gt;
&lt;li&gt;HTMLDataElement&lt;/li&gt;
&lt;li&gt;HTMLDataListElement&lt;/li&gt;
&lt;li&gt;HTMLDetailsElement&lt;/li&gt;
&lt;li&gt;HTMLDialogElement&lt;/li&gt;
&lt;li&gt;HTMLDivElement&lt;/li&gt;
&lt;li&gt;HTMLDListElement&lt;/li&gt;
&lt;li&gt;HTMLEmbedElement&lt;/li&gt;
&lt;li&gt;HTMLFieldSetElement&lt;/li&gt;
&lt;li&gt;HTMLFormElement&lt;/li&gt;
&lt;li&gt;HTMLHeadingElement&lt;/li&gt;
&lt;li&gt;HTMLHeadElement&lt;/li&gt;
&lt;li&gt;HTMLHRElement&lt;/li&gt;
&lt;li&gt;HTMLHtmlElement&lt;/li&gt;
&lt;li&gt;HTMLIFrameElement&lt;/li&gt;
&lt;li&gt;HTMLImageElement&lt;/li&gt;
&lt;li&gt;HTMLInputElement&lt;/li&gt;
&lt;li&gt;HTMLLabelElement&lt;/li&gt;
&lt;li&gt;HTMLLegendElement&lt;/li&gt;
&lt;li&gt;HTMLLIElement&lt;/li&gt;
&lt;li&gt;HTMLLinkElement&lt;/li&gt;
&lt;li&gt;HTMLMapElement&lt;/li&gt;
&lt;li&gt;HTMLMetaElement&lt;/li&gt;
&lt;li&gt;HTMLMeterElement&lt;/li&gt;
&lt;li&gt;HTMLModElement&lt;/li&gt;
&lt;li&gt;HTMLOListElement&lt;/li&gt;
&lt;li&gt;HTMLObjectElement&lt;/li&gt;
&lt;li&gt;HTMLOptGroupElement&lt;/li&gt;
&lt;li&gt;HTMLOptionElement&lt;/li&gt;
&lt;li&gt;HTMLOutputElement&lt;/li&gt;
&lt;li&gt;HTMLParagraphElement&lt;/li&gt;
&lt;li&gt;HTMLParamElement&lt;/li&gt;
&lt;li&gt;HTMLPictureElement&lt;/li&gt;
&lt;li&gt;HTMLPreElement&lt;/li&gt;
&lt;li&gt;HTMLProgressElement&lt;/li&gt;
&lt;li&gt;HTMLQuoteElement&lt;/li&gt;
&lt;li&gt;HTMLScriptElement&lt;/li&gt;
&lt;li&gt;HTMLSelectElement&lt;/li&gt;
&lt;li&gt;HTMLSlotElement&lt;/li&gt;
&lt;li&gt;HTMLSourceElement&lt;/li&gt;
&lt;li&gt;HTMLSpanElement&lt;/li&gt;
&lt;li&gt;HTMLStyleElement&lt;/li&gt;
&lt;li&gt;HTMLTableCaptionElement&lt;/li&gt;
&lt;li&gt;HTMLTableCellElement&lt;/li&gt;
&lt;li&gt;HTMLTableColElement&lt;/li&gt;
&lt;li&gt;HTMLTableElement&lt;/li&gt;
&lt;li&gt;HTMLTimeElement&lt;/li&gt;
&lt;li&gt;HTMLTitleElement&lt;/li&gt;
&lt;li&gt;HTMLTableRowElement&lt;/li&gt;
&lt;li&gt;HTMLTableSectionElement&lt;/li&gt;
&lt;li&gt;HTMLTemplateElement&lt;/li&gt;
&lt;li&gt;HTMLTextAreaElement&lt;/li&gt;
&lt;li&gt;HTMLTrackElement&lt;/li&gt;
&lt;li&gt;HTMLUListElement&lt;/li&gt;
&lt;li&gt;HTMLUnknownElement&lt;/li&gt;
&lt;li&gt;HTMLVideoElement&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  SVG Elements (all inherit from &lt;code&gt;SVGElement&lt;/code&gt;)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;SVGElement&lt;/li&gt;
&lt;li&gt;SVGSVGElement&lt;/li&gt;
&lt;li&gt;SVGCircleElement&lt;/li&gt;
&lt;li&gt;SVGClipPathElement&lt;/li&gt;
&lt;li&gt;SVGDefsElement&lt;/li&gt;
&lt;li&gt;SVGEllipseElement&lt;/li&gt;
&lt;li&gt;SVGFEBlendElement&lt;/li&gt;
&lt;li&gt;SVGFEColorMatrixElement&lt;/li&gt;
&lt;li&gt;SVGFEComponentTransferElement&lt;/li&gt;
&lt;li&gt;SVGFECompositeElement&lt;/li&gt;
&lt;li&gt;SVGFEConvolveMatrixElement&lt;/li&gt;
&lt;li&gt;SVGFEDiffuseLightingElement&lt;/li&gt;
&lt;li&gt;SVGFEDisplacementMapElement&lt;/li&gt;
&lt;li&gt;SVGFEDistantLightElement&lt;/li&gt;
&lt;li&gt;SVGFEDropShadowElement&lt;/li&gt;
&lt;li&gt;SVGFEFloodElement&lt;/li&gt;
&lt;li&gt;SVGFEFuncAElement&lt;/li&gt;
&lt;li&gt;SVGFEFuncBElement&lt;/li&gt;
&lt;li&gt;SVGFEFuncGElement&lt;/li&gt;
&lt;li&gt;SVGFEFuncRElement&lt;/li&gt;
&lt;li&gt;SVGFEGaussianBlurElement&lt;/li&gt;
&lt;li&gt;SVGFEImageElement&lt;/li&gt;
&lt;li&gt;SVGFEMergeElement&lt;/li&gt;
&lt;li&gt;SVGFEMergeNodeElement&lt;/li&gt;
&lt;li&gt;SVGFEMorphologyElement&lt;/li&gt;
&lt;li&gt;SVGFEOffsetElement&lt;/li&gt;
&lt;li&gt;SVGFEPointLightElement&lt;/li&gt;
&lt;li&gt;SVGFESpecularLightingElement&lt;/li&gt;
&lt;li&gt;SVGFESpotLightElement&lt;/li&gt;
&lt;li&gt;SVGFETileElement&lt;/li&gt;
&lt;li&gt;SVGFETurbulenceElement&lt;/li&gt;
&lt;li&gt;SVGFilterElement&lt;/li&gt;
&lt;li&gt;SVGForeignObjectElement&lt;/li&gt;
&lt;li&gt;SVGGElement&lt;/li&gt;
&lt;li&gt;SVGImageElement&lt;/li&gt;
&lt;li&gt;SVGLineElement&lt;/li&gt;
&lt;li&gt;SVGLinearGradientElement&lt;/li&gt;
&lt;li&gt;SVGMarkerElement&lt;/li&gt;
&lt;li&gt;SVGMaskElement&lt;/li&gt;
&lt;li&gt;SVGPathElement&lt;/li&gt;
&lt;li&gt;SVGPatternElement&lt;/li&gt;
&lt;li&gt;SVGPolygonElement&lt;/li&gt;
&lt;li&gt;SVGPolylineElement&lt;/li&gt;
&lt;li&gt;SVGRadialGradientElement&lt;/li&gt;
&lt;li&gt;SVGRectElement&lt;/li&gt;
&lt;li&gt;SVGStopElement&lt;/li&gt;
&lt;li&gt;SVGSwitchElement&lt;/li&gt;
&lt;li&gt;SVGSymbolElement&lt;/li&gt;
&lt;li&gt;SVGTSpanElement&lt;/li&gt;
&lt;li&gt;SVGTextElement&lt;/li&gt;
&lt;li&gt;SVGTextPathElement&lt;/li&gt;
&lt;li&gt;SVGTitleElement&lt;/li&gt;
&lt;li&gt;SVGUseElement&lt;/li&gt;
&lt;li&gt;SVGViewElement&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  MathML Elements
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;MathMLElement&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Document Types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;HTMLDocument&lt;/li&gt;
&lt;li&gt;XMLDocument&lt;/li&gt;
&lt;li&gt;SVGDocument&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other DOM-Related Classes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CharacterData&lt;/li&gt;
&lt;li&gt;Range&lt;/li&gt;
&lt;li&gt;Selection&lt;/li&gt;
&lt;li&gt;MutationObserver&lt;/li&gt;
&lt;li&gt;MutationRecord&lt;/li&gt;
&lt;li&gt;TreeWalker&lt;/li&gt;
&lt;li&gt;NodeIterator&lt;/li&gt;
&lt;li&gt;NamedNodeMap&lt;/li&gt;
&lt;li&gt;DOMTokenList&lt;/li&gt;
&lt;li&gt;DOMStringMap&lt;/li&gt;
&lt;li&gt;DOMRect&lt;/li&gt;
&lt;li&gt;DOMRectList&lt;/li&gt;
&lt;li&gt;DOMPoint&lt;/li&gt;
&lt;li&gt;DOMPointReadOnly&lt;/li&gt;
&lt;li&gt;DOMMatrix&lt;/li&gt;
&lt;li&gt;DOMMatrixReadOnly&lt;/li&gt;
&lt;li&gt;DOMParser&lt;/li&gt;
&lt;li&gt;XMLSerializer&lt;/li&gt;
&lt;li&gt;XPathEvaluator&lt;/li&gt;
&lt;li&gt;XPathResult&lt;/li&gt;
&lt;li&gt;XPathExpression&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  NodeList/Collections
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;NodeList&lt;/li&gt;
&lt;li&gt;HTMLCollection&lt;/li&gt;
&lt;li&gt;HTMLAllCollection&lt;/li&gt;
&lt;li&gt;HTMLFormControlsCollection&lt;/li&gt;
&lt;li&gt;HTMLOptionsCollection&lt;/li&gt;
&lt;li&gt;SVGLengthList&lt;/li&gt;
&lt;li&gt;SVGNumberList&lt;/li&gt;
&lt;li&gt;SVGPointList&lt;/li&gt;
&lt;li&gt;SVGStringList&lt;/li&gt;
&lt;li&gt;SVGTransformList&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Attribute/Style/Other
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Attr&lt;/li&gt;
&lt;li&gt;NamedNodeMap&lt;/li&gt;
&lt;li&gt;CSSStyleDeclaration&lt;/li&gt;
&lt;li&gt;StyleSheet&lt;/li&gt;
&lt;li&gt;CSSStyleSheet&lt;/li&gt;
&lt;li&gt;CSSRuleList&lt;/li&gt;
&lt;li&gt;CSSRule&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Miscellaneous
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Comment&lt;/li&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;li&gt;ProcessingInstruction&lt;/li&gt;
&lt;li&gt;CDATASection&lt;/li&gt;
&lt;li&gt;DocumentType&lt;/li&gt;
&lt;li&gt;ShadowRoot&lt;/li&gt;
&lt;li&gt;DocumentFragment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Event Classes
&lt;/h3&gt;

&lt;p&gt;(tend to have references to DOM)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Event&lt;/li&gt;
&lt;li&gt;CustomEvent&lt;/li&gt;
&lt;li&gt;UIEvent&lt;/li&gt;
&lt;li&gt;MouseEvent&lt;/li&gt;
&lt;li&gt;KeyboardEvent&lt;/li&gt;
&lt;li&gt;FocusEvent&lt;/li&gt;
&lt;li&gt;InputEvent&lt;/li&gt;
&lt;li&gt;TouchEvent&lt;/li&gt;
&lt;li&gt;PointerEvent&lt;/li&gt;
&lt;li&gt;WheelEvent&lt;/li&gt;
&lt;li&gt;CompositionEvent&lt;/li&gt;
&lt;li&gt;DragEvent&lt;/li&gt;
&lt;li&gt;ClipboardEvent&lt;/li&gt;
&lt;li&gt;AnimationEvent&lt;/li&gt;
&lt;li&gt;TransitionEvent&lt;/li&gt;
&lt;li&gt;PopStateEvent&lt;/li&gt;
&lt;li&gt;HashChangeEvent&lt;/li&gt;
&lt;li&gt;PageTransitionEvent&lt;/li&gt;
&lt;li&gt;ProgressEvent&lt;/li&gt;
&lt;li&gt;StorageEvent&lt;/li&gt;
&lt;li&gt;MessageEvent&lt;/li&gt;
&lt;li&gt;ErrorEvent&lt;/li&gt;
&lt;li&gt;PromiseRejectionEvent&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Same but with inheritance depicted
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TD

  %% Inheritance
  EventTarget --&amp;gt;|inherits| Node
  EventTarget --&amp;gt;|inherits| Window
  EventTarget --&amp;gt;|inherits| XMLHttpRequest
  EventTarget --&amp;gt;|inherits| EventSource
  EventTarget --&amp;gt;|inherits| WebSocket
  EventTarget --&amp;gt;|inherits| Worker
  EventTarget --&amp;gt;|inherits| MessagePort
  EventTarget --&amp;gt;|inherits| BroadcastChannel
  EventTarget --&amp;gt;|inherits| FileReader
  EventTarget --&amp;gt;|inherits| MediaStream
  EventTarget --&amp;gt;|inherits| MediaRecorder
  EventTarget --&amp;gt;|inherits| RTCPeerConnection
  EventTarget --&amp;gt;|inherits| Event

  Node --&amp;gt;|inherits| Document
  Node --&amp;gt;|inherits| DocumentFragment
  Node --&amp;gt;|inherits| Element
  Node --&amp;gt;|inherits| Text
  Node --&amp;gt;|inherits| Comment
  Node --&amp;gt;|inherits| CDATASection
  Node --&amp;gt;|inherits| ProcessingInstruction
  Node --&amp;gt;|inherits| DocumentType
  Node --&amp;gt;|inherits| Attr

  CharacterData --&amp;gt;|inherits| Text
  CharacterData --&amp;gt;|inherits| Comment
  CharacterData --&amp;gt;|inherits| CDATASection

  Document --&amp;gt;|inherits| XMLDocument
  Document --&amp;gt;|inherits| HTMLDocument
  Document --&amp;gt;|inherits| SVGDocument

  Element --&amp;gt;|inherits| SVGElement
  Element --&amp;gt;|inherits| MathMLElement
  Element --&amp;gt;|inherits| HTMLElement

  DocumentFragment --&amp;gt;|inherits| ShadowRoot

  %% Aggregation/Fields

  NodeList -- "item[]" --&amp;gt; Node
  HTMLCollection -- "item[]" --&amp;gt; Element
  NamedNodeMap -- "item[]" --&amp;gt; Attr
  DOMTokenList -- "item[]" --&amp;gt; string
  DOMStringMap -- "item[]" --&amp;gt; string

  Range -- "startContainer" --&amp;gt; Node
  Range -- "endContainer" --&amp;gt; Node

  Selection -- "anchorNode" --&amp;gt; Node
  Selection -- "focusNode" --&amp;gt; Node

  MutationRecord -- "target" --&amp;gt; Node
  MutationRecord -- "addedNodes" --&amp;gt; NodeList
  MutationRecord -- "removedNodes" --&amp;gt; NodeList

  TreeWalker -- "root" --&amp;gt; Node
  TreeWalker -- "currentNode" --&amp;gt; Node

  NodeIterator -- "root" --&amp;gt; Node
  NodeIterator -- "referenceNode" --&amp;gt; Node

  ShadowRoot -- "host" --&amp;gt; Element

  Attr -- "ownerElement" --&amp;gt; Element

  Document -- "documentElement" --&amp;gt; Element
  Document -- "body" --&amp;gt; Element
  Document -- "head" --&amp;gt; Element

  Element -- "attributes" --&amp;gt; NamedNodeMap
  Element -- "children" --&amp;gt; HTMLCollection
  Element -- "classList" --&amp;gt; DOMTokenList
  Element -- "dataset" --&amp;gt; DOMStringMap

  DocumentFragment -- "childNodes" --&amp;gt; NodeList

  %% Miscellaneous
  DOMRectList -- "item[]" --&amp;gt; DOMRect
  CSSRuleList -- "item[]" --&amp;gt; CSSRule
  StyleSheet -- "ownerNode" --&amp;gt; Node
  CSSStyleSheet -- "ownerNode" --&amp;gt; Node

  %% Standalone classes (not directly connected)
  DOMRect
  DOMPoint
  DOMPointReadOnly
  DOMMatrix
  DOMMatrixReadOnly
  DOMParser
  XMLSerializer
  XPathEvaluator
  XPathResult
  XPathExpression

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A Phish on a Fork, no Chips</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Wed, 29 Jan 2025 19:30:55 +0000</pubDate>
      <link>https://dev.to/naugtur/a-phish-on-a-fork-no-chips-52cc</link>
      <guid>https://dev.to/naugtur/a-phish-on-a-fork-no-chips-52cc</guid>
      <description>&lt;p&gt;So you were told that this is the safest way to install a package from github with npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"test262": "git+https://github.com/tc39/test262.git#f1ffb1e95fad3468a771a6753595db4e6f55f6bb",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and this is the safest way to install an action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uses: actions/checkout@47176dbabcf093ccbef4a6689f7c80eb4c7693d6 # v4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a very good recommendation. &lt;/p&gt;

&lt;p&gt;Because commit hashes are practically globally unique, the maintainer can't make any changes to what you'll get (like they would if you used #branch or #tag)&lt;/p&gt;

&lt;p&gt;There's one thing you need to look out for as you update the commit hashes though. &lt;/p&gt;

&lt;h3&gt;
  
  
  𐂐 The fork
&lt;/h3&gt;

&lt;p&gt;Both examples above will happily install and work even though the commit hashes you see actually exist in forks I made, not the original repositories.&lt;/p&gt;

&lt;h3&gt;
  
  
  🐟 The phish
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;find a popular repository that gets installed as a package by package managers or as a GitHub Action. &lt;/li&gt;
&lt;li&gt;fork it and introduce &lt;del&gt;malware&lt;/del&gt; &lt;em&gt;opinionated improvements&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;add another commit that looks like a proper version update&lt;/li&gt;
&lt;li&gt;find the security-minded users who have been told that it's best to pin the version to the specific commit hash&lt;/li&gt;
&lt;li&gt;offer an update to latest, but put your own commit hash in the PR&lt;/li&gt;
&lt;li&gt;🍿&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;It's a phish on a fork, see?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The rest of this piece explains the problem and offers tools to avoid the risks. Scroll to the bottom to learn what to use.&lt;/p&gt;




&lt;h2&gt;
  
  
  The full story
&lt;/h2&gt;

&lt;p&gt;Remember how git commits are now hashed with &lt;code&gt;sha256&lt;/code&gt; because &lt;code&gt;sha1&lt;/code&gt; had collisions you could generate if you could get your hands on a bunch of compute?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In case you're into tech history rabbit holes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html" rel="noopener noreferrer"&gt;https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://web.archive.org/web/20120701221418/http://kerneltrap.org/mailarchive/git/2006/8/28/211065" rel="noopener noreferrer"&gt;http://web.archive.org/web/20120701221418/http://kerneltrap.org/mailarchive/git/2006/8/28/211065&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.blog/news-insights/company-news/sha-1-collision-detection-on-github-com/" rel="noopener noreferrer"&gt;https://github.blog/news-insights/company-news/sha-1-collision-detection-on-github-com/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anyway..&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;sha256&lt;/code&gt; has 2^256 possible hashes. That is about 10^78. There's about &lt;a href="https://proofwiki.org/wiki/Number_of_Atoms_in_Observable_Universe" rel="noopener noreferrer"&gt;10^80 atoms in the Observable Universe&lt;/a&gt;. Git commit hashes are practically globally unique. &lt;/p&gt;

&lt;p&gt;And that's great for a lot of reasons.&lt;br&gt;&lt;br&gt;
I'd like to explore one of these. &lt;/p&gt;

&lt;p&gt;GitHub is storing an unbelievable number of git repositories. The more popular ones get forked tens of thousands of times. Imagine copying the entire history and structure of the repository for every fork!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63lsqp83p8que4p6se3b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63lsqp83p8que4p6se3b.png" alt="React repo forks and stars" width="500" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to the uniqueness of commit IDs, you only ever need to store each one once. Regardless of whether it's in the original or a forked repo, the content of the commit with that specific ID will always be the same.&lt;/p&gt;

&lt;p&gt;What a great optimization! Without it, the &lt;code&gt;fork and PR&lt;/code&gt; workflow would not have been possible!&lt;/p&gt;

&lt;p&gt;That also means if you try to load a commit hash from a repo, GitHub will not differentiate between your repo and a fork when fetching it from the database. &lt;/p&gt;

&lt;p&gt;This has caused issues before, &lt;a href="https://arstechnica.com/information-technology/2020/11/githubs-source-code-was-leaked-on-github-last-night-sort-of/" rel="noopener noreferrer"&gt;like when youtube-dl folks confused everyone into thinking GitHub source code was published to the DMCA repo&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  🍟 The chip
&lt;/h3&gt;

&lt;p&gt;As a remediation, GitHub has introduced a warning &lt;a href="https://en.wikipedia.org/wiki/Chip_(GUI)" rel="noopener noreferrer"&gt;chip&lt;/a&gt; in the UI so that if you go to a repository and put commit ID from a fork in the URL you get a hint something's not right.&lt;br&gt;&lt;br&gt;
e.g. This is what UI shows for my fork of the checkout action&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/actions/checkout/commit/47176dbabcf093ccbef4a6689f7c80eb4c7693d6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk8g3sxhdxl9o2xwhjuzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk8g3sxhdxl9o2xwhjuzb.png" alt="git-safe-dependencies on npm" width="749" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I know calling it a chip is a bit of a stretch but it makes for a nice pun in the article title and hardcore designers are not my target audience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don't have to tell you that package installation doesn't have much UI space to work with, which results in no warning there, so you don't get the chip.&lt;/p&gt;

&lt;p&gt;Would you like to see a warning? Keep reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoiding the phish on a fork
&lt;/h2&gt;

&lt;p&gt;You could take every commit ID and put it in the URL for the repository you expected to install from and check whether the warning chip shows. But I've been involved in software security long enough to know you won't. &lt;/p&gt;

&lt;p&gt;People often lack the patience to review security risk warnings even if they're provided to them inline, in the PR they're working on approving. I doubt they'd be willing to get out of their way to put together the URL they need to look up.&lt;/p&gt;

&lt;h3&gt;
  
  
  🍣 A solution that, ehm, &lt;em&gt;scales&lt;/em&gt; 🫣
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Cringe all you want, I'll squeeze the last drop out of this pun.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I found out how GitHub decides whether to show the chip, added all other &lt;del&gt;hatered&lt;/del&gt; best practices I have for using git dependencies and created &lt;a href="https://www.npmjs.com/package/@lavamoat/git-safe-dependencies" rel="noopener noreferrer"&gt;this tool&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@lavamoat/git-safe-dependencies" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhphmy99n3bhweodduyjd.png" alt="git-safe-dependencies" width="556" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Credit for the git-safe name goes to &lt;a href="https://github.com/leotm" rel="noopener noreferrer"&gt;Leo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Curious to know what it can do? Are you &lt;em&gt;hooked&lt;/em&gt;? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ok, ok. I'll stop now.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  The &lt;code&gt;@lavamoat/git-safe-dependencies&lt;/code&gt; validator
&lt;/h4&gt;

&lt;p&gt;What does it do? (as of Jan 2025)&lt;/p&gt;

&lt;p&gt;Current version supports processing your package.json and lockfile as one command and a separate one for scanning workflow yaml files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validates you only directly depend on git repos and actions pinned to commit id (GH workflows, package.json direct dependencies)&lt;/li&gt;
&lt;li&gt;validates that commit id belongs to the repository you intended to install from for both direct and transitive dependencies (lockfile, workflows)&lt;/li&gt;
&lt;li&gt;makes sure resolved URL in lockfile matches pakcage.json (prevents tampering with lockfile)&lt;/li&gt;
&lt;li&gt;complains if the git URL is not pointing to GitHub (lockfile)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do I want to add?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;warning if the package name matches a package that exists on npm&lt;/li&gt;
&lt;li&gt;warning if the git dependency is trying to run scripts on install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's all free and opensource. Like all other protections that we build at &lt;a href="https://lavamoat.github.io" rel="noopener noreferrer"&gt;LavaMoat&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Git safe friends! 🫡&lt;/p&gt;

</description>
      <category>security</category>
      <category>github</category>
      <category>npm</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>How private are your class #private fields?</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Fri, 02 Aug 2024 09:38:09 +0000</pubDate>
      <link>https://dev.to/naugtur/how-private-are-your-class-private-fields-m8n</link>
      <guid>https://dev.to/naugtur/how-private-are-your-class-private-fields-m8n</guid>
      <description>&lt;p&gt;The word "private" is defined as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;belonging to or for the use of one particular person or group of people only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's figure out who those people are.&lt;/p&gt;

&lt;h3&gt;
  
  
  EcmaScript Class
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getPrivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;otherInstance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;otherInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// BB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In native classes the private reference belongs to the class and every instance of that class can access other instances' private field values.&lt;/p&gt;

&lt;p&gt;Ok, so this is fine. All I need to do to avoid giving away my private fields is to not have a method that uses them from a reference given to me in input.&lt;/p&gt;

&lt;p&gt;Well, yes, but &lt;code&gt;this&lt;/code&gt; reference is also input to functions in JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getMyPrivate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMyPrivate&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// AA&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMyPrivate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)());&lt;/span&gt; &lt;span class="c1"&gt;// AA&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Would type-checking help?
&lt;/h3&gt;

&lt;p&gt;Let's take a look at a similar example in TypeScript.&lt;/p&gt;

&lt;p&gt;Our adversary is trying to read private fields from our classes at runtime. All type safety is resolved at compile time though. &lt;br&gt;
Let me remind you what a wise man once said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TypeScript is a seatbelt you wear while the car is stopped and unbuckle when you start the engine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's look at this typescript class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TsClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getPrivate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;privateField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TsClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TsClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrivate&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// AA&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_TsClass_privateField.get(b)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// BB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't fail to compile because the adversarial code is in a string, but this just emulates an XSS or supply chain attack.&lt;/p&gt;

&lt;p&gt;Why does it work? Well, this is the result of running the sample through &lt;code&gt;tsc&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;__classPrivateFieldSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__classPrivateFieldSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;m&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Private method is not writable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Private accessor was defined without a setter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cannot write private member to an object whose class did not declare it&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;__classPrivateFieldGet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__classPrivateFieldGet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Private accessor was defined without a getter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cannot read private member from an object whose class did not declare it&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;m&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;_TsClass_privateField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TsClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Private field&lt;/span&gt;
        &lt;span class="nx"&gt;_TsClass_privateField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;__classPrivateFieldSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_TsClass_privateField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;getPrivate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;__classPrivateFieldGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_TsClass_privateField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;_TsClass_privateField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WeakMap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TsClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TsClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrivate&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_TsClass_privateField.get(b)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's all represented with a conventionally named WeakMap.&lt;/p&gt;

&lt;p&gt;You can target es2022 or above to get TypeScript to generate the same code as in the EcmaScript example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is anything private?
&lt;/h3&gt;

&lt;p&gt;Yes. It's the good old closures. Functional scope is the real private thing in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;NotAClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actuallyPrivate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;doSomethingWithPrivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;actuallyPrivate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NotAClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doSomethingWithPrivate&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// CC-DD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's really private.&lt;/p&gt;

&lt;p&gt;Until you consider the possibility of prototype poisoning&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;join&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doSomethingWithPrivate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="c1"&gt;// logs: join [ 'CC', 'DD' ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But that's a whole different story...&lt;/p&gt;

&lt;p&gt;If you're interested, check out my defensive-coding training or look into tools that can prevent prototype poisoning and much more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lavamoat.github.io/" rel="noopener noreferrer"&gt;https://lavamoat.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/endojs/endo" rel="noopener noreferrer"&gt;https://github.com/endojs/endo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>security</category>
      <category>lavamoat</category>
    </item>
    <item>
      <title>GPT teaches me how to make my logic sync and async at the same time with trampolines</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Thu, 11 Apr 2024 22:03:48 +0000</pubDate>
      <link>https://dev.to/naugtur/gpt-teaches-me-how-to-make-my-logic-sync-and-async-at-the-same-time-with-trampolines-4hnl</link>
      <guid>https://dev.to/naugtur/gpt-teaches-me-how-to-make-my-logic-sync-and-async-at-the-same-time-with-trampolines-4hnl</guid>
      <description>&lt;p&gt;How can I have one implementation of some complex logic that can call out to sync or async hooks where the async one needs to be properly awaited each time?&lt;/p&gt;

&lt;p&gt;I told ChatGPT to teach me that. Below is our (heavily/extensively/drastically/substantially/profoundly redacted and fixed) chat log.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;in javascript, I have a function that's accepting a hook as input, runs a few synchronous operations, calls the hook and runs a few synchronous operations on the results. You can represent the operations as simple mathematical operations for the examples. I need an implementation that shares only one implementation of the operations but has two versions of the function - one that's asynchronous and accepts an async hook and awaits it, the other fully synchronous and accepting a synchronous hook.&lt;br&gt;
I was told to use generators and to build a trampoline. I need an example of what that could look like with an explanation of the trampoline.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;//the prompt was longer and contained snippets from tips I got from humans&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;To implement the solution you're looking for, we'll start by creating a generic function that can perform operations both synchronously and asynchronously, depending on the hook it receives. This function will be a generator, allowing us to use &lt;code&gt;yield&lt;/code&gt; to handle both synchronous and asynchronous operations in a unified way.&lt;/p&gt;

&lt;p&gt;The key concept here is the use of a "trampoline" function. A trampoline in this context is a mechanism that iteratively executes generator functions without growing the call stack. This is crucial for handling potentially deep or infinite recursion without causing a stack overflow. For asynchronous operations, the trampoline will use promises to handle the asynchronous yields.&lt;/p&gt;

&lt;p&gt;Let's start with an example of the operations and the generator function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generator function accepting a hook&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// First operation&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nf"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Call the hook, which can be sync or async&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Operation on the hook's result&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's implement two trampoline functions, one for synchronous execution and another for asynchronous execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Synchronous trampoline&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// Asynchronous trampoline&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;asyncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Editor note: I fixed the implementation here, async trampoline was wrong and didn't work. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With these trampolines, you can now execute your generator function either synchronously or asynchronously, depending on the nature of the hook you're passing. Here's how you would use them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Synchronous hook&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syncHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Asynchronous hook&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;asyncHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// Execute synchronously&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;syncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;syncHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;done:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;syncResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output will depend on operations and hook&lt;/span&gt;

&lt;span class="c1"&gt;// Execute asynchronously&lt;/span&gt;
&lt;span class="nf"&gt;asyncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asyncHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;done:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output will depend on operations and hook&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach allows you to maintain a single implementation of your operations and seamlessly switch between synchronous and asynchronous execution by choosing the appropriate trampoline function. The generator function acts as a bridge, using &lt;code&gt;yield&lt;/code&gt; to pause execution at the hook call, which can then be handled either synchronously or asynchronously by the trampoline.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;One more complication. operationsWithHook calls itself recursively if the current result is below N. How would I wire that up?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;To handle recursion within your &lt;code&gt;operationsWithHook&lt;/code&gt; generator function, especially when deciding whether to recurse based on the result of calling the hook, you can use &lt;code&gt;yield*&lt;/code&gt; to delegate to another generator function. This allows the current generator to yield values from another generator, effectively creating a recursive loop.&lt;/p&gt;

&lt;p&gt;Let's modify the &lt;code&gt;operationsWithHook&lt;/code&gt; function to include a condition for recursion if the result of calling the hook and multiplying it remains below constant &lt;code&gt;N&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Modified generator function with recursion&lt;/span&gt;
&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// First operation&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nf"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Call the hook, which can be sync or async&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Operation on the hook's result&lt;/span&gt;
  &lt;span class="c1"&gt;// Check if the result is divisible by N, and if so, recurse&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Recurse with yield*&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;yield*&lt;/code&gt; expression is used for delegating to another generator function, in this case, &lt;code&gt;operationsWithHook&lt;/code&gt; itself, which allows for recursion. This works seamlessly with both synchronous and asynchronous hooks because the trampoline functions are designed to handle the iteration over generator functions, including when they delegate to other generators or themselves.&lt;/p&gt;

&lt;p&gt;The trampoline functions (&lt;code&gt;syncTrampoline&lt;/code&gt; and &lt;code&gt;asyncTrampoline&lt;/code&gt;) do not need to be modified to support this recursion. They will continue to work as before, driving the generator to completion, whether it involves recursion or not.&lt;/p&gt;

&lt;p&gt;The same execution code as before can be used to execute the generator function either synchronously or asynchronously, depending on the nature of the hook you're passing.&lt;/p&gt;

&lt;p&gt;This approach allows the &lt;code&gt;operationsWithHook&lt;/code&gt; function to call itself recursively under certain conditions, with the trampoline functions handling the execution flow, whether synchronous or asynchronous.&lt;/p&gt;




&lt;h2&gt;
  
  
  Complete example file
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;I put it together and added logging so you can see the output and understand the flow.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// First operation&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nf"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Call the hook, which can be sync or async&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Operation on the hook's result&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="c1"&gt;// Check if the result is divisible by N, and if so, recurse&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Recurse with yield*&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Synchronous trampoline&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Asynchronous trampoline&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;asyncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatorFunc&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; -&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Synchronous hook&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syncHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Asynchronous hook&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;asyncHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Execute synchronously&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;syncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;syncHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output will depend on operations and hook&lt;/span&gt;

&lt;span class="c1"&gt;// Execute asynchronously&lt;/span&gt;
&lt;span class="nf"&gt;asyncTrampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operationsWithHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asyncHook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output will depend on operations and hook&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Disclaimer and license
&lt;/h2&gt;

&lt;p&gt;Note: I have modified the response from our benevolent AI overlord to my liking in sufficiently many places, so now it's copyrightable, which allows me to release it under &lt;a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener noreferrer"&gt;CC BY-NC-SA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mean, I had to modify it because asyncTrampoline was broken, it's not just for copyright :D&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>asynchronous</category>
      <category>programming</category>
      <category>llm</category>
    </item>
    <item>
      <title>Supply chain security - prevent, not avoid</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Wed, 03 Aug 2022 16:12:00 +0000</pubDate>
      <link>https://dev.to/naugtur/supply-chain-security-prevent-not-avoid-54ng</link>
      <guid>https://dev.to/naugtur/supply-chain-security-prevent-not-avoid-54ng</guid>
      <description>&lt;p&gt;Semver range specifiers &lt;code&gt;~^&lt;/code&gt; are not only used in a top-level package.json. They're also used by dependencies. It's not feasible to get everyone to stop using them and it wouldn't be good for the ecosystem and even security. If a dependency 5 levels deep gets a security fix, how do you update all along the way? It's a problem already, even though ^ is fairly popular.&lt;/p&gt;

&lt;p&gt;Lockfiles solve the issue of a nested dependency getting updated accidentally. package-lock.json or yarn.lock, if used right, eliminate the probability of unexpected nested package updates in CI etc.&lt;/p&gt;

&lt;p&gt;"Vendoring" - pushing node_modules into the repository - is not practical and doesn't offer benefits compared to fully leveraging lockfiles.&lt;/p&gt;

&lt;p&gt;Even if "vendored", updating is a must and at any significant size of the dependency tree reviewing every single package coming down is not humanely possible. &lt;/p&gt;

&lt;p&gt;Now finding a package and taking it over is one threat, but what about a maintainer of a useful package who intentionally publishes a malicious version to get rich quicker than otherwise just making opensource?&lt;br&gt;
What about a prototype pollution in one package leading to a compromise of another package? What about the most popular way of delivering attacks - a postinstall script? The script would run before you get the chance to review the contents of the package. (That can be mitigated by socket.dev decently)&lt;/p&gt;

&lt;p&gt;That's why instead of attempting the impossibility of reviewing all packages in your dependency tree I'd suggest preventing the outcomes of a malicious package eventually reaching your dependencies.&lt;/p&gt;

&lt;p&gt;Enter: LavaMoat.&lt;br&gt;
&lt;a href="https://github.com/LavaMoat/LavaMoat" rel="noopener noreferrer"&gt;https://github.com/LavaMoat/LavaMoat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LavaMoat has tools for preventing unexpected postinstall scripts from running. (allow-scripts)&lt;/p&gt;

&lt;p&gt;LavaMoat has tools to put each package in its own compartment and only allow it to access globals, builtins and other packages based on a policy. At runtime! &lt;/p&gt;

&lt;p&gt;If a package attempts to &lt;code&gt;require('fs')&lt;/code&gt; or call &lt;code&gt;fetch()&lt;/code&gt; in a new version, it's not going to work if it wasn't there previously.&lt;/p&gt;

&lt;p&gt;Enough reading?&lt;/p&gt;

&lt;p&gt;Here's a conversation about supply chain and install scripts&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=STC_ubJNiMs" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=STC_ubJNiMs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's an intro to lavamoat&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=iaqe6F4S2tA" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=iaqe6F4S2tA&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Additive changes to your cjs exports are now breaking changes.</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Thu, 03 Mar 2022 21:27:43 +0000</pubDate>
      <link>https://dev.to/naugtur/additive-changes-to-your-cjs-exports-are-now-breaking-changes-3pnk</link>
      <guid>https://dev.to/naugtur/additive-changes-to-your-cjs-exports-are-now-breaking-changes-3pnk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The title is a bit of a clickbait, but it's not false! :D &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So you're providing a module with a very useful utility function in &lt;code&gt;even.cjs&lt;/code&gt; version 1.0.1 &lt;em&gt;(improved performance since 1.0.0!)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A faithful consumer comes in and uses it in their &lt;code&gt;app.mjs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./even.cjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;even&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks good. Time for feature creep.&lt;/p&gt;

&lt;p&gt;A contributor comes and makes a pull request to add a very helpful field allowing them to look up the version at runtime. &lt;em&gt;(jQuery has it, it must be good.)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Lovely, thanks for the contribution! Published as v1.1.0!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;1 hour later:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Issue: You broke my app! TypeError: utils.even is not a function&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Wait, what?
&lt;/h2&gt;

&lt;p&gt;Yeah, the named export is gone.&lt;/p&gt;

&lt;p&gt;If we switch to named imports, the error message is more helpful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { even } from './even.cjs';
         ^^^^
SyntaxError: Named export 'even' not found. The requested module './even.cjs' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from './even.cjs';
const { even } = pkg;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the before and after for all 3 cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// import * as utils from './even.cjs';&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// import { even } from './even.cjs';&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;// import utils from './even.cjs';&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// import * as utils from './even.cjs';&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// import { even } from './even.cjs';&lt;/span&gt;
    &lt;span class="nx"&gt;ERROR&lt;/span&gt;
&lt;span class="c1"&gt;// import utils from './even.cjs';&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But why??
&lt;/h2&gt;

&lt;p&gt;When you import modules, you're supposed to get the exports without actually running the code. For ESM modules the limitation to how &lt;code&gt;export&lt;/code&gt; keyword can be used it's fairly easy and quick to provide a complete and correct list without fully parsing and tracing the execution of the entire file. It's not possible for CommonJS. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;BTW, that's why it took so long to provide ESM in Node too - figuring out ESM&amp;lt;-&amp;gt;CJS crossover was &lt;em&gt;difficult&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So to get importing CommonJS to work at all, a good-enough pass through the cjs file is made to try and detect exports without running the code.&lt;/p&gt;

&lt;p&gt;It ships with Node.js: &lt;a href="https://github.com/nodejs/node/tree/fdf625bae8f8b29a25cbd7c8a5d8220af6292cea/deps/cjs-module-lexer" rel="noopener noreferrer"&gt;https://github.com/nodejs/node/tree/fdf625bae8f8b29a25cbd7c8a5d8220af6292cea/deps/cjs-module-lexer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The readme there offers a few cases where the lexer bails out of listing exports, but I think the tests are better at documenting it precisely.&lt;br&gt;&lt;br&gt;
This is the exact test explaining what we're seeing here:&lt;br&gt;
&lt;a href="https://github.com/nodejs/cjs-module-lexer/blob/main/test/_unit.js#L532" rel="noopener noreferrer"&gt;https://github.com/nodejs/cjs-module-lexer/blob/main/test/_unit.js#L532&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why do I know all this? Well, I'm trying to provide a consistent cjs import implementation in a different engine's  import implementation. And now I have to fake the differences even though I could provide more reliable exports listings. &lt;/p&gt;

&lt;p&gt;Oh, and guess what - this differs between Node, webpack, parcel etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should a package maintainer do?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Be aware of this :) &lt;/li&gt;
&lt;li&gt;Look into &lt;code&gt;exports&lt;/code&gt; field in package.json - it might help

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webpack.js.org/guides/package-exports/" rel="noopener noreferrer"&gt;https://webpack.js.org/guides/package-exports/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/api/packages.html#exports" rel="noopener noreferrer"&gt;https://nodejs.org/api/packages.html#exports&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Consider wrapping your package in a .mjs that just reexports things under the right names if you could be affected.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Get safe and remain productive with can-i-ignore-scripts</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Tue, 24 Aug 2021 09:10:39 +0000</pubDate>
      <link>https://dev.to/naugtur/get-safe-and-remain-productive-with-can-i-ignore-scripts-2ddc</link>
      <guid>https://dev.to/naugtur/get-safe-and-remain-productive-with-can-i-ignore-scripts-2ddc</guid>
      <description>&lt;p&gt;So you've heard about supply chain security? You should no longer want to run &lt;code&gt;npm ci&lt;/code&gt; without the &lt;code&gt;--ignore-scripts&lt;/code&gt; flag. If you still need more convincing - I made a package that makes typescript compiler inject malicious code to your application. &lt;a href="https://www.youtube.com/watch?v=Y5gtOqPjUJM" rel="noopener noreferrer"&gt;See this video for more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now with the good advice to always run &lt;code&gt;npm ci --ignore-scripts&lt;/code&gt; all that's left is to start using it. But wait! My app no longer works! Some of these scripts were necessary after all...&lt;br&gt;&lt;br&gt;
All you need to do is &lt;code&gt;npm rebuild packagename&lt;/code&gt;. If you know which package needs its scripts to run.&lt;/p&gt;

&lt;p&gt;That's the problem with security best practices - there's always convenience that you need to give away. But that's where I come in! I enjoy making security best practices easier to deploy in your team. (That's why I wrote npm-audit-resolver but that's a different story)&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;--ignore-scripts&lt;/code&gt; and no regrets
&lt;/h2&gt;

&lt;p&gt;Figuring out which of your packages actually need their postinstall scripts is not a candidate to make the list of "top 5 moments at work". I bet you'll be happy to hear there's a tool to do it for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/can-i-ignore-scripts" rel="noopener noreferrer"&gt;&lt;code&gt;can-i-ignore-scripts&lt;/code&gt;&lt;/a&gt; is a commandline utility that scans your node_modules folder and lists all packages with scripts that run on installation. It then checks against a collection of known packages whose scripts were already evaluated before and lists suggestions.&lt;/p&gt;

&lt;p&gt;You can use the suggestions to quickly choose which scripts to run after the installations have finished.&lt;br&gt;&lt;br&gt;
There's nothing wrong with accepting some scripts you're not sure about. The goal of having an allowlist is to avoid running a script that was maliciously added where it wasn't before. The sooner you introduce &lt;code&gt;--ignore-scripts&lt;/code&gt; to your app the better. Even if that means adding exceptions for ALL existing packages.&lt;/p&gt;

&lt;p&gt;Quick roll out in your project? Here you go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm ci --ignore-scripts
npx can-i-ignore-scripts


█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█
  ▄▄·  ▄▄▄·  ▐ ▄    ▄     ▪    ▄▄     ▐ ▄       ▄▄▄   ▄▄▄      ▄▄▄▄·
 ▐█ ▌ ▐█ ▀█ ·█▌▐█   ██    ██  ▐█ ▀    █▌▐█      ▐▄ █· █  ▀·  .▀  .█▌
 ██ ▄▄▄█▀▀█ ▐█▐▐▌   ▐█·   ▐█· ▄█ ▀█▄ ▐█▐▐▌ ▄█▀▄ ▐▀▀▄ ▐█▀      ▄█▀▀▀·
 ▐███▌▐█ ▪▐▌██▐█▌   ▐█▌   ▐█▌ ▐█▄ ▐█ ██▐█▌▐█▌.▐▌▐▄ █▌▐█▄▄▄▌   ▀
 ·▀▀▀  ▀  ▀ ▀▀ █▪   ▀▀▀   ▀▀▀ ·▀▀▀▀  ▀▀ █▪ ▀█▄▀▪.▀  ▀ ▀▀▀     ▀

▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
Found following packages with scripts:
[ ignore ] 'pre-commit' has scripts but they can be ignored 
             reason: used in local development
[ ignore ] 'core-js' has scripts but they can be ignored 
             reason: funding
[  keep  ] 'grpc' needs its scripts to run
[  keep  ] 'bignum' needs its scripts to run

▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
What now? Run rebuild after 'npm ci --ignore-scripts' to trigger scripts you need to keep. 

A suggestion to get you started:
npm rebuild bignum grpc
█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then take a look at the recommendations and add the &lt;em&gt;rebuild&lt;/em&gt; line after the installation in CI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm rebuild bignum grpc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Go hack yourself
&lt;/h2&gt;

&lt;p&gt;Don't know if postinstall scripts actually run in your CI? Or maybe you need to convince someone it'a an issue? Hack yourself by installing &lt;a href="https://www.npmjs.com/package/@naugtur/pentest-my-ci" rel="noopener noreferrer"&gt;&lt;code&gt;@naugtur/pentest-my-ci&lt;/code&gt;&lt;/a&gt; as your dev dependency.  It contains a preinstall script that stops the CI and tries to scare the reader of the logs a bit.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>npm</category>
    </item>
    <item>
      <title>Do you need help with your npm audit?</title>
      <dc:creator>naugtur</dc:creator>
      <pubDate>Wed, 07 Jul 2021 20:41:06 +0000</pubDate>
      <link>https://dev.to/naugtur/do-you-need-help-with-your-npm-audit-3olf</link>
      <guid>https://dev.to/naugtur/do-you-need-help-with-your-npm-audit-3olf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ok, I'm gonna try and surf the wave of publicity resulting from &lt;a href="https://overreacted.io/npm-audit-broken-by-design/" rel="noopener noreferrer"&gt;Dan Abramov's recent post&lt;/a&gt; and its discussions. &lt;br&gt;
It's 10PM and English is not my first language, so... hold on to your grammars.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me address the elephant in the room too. Or talk about how I'm working to address it.&lt;/p&gt;

&lt;p&gt;I've encountered the &lt;em&gt;npm audit fatigue&lt;/em&gt; just days after the audit feature was released. It was on a Node.js project. (ok, 20+ of them at once) &lt;/p&gt;

&lt;p&gt;It resulted with the first version of &lt;a href="https://www.npmjs.com/package/npm-audit-resolver" rel="noopener noreferrer"&gt;npm-audit-resolver&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to know how npm-audit-resolver came to life, I've told the story in this recording:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=X-0yb1Nfp_I" rel="noopener noreferrer"&gt;OpenJS World 2021 pkg vuln talk&lt;/a&gt;&lt;br&gt;
&lt;em&gt;apologies for the quality of my webcam&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The video introduces Package Vulnerability Management &amp;amp; Reporting Collaboration Space.&lt;br&gt;&lt;br&gt;
Actually, I recommend you stop reading and watch a bit of it now. &lt;/p&gt;




&lt;p&gt;What I want to talk about here is the ideas for the future of npm-audit-resolver.&lt;/p&gt;

&lt;p&gt;And that future is tightly bound to the &lt;a href="https://github.com/openjs-foundation/pkg-vuln-collab-space" rel="noopener noreferrer"&gt;Package Vulnerability Management &amp;amp; Reporting Collaboration Space&lt;/a&gt;, I hope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current state
&lt;/h2&gt;

&lt;p&gt;Let me give you a quick summary &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's an interactive tool that asks you what to do with each vulnerability&lt;/li&gt;
&lt;li&gt;lets you ignore vulnerabilities with surgical precision&lt;/li&gt;
&lt;li&gt;helps maintain a culture of caring about security by reducing annoyance (not enough yet)&lt;/li&gt;
&lt;li&gt;maintains a json file with your decisions &lt;code&gt;audit-resolve.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;wraps &lt;code&gt;npm audit&lt;/code&gt; for running in CI and applies your ignores&lt;/li&gt;
&lt;li&gt;supports yarn too&lt;/li&gt;
&lt;li&gt;npm7 support on its way (I'm working with npm folks on some details)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Plans
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Decisions file
&lt;/h3&gt;

&lt;p&gt;I intend to donate the JSONSchema of the &lt;code&gt;audit-resolve.json&lt;/code&gt; file to OpenJS Foundation. When it's ready :) &lt;/p&gt;

&lt;p&gt;The format evolved a bit already, but I also need to adapt it to the new usecase of sharing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharing decisions
&lt;/h3&gt;

&lt;p&gt;The new usecase for &lt;code&gt;audit-resolve.json&lt;/code&gt; is sharing decisions. &lt;/p&gt;

&lt;p&gt;Imagine an internal security team publishing a file with recommendations what to safely ignore that shows up as suggestions or can be applied automatically.&lt;br&gt;&lt;br&gt;
How about a central location to manage shared decisions across projects?&lt;br&gt;&lt;br&gt;
Ok, now the best part - &lt;em&gt;security influencers&lt;/em&gt;!&lt;br&gt;&lt;br&gt;
Jokes aside, package maintainers could publish ignore lists for the dependencies of their package when they did the research to verify the package is not affected. &lt;br&gt;
Such lists could be aggregated into recommendations maintained by security professionals.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;audit-resolve.json&lt;/code&gt; support everywhere!
&lt;/h3&gt;

&lt;p&gt;The plan is to make the default &lt;code&gt;npm audit&lt;/code&gt; command take the file into account. I've extracted the core from npm-audit-resolver so that anyone can embed it in their tooling. &lt;/p&gt;

&lt;p&gt;It's not much, it's not 100% ready, but it's doing basic work for you.&lt;/p&gt;

&lt;p&gt;I hope yarn, pnpm, snyk and so on would eventually understand the format.&lt;/p&gt;

&lt;h2&gt;
  
  
  pkg-vuln-collab-space
&lt;/h2&gt;

&lt;p&gt;These ideas are just my ideas. I'm hoping to see them shaped by real data and feedback and discussions in the Collab Space.&lt;/p&gt;

&lt;p&gt;Please participate in the Collab Space.&lt;br&gt;
Please try npm-audit-resolver&lt;br&gt;
Please don't get demotivated - try caring about security at least to the point of ignoring the vulnerabilities one by one ;) &lt;/p&gt;




&lt;p&gt;Hey, did you watch the OpenJsWorld video already?&lt;/p&gt;

</description>
      <category>npm</category>
      <category>security</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
