<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>alyxia.dev</title><description>a blog with insignificant contents</description><link>https://alyxia.dev/</link><item><title>A Retrospective, Ex Post Facto</title><link>https://alyxia.dev/blog/2023-ex-post-facto</link><guid isPermaLink="true">https://alyxia.dev/blog/2023-ex-post-facto</guid><pubDate>Sun, 31 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today marks the final day. We’ve all seen a whole lot this year, no?&lt;/p&gt;
&lt;p&gt;Ups and downs plenty, but I’m alive. I’m working on myself, and it’s going better than ever. I’m &lt;em&gt;happy&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, let’s go over a couple of things I’ve done this year.&lt;/p&gt;
&lt;h2 id=&quot;joining-brikdigital&quot;&gt;Joining Brik.digital&lt;/h2&gt;
&lt;p&gt;This year marks the year I started my first actual job. It was masked as an internship for school, which all in all it really wasn’t. Besides the reports and assignments I had to do about my work for school, to me this was nothing like the average internship.&lt;/p&gt;
&lt;p&gt;I wasn’t treated like an intern. I was treated like a coworker. Someone who’d been there for years. I don’t think I’ve ever integrated into a team this quick. I found my place so incredibly fast between these wonderful people, and I’m eternally grateful for being given the opportunity to stick around for as long as I did.&lt;/p&gt;
&lt;p&gt;It was supposed to be an internship that lasted half a year, from February 2nd to June 26th, however, I was offered a temporary contract throughout the summer holiday if I was interested in that. Being willing to continue growing in this team, I accepted without hesitation. I only had two weeks of summer holiday this year compared to the usual six. But it was worth it!&lt;/p&gt;
&lt;p&gt;I learnt a lot, was able to work on ton of cool projects, and it didn’t stop there. My education was supposed to last four years, but I was told I was able to skip a year if that fit my needs more, as the third year was full of stuff I’d likely already know. So I did. And then another big switch-up happened; they moved the internship period of the fourth year from the second half to the first half of the year. Meaning that starting the 28th of August, I’d be right back in the office until the 2nd of February 2024.&lt;/p&gt;
&lt;p&gt;There’s only plus-minus one month left until that day. And that only really strikes in now. Each of the people there have been the kindest, most wonderful people I’ve had the pleasure of working with in a very long time. I’ve worked on some amazing things (some of which &lt;a href=&quot;https://github.com/lexisother/craft-narrowcasting&quot;&gt;even&lt;/a&gt; &lt;a href=&quot;https://github.com/lexisother/nc-client&quot;&gt;publicly&lt;/a&gt; &lt;a href=&quot;https://github.com/lexisother/craft-statuspaginator&quot;&gt;available&lt;/a&gt;!), went on a couple outings with them, helped move to the new office, and so much more. I’ve taught my coworkers new things, they’ve taught me new things, and honestly I could keep going about everything I’ve accomplished there this year.&lt;/p&gt;
&lt;p&gt;It’s been a great time, for any of you folks there that end up reading this. Thank you so much.&lt;/p&gt;
&lt;h2 id=&quot;crosscode-modding&quot;&gt;CrossCode Modding&lt;/h2&gt;
&lt;p&gt;This, like many others, is also a year in which I spent a lot of time doing more work for the community that I originally started out in; the modding community for the brilliant video game &lt;a href=&quot;https://store.steampowered.com/app/368340/CrossCode/&quot;&gt;CrossCode&lt;/a&gt;. (it’s on sale until January 4th! go buy it!)&lt;/p&gt;
&lt;p&gt;Here’s a list of personal projects I worked on this year, in order of how cool I think they are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CCProjectRed: Story expansion set in a certain game area (currently private as per request from one of the team members)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/cc-touchbar&quot;&gt;cc-touchbar&lt;/a&gt;: Mod with a native Node module for controlling the MacBook’s touchbar&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/CCHijack&quot;&gt;CCHijack&lt;/a&gt;: Injects into the game before it even loads, allowing you to write your own game&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/cc-quickinfo-exp&quot;&gt;cc-quickinfo-exp&lt;/a&gt;: Simple mod for showing the EXP an enemy will give you in the quick info dialog&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/cc-alybox&quot;&gt;cc-alybox&lt;/a&gt;: Library mod containing game tweaks and features for other modders&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/CCPostDLC&quot;&gt;CCPostDLC&lt;/a&gt;: Allows you to continue playing the game after the DLC ends&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/CCOldMedia&quot;&gt;CCOldMedia&lt;/a&gt;: Brings back a couple old assets and audio tracks from v0.7.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aside from these personal projects, I obviously also contributed to a couple projects on the organization, &lt;a href=&quot;https://github.com/CCDirectLink&quot;&gt;CCDirectLink&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CCDirectLink/CCLoader3&quot;&gt;CCLoader3&lt;/a&gt;: Next generation never-to-be-released modloader&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CCDirectLink/ccbot&quot;&gt;ccbot&lt;/a&gt;: Central community bot; worked on a huge codebase refresh/update&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CCDirectLink/ultimate-crosscode-typedefs&quot;&gt;ultimate-crosscode-typedefs&lt;/a&gt;: Huge conglomerate repository with type definitions for the game&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CCDirectLink/c2dl-web&quot;&gt;c2dl-web&lt;/a&gt;: &lt;a href=&quot;https://c2dl.info&quot;&gt;c2dl.info&lt;/a&gt; website written in Laravel&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CCDirectLink/cc-ts-template&quot;&gt;cc-ts-template&lt;/a&gt;: Simple TypeScript template for your new mod&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’d like to thank 2767mr, Emi, Nax, EL, krypek, and image not found for being such nice and clever people to interact with.&lt;/p&gt;
&lt;h2 id=&quot;discord-modding&quot;&gt;Discord Modding&lt;/h2&gt;
&lt;p&gt;And of course, just like the past three years, I’ve contributed and done lots of stuff for various Discord mods.&lt;/p&gt;
&lt;p&gt;There’s too many people to thank in this community, so I’ll just skip over that for now. Thank you all :)&lt;/p&gt;
&lt;h3 id=&quot;replugged&quot;&gt;Replugged&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/replugged-org/replugged-web-rewrite&quot;&gt;replugged-web-rewrite&lt;/a&gt;: Complete rewrite of Replugged’s front- and backend in Laravel&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/replugged-org/installer&quot;&gt;installer&lt;/a&gt;: Replugged installer written in Go using Frenyard&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/replugged-org/replugged&quot;&gt;replugged&lt;/a&gt;: Replugged itself, of course&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/replugged-plugins&quot;&gt;replugged-plugins&lt;/a&gt;: My Replugged plugins repo&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;moonlight&quot;&gt;moonlight&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lexisother/moonlight-extensions&quot;&gt;moonlight-extensions&lt;/a&gt;: My moonlight extensions repo&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;personal-projects&quot;&gt;Personal projects&lt;/h2&gt;
&lt;p&gt;Lastly, let’s go over some personal projects I’ve done this year. Despite there not being a lot of those, there’s quite a couple things I did &lt;em&gt;for&lt;/em&gt; them!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lexisother/dotfiles/&quot;&gt;dotfiles&lt;/a&gt;: Lots of stuff in lots of different places here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Good couple plugins for hh3&lt;/li&gt;
&lt;li&gt;Started using Nix&lt;/li&gt;
&lt;li&gt;Worked on the Neovim config where necessary, along with an attempt to write a new config&lt;/li&gt;
&lt;li&gt;Did some script/zsh config maintenance&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lexisother/alyxia.dev&quot;&gt;alyxia.dev&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rewrote my old website in Common Lisp starting Dec 30th 2022&lt;/li&gt;
&lt;li&gt;Did a bunch of work over the course of this year, both functionality and UI wise&lt;/li&gt;
&lt;li&gt;Got in touch with &lt;a href=&quot;https://lisperator.net/&quot;&gt;Mihai Bazon&lt;/a&gt;, the creator of the web framework I used&lt;/li&gt;
&lt;li&gt;Currently working on a rewrite in &lt;a href=&quot;https://rescript-lang.org&quot;&gt;ReScript&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;advent-of-code&quot;&gt;Advent of Code&lt;/h2&gt;
&lt;p&gt;This year I also hosted my annual Advent of Code leaderboard, bringing out some of the people I thought were totally gonna dig a challenge like this.&lt;/p&gt;
&lt;p&gt;Thank you to all participants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tasky&lt;/li&gt;
&lt;li&gt;Niels&lt;/li&gt;
&lt;li&gt;birb&lt;/li&gt;
&lt;li&gt;image not found&lt;/li&gt;
&lt;li&gt;krypek&lt;/li&gt;
&lt;li&gt;EastArctica&lt;/li&gt;
&lt;li&gt;Chris&lt;/li&gt;
&lt;li&gt;Maru&lt;/li&gt;
&lt;li&gt;Nax&lt;/li&gt;
&lt;li&gt;Nico&lt;/li&gt;
&lt;li&gt;Janneke&lt;/li&gt;
&lt;li&gt;Snare&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As I said to you all already, I hope to see you December 2024 for the next round :)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;…and that just about rounds this year up. It’s been a rough one, but we’re all still here, aren’t we?&lt;/p&gt;
&lt;p&gt;I’d like to extend my additional thank you to some people who I’ve only really interacted with through DMs this year. You know who you are.&lt;/p&gt;
&lt;p&gt;Happy New Year, hopefully 2024 is going to be a good year for y’all.&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;</content:encoded></item><item><title>2024 in Review</title><link>https://alyxia.dev/blog/2024-retrospective</link><guid isPermaLink="true">https://alyxia.dev/blog/2024-retrospective</guid><pubDate>Tue, 31 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today marks the last day of 2024. It was quite the turbulent year, but for me it’s been quite a positive one. Which I’m glad I’m able to say, given how the past couple of years haven’t exactly been favourable.&lt;/p&gt;
&lt;p&gt;I’ve accomplished a lot this year, and I’d like to go over a couple of them.&lt;/p&gt;
&lt;h2 id=&quot;events&quot;&gt;Events&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I graduated from school.&lt;/li&gt;
&lt;li&gt;I turned 19.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;personal-projects&quot;&gt;Personal projects&lt;/h2&gt;
&lt;h3 id=&quot;alyxiadev&quot;&gt;alyxia.dev&lt;/h3&gt;
&lt;p&gt;Late 2023, I redid my website’s design and internals using &lt;a href=&quot;https://rescript-lang.org/&quot;&gt;ReScript&lt;/a&gt; after a failed attempt where I used Common Lisp with &lt;a href=&quot;https://github.com/mishoo/sytes&quot;&gt;Sytes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately both of these attempts failed due to one deciding factor: I didn’t work with the languages often enough to remember how to use them. I don’t update my website every week, not even every month. The most I might do is add some people’s 88x31 badges to my friends page. This obviously meant that I barely touched the code part of the project, and as a result I barely remembered how to do some things after a while of not working on it.&lt;/p&gt;
&lt;p&gt;Not long after making this realisation, I decided it was time to say goodbye to ReScript and move to something I actually knew how to maintain in the long run. So, I took the design with me and moved to &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;. I decided to use Vue for the majority of the frontend components because it was handy for fetching dynamic data like my Last.fm songs &amp;amp; my &lt;a href=&quot;https://status.cafe/&quot;&gt;status.cafe&lt;/a&gt; status.&lt;/p&gt;
&lt;h3 id=&quot;alycms&quot;&gt;AlyCMS&lt;/h3&gt;
&lt;p&gt;Somewhere near the start of 2024, I did some final feature implementations and bugfixes to my own content management system, &lt;a href=&quot;https://github.com/lexisother/AlyCMS&quot;&gt;AlyCMS&lt;/a&gt;, and left the project there. It’ll take a lot more time for this tool to become viable and potentially function as the actual content source for this blog, but it’s time I either don’t have or am not willing to spend working on it.&lt;/p&gt;
&lt;p&gt;However, due to the rising attention of social network Bluesky’s protocol &lt;a href=&quot;https://atproto.com&quot;&gt;ATProto&lt;/a&gt;, I figured I’d try my hand at implementing authentication and data storing using it. I inevitably got stuck and put my work on &lt;a href=&quot;https://github.com/lexisother/AlyCMS/commits/atproto&quot;&gt;this branch&lt;/a&gt;, which I intend to finish sometime in the future.&lt;/p&gt;
&lt;h3 id=&quot;misc&quot;&gt;Misc&lt;/h3&gt;
&lt;p&gt;Besides all that, here’s a loosely date-sorted list of stuff I’ve done.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Overhauled the project structure of &lt;a href=&quot;https://github.com/CCDirectLink/CCLoader3&quot;&gt;CCLoader3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tried to write a modloader for a game about coffins&lt;/li&gt;
&lt;li&gt;Wrote a version archiving toolchain for a game about coffins&lt;/li&gt;
&lt;li&gt;Made some fixes to &lt;a href=&quot;https://github.com/lexisother/frenyard&quot;&gt;Frenyard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Wrote a &lt;a href=&quot;https://github.com/lexisother/raycast-extensions&quot;&gt;Raycast extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Wrote a somewhat functional &lt;a href=&quot;https://github.com/lexisother/Phonograph&quot;&gt;music bot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Wrote a &lt;a href=&quot;https://spicetify.app/&quot;&gt;Spicetify&lt;/a&gt; &lt;a href=&quot;https://github.com/lexisother/spicetify-macropad&quot;&gt;plugin&lt;/a&gt; to control media playback with my macropad&lt;/li&gt;
&lt;li&gt;Wrote a couple &lt;a href=&quot;https://coder.com/&quot;&gt;Coder&lt;/a&gt; &lt;a href=&quot;https://github.com/lexisother/coder-templates&quot;&gt;templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Together with friends, started a modloader for a rhythm game&lt;/li&gt;
&lt;li&gt;Wrote a converter for osu!mania charts to said rhythm game&lt;/li&gt;
&lt;li&gt;Wrote a couple &lt;a href=&quot;https://github.com/lexisother/UltrakillMods&quot;&gt;ULTRAKILL mods&lt;/a&gt; in F#&lt;/li&gt;
&lt;li&gt;Started working on a website for a local scouts group&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/taskylizard&quot;&gt;Tasky&lt;/a&gt; and I made a somewhat successful attempt at obtaining &lt;a href=&quot;https://mintlify.com/&quot;&gt;Mintlify’s&lt;/a&gt; source code and using it to build a static docs site&lt;/li&gt;
&lt;li&gt;Wrote a script to mirror an entire GitLab organisation to GitHub&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;brikdigital&quot;&gt;Brik.digital&lt;/h2&gt;
&lt;p&gt;Like last year, I’d like to take a moment to look back on the various projects I’ve worked on for my job this year. It’s been a rather turbulent year and personally I believe I’ve made some crucial contributions to the very way we work in our development team. Aside from that, I’ve managed to even publicise some of the work.&lt;/p&gt;
&lt;h3 id=&quot;project-baseplate&quot;&gt;Project Baseplate&lt;/h3&gt;
&lt;p&gt;Most notably, this year I spearheaded the development of our project template. The one we used before was originally made for Craft 3, using now outdated standards and toolchains, which we upgraded along the way as we saw fit. It currently does use Craft 5, but it still employs a bunch of outdated and suboptimal strategies, because the &lt;em&gt;way&lt;/em&gt; the template does things was never changed. New things were just tacked on.&lt;/p&gt;
&lt;p&gt;So, after a couple of internal discussions to figure out what we needed/wanted, I was given the green light to start working on a new template from scratch. I started out by bumping any dependencies we wanted to carry over to their latest versions, and got to work. My first order of business; come up with a better system for our JavaScript.&lt;/p&gt;
&lt;p&gt;I made the decision to ditch our old JS code (which in most projects always ended up being stuffed into the main &lt;code&gt;app.js&lt;/code&gt; file) and replace it with a neat TS based dynamic importing system. It works as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ComponentLoader, { Component } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;quot;./loader&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; componentLoader&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ComponentLoader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; components&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Component&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    name: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;alpine&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    selector: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;[data-alpine]&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; component &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; components) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  componentLoader.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;loadComponent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    component.name,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    component.selector,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    component.plugins &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will dynamically load the &lt;code&gt;components/alpine.ts&lt;/code&gt; file when an element with the &lt;code&gt;data-alpine&lt;/code&gt; attribute exists on the page. Said file exports a default function which will then get executed. It allows us to lower the amount of code loaded and executed when certain elements aren’t even present on the page. Very neat, and very clean.&lt;/p&gt;
&lt;p&gt;Another big thing I introduced was the use of &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt;, which wasn’t just something new for our team, but is something &lt;strong&gt;I pioneered in the public Craft CMS community&lt;/strong&gt;. There are old projects on GitHub that demonstrate the use of Storybook in a Craft CMS environment, but they were terrible hacks. One of them even rendered the Twig templates client-side by using a JS implementation of Twig. A 2021 talk concluded that it was “terribly difficult” to integrate Storybook into Craft CMS.&lt;/p&gt;
&lt;p&gt;After more discussing of the idea internally, I started working on an integration, and… got it &lt;a href=&quot;https://github.com/brikdigital/craft-baseplate/commit/2ab608010a54dff5edb8cb6f9709e942f043f835&quot;&gt;functional&lt;/a&gt; in a single night of work. The way it works is rather simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We override Storybook’s &lt;code&gt;fetchStoryHtml&lt;/code&gt; function and make a request to a custom controller with the path to the current &lt;code&gt;.stories.json&lt;/code&gt; file along with all the selected properties/options&lt;/li&gt;
&lt;li&gt;We fetch the corresponding &lt;code&gt;.twig&lt;/code&gt; file on the server, construct a fake Twig template in a string in which we place the contents of our component’s &lt;code&gt;.twig&lt;/code&gt; file, and render it&lt;/li&gt;
&lt;li&gt;We send the resulting HTML back to Storybook&lt;/li&gt;
&lt;li&gt;We do some final post-processing of the returned HTML on Storybook’s side and send it off to the renderer&lt;/li&gt;
&lt;/ol&gt;
&lt;img src=&quot;https://alyxia.dev/_image?href=%2F_astro%2Fstorybook.CRGnAK9K.png&amp;#38;w=3136&amp;#38;h=1936&amp;#38;f=webp&quot; style=&quot;width: 100%; height: auto&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3136&quot; height=&quot;1936&quot;&gt;
&lt;p&gt;We’ve been working with Storybook since I added it, which is about two to three months ago. There were some bumps here and there which I managed to iron out pretty well, but I’ve heard nothing but positive feedback from my coworkers, so I think this was a good addition to our workflow. On top of that, we can statically build Storybook and serve it on a project’s staging domain, which we can then hand over to the design team for review. Using something like &lt;a href=&quot;https://marker.io/&quot;&gt;Marker.io&lt;/a&gt; within Storybook allows us to have a very fluent workflow from design, implementation, and feedback.&lt;/p&gt;
&lt;h3 id=&quot;composer-patches-regex&quot;&gt;composer-patches-regex&lt;/h3&gt;
&lt;h4 id=&quot;the-problem&quot;&gt;The problem&lt;/h4&gt;
&lt;p&gt;Internally, we sometimes use &lt;a href=&quot;https://github.com/cweagans/composer-patches&quot;&gt;composer-patches&lt;/a&gt;, a project much like pnpm’s builtin patching functionality, to apply changes to dependencies before installing them. It, much like pnpm’s functionality, has one fatal flaw: it relies on diff files. It might not sound like a big deal, because you can just pin the dependency version and ensure the patch always applies, but for a fast-moving project like Craft that releases a new version every week, this isn’t exactly ideal, because there’s a small catch when using diff files for patches.&lt;/p&gt;
&lt;p&gt;For those unaware, here’s a sample excerpt from a patch:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;diff --git a/src/elements/Asset.php b/src/elements/Asset.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;index acde040fb2..568475202e 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FDAEB7&quot;&gt;&lt;span style=&quot;user-select:none&quot;&gt;-&lt;/span&gt;-- a/src/elements/Asset.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;&lt;span style=&quot;user-select:none&quot;&gt;+&lt;/span&gt;++ b/src/elements/Asset.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0;font-weight:bold&quot;&gt;@@ -276,7 +276,7 @@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; class Asset extends Element&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     public static function isLocalized(): bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FDAEB7&quot;&gt;&lt;span style=&quot;user-select:none&quot;&gt;-&lt;/span&gt;        return true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;&lt;span style=&quot;user-select:none&quot;&gt;+&lt;/span&gt;        return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     /**&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What this basically says is “on line 276, replace what is prepended with a &lt;code&gt;-&lt;/code&gt; with what is prepended with a &lt;code&gt;+&lt;/code&gt;”&lt;/p&gt;
&lt;p&gt;If you haven’t figured out the problem with this at first glance, let me once again point you to the fact that it &lt;strong&gt;relies on line numbers to tell the patch applier where the changes are.&lt;/strong&gt; So what happens if code is inserted &lt;strong&gt;above&lt;/strong&gt; the lines I’m patching? The line numbers for the lines I’m patching &lt;strong&gt;increase&lt;/strong&gt;, of course, meaning that my patch now no longer applies.&lt;/p&gt;
&lt;p&gt;My solution to this was simple. And it all comes back to Discord client modding. A couple well known projects use something we call “plaintext patching” to change Discord’s code. The way code is patched, in essence, is like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Original content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; calculateSum&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Patch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; patch&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  find:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt;a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt; (b)&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  replace&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; `a + 10 + ${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Changed content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; calculateSum&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; b;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can make clever use of Regex capturing groups to carry over or reference original pieces of code in our replacements, or get rid of code entirely if we so desire. So I figured… why not take the same approach for Composer dependencies?&lt;/p&gt;
&lt;h4 id=&quot;the-solution&quot;&gt;The solution&lt;/h4&gt;
&lt;p&gt;To remedy my gripes with the way &lt;code&gt;composer-patches&lt;/code&gt; works, I built &lt;code&gt;composer-patches-regex&lt;/code&gt;, an extension upon the original package to allow for regex replacements in dependencies. A patch for &lt;code&gt;composer-patches-regex&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  &amp;quot;patches&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &amp;quot;scope/packagename&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        &amp;quot;files&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          &amp;quot;someFile&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              &amp;quot;find&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;/some/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              &amp;quot;replace&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;a bit of&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              &amp;quot;find&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;/original/g&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              &amp;quot;replace&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;copied&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A couple fields required to make this all word were omitted for brevity, but it’s enough to show off the gist of what we’re doing here. We specify a file using the key in the &lt;code&gt;files&lt;/code&gt; object, and specify the patches to execute on this file. Similarly to the JS based approach, we can leverage capture groups and specify them in our replacements using &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, andsoforth. The numbers are ordered in the appearance of the capture groups.&lt;/p&gt;
&lt;p&gt;Sure, this solution isn’t entirely waterproof, but it sure will hold up a lot longer than diff files, as we now no longer depend on the &lt;strong&gt;position&lt;/strong&gt; of the code, but instead the &lt;strong&gt;structure&lt;/strong&gt; of it, which is obviously much less likely to change.&lt;/p&gt;
&lt;h3 id=&quot;statuspaginator&quot;&gt;Statuspaginator&lt;/h3&gt;
&lt;p&gt;Statuspaginator was a project I started building in late 2023 and having received mostly neglect since then, its main purpose being giving us a clear overview of the different Craft CMS sites we were running and which versions they were on. This would be especially useful in the rare case a security vulnerability was found in Craft, and was the main reasoning behind the project’s development.&lt;/p&gt;
&lt;p&gt;Fast forward to December 18 2024, on a peaceful evening, at 8PM… &lt;a href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-2p6p-9rc9-62j9&quot;&gt;GHSA-2p6p-9rc9-62j9&lt;/a&gt; was published. A critical RCE vulnerability was found. At that very moment, Statuspaginator finally demonstrated its usefulness, as every affected site now lit up red:&lt;/p&gt;
&lt;img src=&quot;https://alyxia.dev/_image?href=%2F_astro%2Fstatuspaginator.DVeUhhQy.png&amp;#38;w=2688&amp;#38;h=1682&amp;#38;f=webp&quot; style=&quot;width: 100%; height: auto&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2688&quot; height=&quot;1682&quot;&gt;
&lt;p&gt;For the sites that were being tracked by Statuspaginator (which is frankly a fraction of the projects we run) we could easily see which projects were affected and which weren’t. Despite the circumstances, I felt a sense of pride knowing the thing I built actually did its job pretty well.&lt;/p&gt;
&lt;h3 id=&quot;marker-to-youtrack&quot;&gt;marker-to-youtrack&lt;/h3&gt;
&lt;p&gt;Sometime in August we were figuring out if we wanted to migrate from Jira to JetBrains YouTrack. Jira is expensive, especially so since we’re paying for a lot of functionality we barely use. After a whole lot of research, we found there was only a single blocking issue keeping us from migrating: integration with Marker.io. Marker is a crucial part of how we let our clients submit feedback to our Jira service desk, which is made particularly easy through Marker’s builtin integration with Jira. This wasn’t something we were willing to lose, so I took matters into my own hands and built &lt;a href=&quot;https://github.com/lexisother/marker-to-youtrack&quot;&gt;marker-to-youtrack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There was just one issue… Marker doesn’t have a public API. There has been an open &lt;a href=&quot;https://feedback.marker.io/feature-request/p/markerio-api&quot;&gt;feature request&lt;/a&gt; since late 2022, but despite the attention given to it, nothing’s been done with it so far. My solution? &lt;a href=&quot;https://pptr.dev/&quot;&gt;Puppeteer&lt;/a&gt;. The process is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start a Puppeteer instance and navigate to Marker’s signin page&lt;/li&gt;
&lt;li&gt;Input the email and password&lt;/li&gt;
&lt;li&gt;Wait for Marker’s dashboard to load&lt;/li&gt;
&lt;li&gt;Fetch the browser’s cookies and extract the &lt;code&gt;markersess&lt;/code&gt; cookie&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now I could monitor the devtools’ network tab and see what requests Marker made to its own API to fetch data. I figured out what request was made to obtain a full list of projects, and at that point I could configure a webhook on a Marker project to send events to marker-to-youtrack’s URL. I got whatever data I needed from the project through the webhook event (for example, a new Marker issue), fetched any additional project data from the previously obtained list of Marker projects, and created a corresponding ticket in YouTrack.&lt;/p&gt;
&lt;p&gt;In essence, a very simple tool, but it was a nice challenge regardless!&lt;/p&gt;
&lt;h3 id=&quot;craft-plugins&quot;&gt;Craft plugins&lt;/h3&gt;
&lt;p&gt;Aside from all of the above, I’ve also brought new life to our GitHub organisation by publicising a good chunk of the work I’ve been doing. Here’s a small overview:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wrote TypeScript type definitions for Craft’s &lt;code&gt;window&lt;/code&gt; globals on &lt;a href=&quot;https://github.com/brikdigital/craftcms-typedefs&quot;&gt;craftcms-typedefs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brikdigital/craft-readtime&quot;&gt;Upgraded&lt;/a&gt; the unmaintained Craft Readtime plugin to Craft 5&lt;/li&gt;
&lt;li&gt;Wrote a &lt;a href=&quot;https://github.com/brikdigital/opening-hours&quot;&gt;plugin&lt;/a&gt; that adds a custom field type for specifying a store’s opening times&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brikdigital/craft-scss&quot;&gt;Upgraded&lt;/a&gt; the unmaintained Craft SCSS plugin to Craft 5&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brikdigital/craft-cookiebot&quot;&gt;Upgraded&lt;/a&gt; the unmaintained Craft Cookiebot plugin to Craft 5&lt;/li&gt;
&lt;li&gt;Published &lt;a href=&quot;https://github.com/brikdigital/entry-navigation&quot;&gt;entry-navigation&lt;/a&gt;, a plugin to edit navigation nodes from an entry’s editing page&lt;/li&gt;
&lt;li&gt;Published &lt;a href=&quot;https://github.com/brikdigital/entry-type-permissions&quot;&gt;entry-type-permissions&lt;/a&gt;, a plugin to allow fine-grained permissions of entry type creation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;advent-of-code&quot;&gt;Advent of Code&lt;/h2&gt;
&lt;p&gt;As per usual, I hosted my annual Advent of Code leaderboard this year. I asked the participants of last year if they wanted to participate again, and brought in some new folks too. Besides that, I started using the rather handy &lt;a href=&quot;https://github.com/aockit/aockit&quot;&gt;aockit&lt;/a&gt; by Tasky to support using arbitrary programing languages for my solutions instead of locking myself into TS for the auto-downloading of inputs.&lt;/p&gt;
&lt;p&gt;Thank you to all participants, in no particular order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;image unavailable&lt;/li&gt;
&lt;li&gt;Isabel&lt;/li&gt;
&lt;li&gt;M6&lt;/li&gt;
&lt;li&gt;maeve&lt;/li&gt;
&lt;li&gt;marsh&lt;/li&gt;
&lt;li&gt;Nax&lt;/li&gt;
&lt;li&gt;Snare&lt;/li&gt;
&lt;li&gt;Mopi&lt;/li&gt;
&lt;li&gt;Anya&lt;/li&gt;
&lt;li&gt;Basil&lt;/li&gt;
&lt;li&gt;Janneke&lt;/li&gt;
&lt;li&gt;Krypek&lt;/li&gt;
&lt;li&gt;Maru&lt;/li&gt;
&lt;li&gt;Niels&lt;/li&gt;
&lt;li&gt;20&lt;/li&gt;
&lt;li&gt;Tasky&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This year exceeded my expectations once again, and I’m glad I’m able to host this little leaderboard for my friends every year. It brings me pure joy to see folks interact with eachother and see what solutions they come up with to the problems presented.&lt;/p&gt;
&lt;p&gt;I hope to see you all again next year. :)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;…and that just about rounds this year up. Looking back at everything, it sure was an eventful one. It took me about three days to write this all out, both because I have trouble writing long-form stuff, but also because I kept having to look back through my account histories. There’s a lot more I’ve done that I haven’t explicitly written out here, and if you’re really &lt;strong&gt;that&lt;/strong&gt; interested, feel free to take a look at my &lt;a href=&quot;https://github.com/lexisother&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lastly I’d like to express my gratitude to everyone I’ve talked to this year. I’ve made a bunch of new friends and livened up my &lt;a href=&quot;https://alyxia.dev/friends&quot;&gt;friends page&lt;/a&gt; as a result. Thank you all for sticking around.&lt;/p&gt;
&lt;p&gt;Late happy new year’s to you all!&lt;/p&gt;</content:encoded></item><item><title>Applying hobby knowledge to work</title><link>https://alyxia.dev/blog/applying-knowledge</link><guid isPermaLink="true">https://alyxia.dev/blog/applying-knowledge</guid><pubDate>Sat, 15 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For years now, I’ve been programming as a hobby. It’s my passion to create, even if the things I make aren’t perceived as useful. One thing I’ve noticed is that over the years, you start looking back on older projects as a reference for anything you’re currently working on.&lt;/p&gt;
&lt;p&gt;Recently, my employer asked me to finish a plugin he was working on for the CMS we offer to clients. There’s a library in the frontend code for the CMS that the creators wrote themselves that looked strangely familiar to something I’ve worked with before.&lt;/p&gt;
&lt;p&gt;But before I get to that, I have to explain &lt;em&gt;why&lt;/em&gt; this was so familiar.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;classes-in-early-javascript&quot;&gt;Classes in early JavaScript&lt;/h2&gt;
&lt;p&gt;JavaScript didn’t get any native support for classes until ES6 (which released in 2015) despite already having the &lt;code&gt;new&lt;/code&gt; keyword which could call a function and return a new object with said function as the &lt;code&gt;.prototype.constructor&lt;/code&gt; property.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sayName&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;#39;I am &amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.name);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Class &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;#39;Alyxia&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Class.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sayName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// =&amp;gt; I am Alyxia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In 2006, &lt;a href=&quot;http://dean.edwards.name/&quot;&gt;Dean Edwards&lt;/a&gt; (who I can find surprisingly little about), published &lt;a href=&quot;http://dean.edwards.name/weblog/2006/03/base/&quot;&gt;Base.js&lt;/a&gt;, a single file you could add to your website to ease the process of creating class-like objects in JavaScript.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; object &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Base.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  value: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;#39;some data&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  method&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    alert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;#39;Hello World!&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;object.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ==&amp;gt; Hello World!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, anything that calls &lt;code&gt;extend&lt;/code&gt; on &lt;code&gt;Base&lt;/code&gt;, &lt;strong&gt;is also inherently extendable.&lt;/strong&gt; So in this example, &lt;code&gt;object.extend(...)&lt;/code&gt; would be completely valid, and the resulting object would &lt;em&gt;inherit&lt;/em&gt; any methods and properties from &lt;code&gt;object&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This system worked as follows, where &lt;code&gt;A&lt;/code&gt; is &lt;code&gt;Base&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt; is your class definition:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Upon calling &lt;code&gt;B = A.extend(C)&lt;/code&gt;, copy all properies and methods of &lt;code&gt;C&lt;/code&gt; into a new object&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;C&lt;/code&gt;’s prototype to that of &lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Link the inherited methods from &lt;code&gt;A&lt;/code&gt; into &lt;code&gt;C&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It sounds complex, but in practice, it’s dead simple and quite intuitive.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;simple-inheritance&quot;&gt;Simple Inheritance&lt;/h2&gt;
&lt;p&gt;In 2008, &lt;a href=&quot;https://github.com/jeresig&quot;&gt;John Resig&lt;/a&gt;, who is best known for his work on world-renowned library &lt;a href=&quot;https://jquery.com&quot;&gt;jQuery&lt;/a&gt;, wrote an entire yet simple inheritance system in JavaScript for the in-progress book he was writing.&lt;/p&gt;
&lt;p&gt;After seeing many attempts at “class systems” in JavaScript, two were his favourites, namely Dean Edwards’ Base.js, and something I’d never heard about before called &lt;a href=&quot;http://prototypejs.org/&quot;&gt;Prototype&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Resig wrote a blog post about his attempt &lt;a href=&quot;https://johnresig.com/blog/simple-javascript-inheritance/&quot;&gt;here&lt;/a&gt; if you’re interested in the way the thing looked. All in all it’s pretty similar to Base.js, except Resig’s attempt had a considerably shorter implementation for the &lt;code&gt;extend&lt;/code&gt; function.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;impact&quot;&gt;Impact&lt;/h2&gt;
&lt;p&gt;The majority of game engines in the modern day are written in object oriented languages. This was no different back in 2010, with well known engines like Unity and Unreal Engine being written in C++. To clearly separate concerns in your game, it’s typically recommended to use classes as well. (e.g. a base class &lt;code&gt;Entity&lt;/code&gt; that &lt;code&gt;Player&lt;/code&gt; and &lt;code&gt;Enemy&lt;/code&gt; extend from)&lt;/p&gt;
&lt;p&gt;In late 2010, Polish developer Dominic Szablewski, otherwise known as &lt;a href=&quot;https://github.com/phoboslab&quot;&gt;phoboslab&lt;/a&gt;, open sourced v1.14 of his game library &lt;a href=&quot;https://impactjs.com/&quot;&gt;Impact&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Impact, which is largely a “bring your own glue” game engine, was obviously also written before JavaScript had any coherent concept of classes. That’s why Impact’s core file directly included John Resig’s implementation of the class system. Basically every system in the game, like entities, the input manager, the sound system, collision/background maps, were all written using &lt;code&gt;ig.Class.extend(...)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This meant that, for example, fonts were simple to implement. Fonts are image files. The &lt;strong&gt;font specific&lt;/strong&gt; functionality is in &lt;code&gt;ig.Font&lt;/code&gt;, which is defined as…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ig.Font &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ig.Image.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So even in Impact’s own source code, it makes use of this system to separate concerns. The handy thing about this is that game developers could do the same thing; create their own extendable classes or extensions of existing ones.&lt;/p&gt;
&lt;p&gt;There was &lt;strong&gt;one core difference&lt;/strong&gt; in comparison to Resig’s implementation that Szablewski added himself: &lt;code&gt;ig.Class.inject&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;injecting-into-classes&quot;&gt;Injecting into classes&lt;/h2&gt;
&lt;p&gt;What made Impact so different is its ability to inject into classes at runtime. The best way to explain is to just give an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ig.Person &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ig.Class.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  sayName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.name);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; me &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ig.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Person&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;#39;Alyxia&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;me.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sayName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// =&amp;gt; Alyxia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ig.Person.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;inject&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  sayName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;#39;Hello, my name is &amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.name);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;me.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sayName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// =&amp;gt; Hello, my name is Alyxia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To explain:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a class named &lt;code&gt;Person&lt;/code&gt; with a method that logs out the name&lt;/li&gt;
&lt;li&gt;Create a new instance of &lt;code&gt;Person&lt;/code&gt; named &lt;code&gt;me&lt;/code&gt; with name &lt;code&gt;Alyxia&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;sayName&lt;/code&gt;, which logs out the person’s name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inject into &lt;code&gt;ig.Person&lt;/code&gt;&lt;/strong&gt; to change the functionality of &lt;code&gt;sayName&lt;/code&gt;, permanently altering &lt;strong&gt;all existing and future instances of &lt;code&gt;Person&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;sayName&lt;/code&gt; again, showing our new output&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Technically, if you were to build a game with Impact, your game is inherently moddable.&lt;/p&gt;
&lt;p&gt;Speaking of…&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;crosscode&quot;&gt;CrossCode&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cross-code.com/&quot;&gt;CrossCode&lt;/a&gt; is an action RPG released in 2018, which started development in 2011.&lt;/p&gt;
&lt;p&gt;I’ve been in love with the game since I discovered it, and as such I’ve been a part of the modding community since late 2018. After people discovered how to run their own code before/during the game… modding became extremely easy. This is because it used Impact as the game engine. 95% of the game’s core functionality is defined in Impact classes that are accessible through the global objects &lt;code&gt;ig&lt;/code&gt; and &lt;code&gt;sc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nowadays, a good chunk of the mods for the game are written in &lt;a href=&quot;https://typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;. The requirement for comfortably being able to access stuff on &lt;code&gt;ig&lt;/code&gt; and &lt;code&gt;sc&lt;/code&gt;, and additionally call &lt;code&gt;extend&lt;/code&gt; and &lt;code&gt;inject&lt;/code&gt; on any classes, is writing &lt;em&gt;type definitions&lt;/em&gt; for everything.&lt;/p&gt;
&lt;p&gt;Community member &lt;a href=&quot;https://github.com/dmitmel&quot;&gt;dmitmel&lt;/a&gt; made great effort toward this goal during the development of the first big TypeScript mod, &lt;a href=&quot;https://github.com/CCDirectLink/crosscode-ru&quot;&gt;crosscode-ru&lt;/a&gt;, which is a Russian translation of the game. To properly mod the game in TS, he wrote type definitions (labeled the “Ultimate CrossCode Typedefs”, later in this post referenced as UCCTD) which eventually resulted in a &lt;a href=&quot;https://github.com/CCDirectLink/ultimate-crosscode-typedefs&quot;&gt;single repository&lt;/a&gt; specifically meant for containing typedefs for the entire game.&lt;/p&gt;
&lt;p&gt;The most important and core part of these typedefs are the definitions of Impact’s class system.&lt;/p&gt;
&lt;p&gt;For global classes in the game, like &lt;code&gt;sc.ItemListBox&lt;/code&gt;, we can define them like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;declare&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; global {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; sc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ItemListBox&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;GuiElementBase&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;      list&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; sc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ButtonListBox&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      clear&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;skip&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Nullable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      addButton&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;gui&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FocusGui&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      getChildren&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FocusGui&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ItemListBoxConstructor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ImpactClass&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ItemListBox&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        topPadding&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        noHeader&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        buttonInteract&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ButtonInteractEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      )&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ItemListBox&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ItemListBox&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ItemListBoxConstructor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we see a couple things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;ItemListBox&lt;/code&gt; interface properly extends from &lt;code&gt;ig.GuiElementBase&lt;/code&gt;, which is defined elsewhere in a similar fashion&lt;/li&gt;
&lt;li&gt;All the properties in this interface will be available to instances of the class. (so after calling &lt;code&gt;new&lt;/code&gt; on it) Third, the &lt;code&gt;ItemListBoxConstructor&lt;/code&gt; acts as our “callable constructor” and contains the arguments we pass to the constructor.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ItemListBox&lt;/code&gt; var is a reference to our constructor and is the thing that eventually appears on the &lt;code&gt;sc&lt;/code&gt; namespace.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, now we’ve got type definitions for &lt;code&gt;sc.ItemListBox&lt;/code&gt; so we can call it as normal code, with type checking. Why am I highlighting this project though…?&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-actual-gist-of-the-post&quot;&gt;The actual gist of the post&lt;/h2&gt;
&lt;p&gt;At work, we use &lt;a href=&quot;https://craft-cms.com&quot;&gt;CraftCMS&lt;/a&gt; to build websites for customers. The point is that we architecture the CMS in such a way that eventually, customers can completely self-manage their websites content-wise, so we won’t even have to intervene with over 60% of changes they want made.&lt;/p&gt;
&lt;p&gt;Craft supports plugins. There’s many companies and organisations making these plugins, but it’s perfectly normal for a regular developer to make their own plugin for some niche feature if it doesn’t already exist. We had to do this for a couple customers, namely store owners, so they can specify their store’s opening times in a nice table and add exceptions to those specified times.&lt;/p&gt;
&lt;p&gt;So, I was put to work. I got most of the functionality out of the way pretty easily since one of my coworkers had done the majority of the work before I got started on it, but the main problem now was rendering nicely editable tables with time selectors so people authoring one of these opening hour tables wouldn’t have to type so much manually. Additionally, it had to be possible to &lt;strong&gt;create a new period&lt;/strong&gt; below an existing one so you could, for example, say that from January through March you were opened from 8am to 5pm, and from that point onwards from 9am to 4pm.&lt;/p&gt;
&lt;p&gt;To create one of these editable tables, most plugin developers use Craft’s very own &lt;code&gt;Craft.EditableTable&lt;/code&gt; which conveniently exists on the &lt;code&gt;window&lt;/code&gt;. Cool!&lt;/p&gt;
&lt;p&gt;As clueless me traveled to the Craft GitHub repository to take a look at the source code for this thing, I stumbled across something weird. The definition of the object looked like…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Craft.EditableTable &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Garnish.Base.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;extend&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  /* ... */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Huh. That’s weird. What’s Garnish? I delved further and further through Craft’s AssetBundles until I found a folder labeled &lt;code&gt;garnish&lt;/code&gt;, and looked in there. After a bit of poking through there, I found a file called &lt;code&gt;Base.js&lt;/code&gt;, which started with…&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/*!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	Base.js, version 1.1a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	Copyright 2006-2010, Dean Edwards&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	License: http://www.opensource.org/licenses/mit-license.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ah. Well, isn’t that interesting.&lt;/p&gt;
&lt;p&gt;Now, this is all fine and dandy, but my Craft plugin’s frontend logic is using TypeScript. If only there was a solution to this problem…&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-ultimate-craft-cms-typedefs&quot;&gt;The Ultimate Craft CMS Typedefs&lt;/h2&gt;
&lt;p&gt;When I saw the way Base.js classes worked, I immediately knew I could cobble something functional together by referencing UCCTD’s Impact class definitions. There was just one striking difference between Impact classes and Base.js classes: the second argument to &lt;code&gt;extend&lt;/code&gt;. This is what allows the developer to declare static properties on a class. (&lt;code&gt;.extend({ /* instance properties */}, { /* static properties */})&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Impact classes do not have this, so I couldn’t just use UCCTD’s definitions out of the box. I ended up turning to my good friend Nax who eventually figured out how to properly type this functionality. After this was done, I created the empty stub type for Garnish’s Base class, and with that, I can now write typings for Craft’s classes.&lt;/p&gt;
&lt;p&gt;The way they’re defined is pretty much identical to what I’ve shown off for UCCTD, with two differences:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;naming (&lt;code&gt;ImpactClass&lt;/code&gt; becomes &lt;code&gt;BaseClass&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;two generics instead of 1 in &lt;code&gt;BaseClass&lt;/code&gt; (&lt;code&gt;BaseClass&amp;lt;Instance, Static&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that’s how I applied knowledge I garnered from hobby projects over the years to something I actually need to do in my work. The overlap is just a small coincidence, but it’s still really cool to me.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Honestly, for one of my first long-form posts, this is awful. Way too much talking for a point I could’ve explained in a &amp;lt;=100 word post on some social media. This post also took me several months to finish due to how unmotivated I was to write it. Let it be known that posts like this are not my forte, but I just wanted to write about something. Hope it turned out OK.&lt;/p&gt;</content:encoded></item><item><title>Making my Nix config smarter</title><link>https://alyxia.dev/blog/nix-autoimport</link><guid isPermaLink="true">https://alyxia.dev/blog/nix-autoimport</guid><pubDate>Mon, 12 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So, today I was playing around with my Nix config again, and I thought “wouldn’t it be nice if I wouldn’t need a manual &lt;code&gt;imports&lt;/code&gt; array on my user config?”&lt;/p&gt;
&lt;p&gt;And so I set out to figure out what a good approach was for the situation. I remembered there was a function for listing directories, because back when I was messing around with operator overloading, I used that thing to demonstrate some code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  __mul&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x: y:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; builtins&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;typeOf&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;quot;lambda&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; then&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      z: &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  builtins&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;attrNames&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; builtins&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;readDir&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ./.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The operator overloading obviously isn’t that important here… but it’s still fun to show off By the way, this would provide you with a list of files in the current directory. (e.g. &lt;code&gt;[ &amp;quot;.git&amp;quot; &amp;quot;Documents&amp;quot; &amp;quot;Downloads&amp;quot; ]&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;So, with that knowledge, I set out to figure out how I could generate a list of files that the &lt;code&gt;imports&lt;/code&gt; property could read. After a short while, I found a &lt;a href=&quot;https://www.reddit.com/r/NixOS/comments/j5pa9o/comment/g81dvop&quot;&gt;Reddit comment&lt;/a&gt; that demonstrated usage of the &lt;code&gt;map&lt;/code&gt; function accompanied by our previous findings, &lt;code&gt;attrNames&lt;/code&gt; and &lt;code&gt;readDir&lt;/code&gt;. In Nix, &lt;code&gt;map&lt;/code&gt; works similarly as in JS, as in that the following Nix code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (e: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;test &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;…would give output similar to this JS code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; `test ${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code this Reddit user gave would read the current dir, which would give output like &lt;code&gt;{ &amp;quot;test.nix&amp;quot; = &amp;quot;regular&amp;quot;; }&lt;/code&gt;, run &lt;code&gt;attrNames&lt;/code&gt; on that, which outputs a list of key names in the object, e.g. &lt;code&gt;[ &amp;quot;test.nix&amp;quot; ]&lt;/code&gt;, and then stick the path to the current derivation in front of it, like so: &lt;code&gt;/nix/store/&amp;lt;id&amp;gt;-alymac/test.nix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This works fine! There are no issues with this approach! Except for one. What if I want subdirectories? Well, you can’t. &lt;code&gt;readDir&lt;/code&gt; gives you all files in the current directory, no more no less. After a bit of snooping in nixpkgs’ &lt;code&gt;lib&lt;/code&gt; folder, I found &lt;em&gt;just&lt;/em&gt; the function I need, &lt;a href=&quot;https://github.com/NixOS/nixpkgs/blob/c8cb1f7a2df211360ff492b13ffdf896a8c25d00/lib/filesystem.nix#L144-L157&quot;&gt;&lt;code&gt;listFilesRecursive&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After only a couple invocations of this function in the REPL, I came to the solution on how to use it. I could get rid of the call to &lt;code&gt;attrNames&lt;/code&gt;, as &lt;code&gt;listFilesRecursive&lt;/code&gt; outputs a list of full paths to files, not an object. With this knowledge, I edited my invocation as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (n: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;filesystem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;listFilesRecursive&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ./.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One caveat I found with this approach was that because &lt;code&gt;listFilesRecursive&lt;/code&gt; outputs a list of &lt;em&gt;full paths&lt;/em&gt; instead of just filenames, I was no longer able to pop the path to the current derivation in front of &lt;code&gt;n&lt;/code&gt;, because instead of &lt;code&gt;n&lt;/code&gt; being a simple filename, it was now… a &lt;code&gt;/nix/store&lt;/code&gt; path to that file. As in, &lt;code&gt;/nix/store/&amp;lt;id&amp;gt;-test.nix&lt;/code&gt;. That’s what I get for using full paths. I guess what I could do is take the full path to the current file and trim off the irrelevant part, but it seems like more effort than it’s worth, because now you’d have to take subdirectories into account again.&lt;/p&gt;
&lt;p&gt;And with that, my result code is as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  importMap&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; map&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (n: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;filesystem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;listFilesRecursive&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ./.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  importsFiltered&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    builtins&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;filter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      (x: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;strings&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;hasInfix&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;quot;default&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;      importMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s not anything remarkable in any way, but this &lt;em&gt;did&lt;/em&gt; take me about an hour to accomplish.&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;Code that got me to write this post (the post content is basically just my code comment but longer)&lt;/summary&gt;&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # We&amp;#39;ve got a small issue here. I tested this in a repl, and what I&amp;#39;ve&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # observed is that listFilesRecursive spits out [ /full/path/to/default.nix ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # while builtins.readDir spits out { &amp;quot;default.nix&amp;quot; = &amp;quot;regular&amp;quot;; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # In theory, this shouldn&amp;#39;t be much of an issue, however, when using readDir&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # I would be able to do `map (n: &amp;quot;${./.}/${n}&amp;quot;), while when using&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # listFilesRecursive I have to use `map (n: &amp;quot;${n}&amp;quot;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # The difference here is that when using listFilesRecursive, `n` becomes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # `/nix/store/&amp;lt;ID&amp;gt;-default.nix`, meaning it can be used as-is, but when using&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # `readDir` it becomes `default.nix`, meaning the string used in the map&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # callback must be `&amp;quot;${./.}/${n}&amp;quot;` to get a path to the current derivation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # where the nix file lives in.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # Currently, I am unsure of the implications of having all files separately.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # To do it &amp;quot;the right way&amp;quot; I&amp;#39;d obviously prefer the nix files to be children&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # of the alymac derivation, but it seems that if I want my map of imports to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # be generated from the entire directory listing, it isn&amp;#39;t going to work out.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # The solution was slightly modified from this Reddit answer:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # &amp;lt;https://www.reddit.com/r/NixOS/comments/j5pa9o/comment/g81dvop/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # So, let&amp;#39;s get all files in the current directory...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  importMap&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; map&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (n: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;filesystem&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;listFilesRecursive&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ./.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # importMap = map&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  #   (n: &amp;quot;${./.}/${n}&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  #   (builtins.attrNames (builtins.readDir ./.));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # And filter out default.nix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  importsFiltered&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    builtins&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;filter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      (x: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;strings&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;hasInfix&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;quot;default&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;      importMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;home-manager&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;alyxia&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;... &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}: { &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Defined further above, a list of files to import.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;imports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; importsFiltered&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded></item></channel></rss>