<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tajudeen Abdulgafar</title>
    <description>The latest articles on DEV Community by Tajudeen Abdulgafar (@tajudeen_abdulgafar_e0363).</description>
    <link>https://dev.to/tajudeen_abdulgafar_e0363</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2137332%2F7796d006-ff36-421e-aa67-33bc85337a4c.jpg</url>
      <title>DEV Community: Tajudeen Abdulgafar</title>
      <link>https://dev.to/tajudeen_abdulgafar_e0363</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tajudeen_abdulgafar_e0363"/>
    <language>en</language>
    <item>
      <title>Taking Repo Context Packager to the Next Level</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sun, 30 Nov 2025 05:14:39 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/taking-repo-context-packager-to-the-next-level-3fe8</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/taking-repo-context-packager-to-the-next-level-3fe8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In Release 0.3, I built and published &lt;a href="https://www.npmjs.com/package/@tajudeen/repo-context-packager" rel="noopener noreferrer"&gt;&lt;code&gt;repo-context-packager&lt;/code&gt;&lt;/a&gt;, a CLI tool that helps developers package their repository context for Large Language Models (LLMs). While the initial release (v1.0.3) works well and is available on npm, there is a significant difference between a "working" project and a "professional" open source project.&lt;/p&gt;

&lt;p&gt;For Release 0.4, my goal is to bridge that gap. I plan to take this tool from a manual, local-first utility to a fully automated, widely distributable package that follows modern DevOps best practices.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Plan: What I Will Do
&lt;/h2&gt;

&lt;p&gt;Over the next few weeks, I will focus on four key areas:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Remote Repository Support
&lt;/h3&gt;

&lt;p&gt;Currently, users must manually clone a repository before they can package it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Goal:&lt;/strong&gt; Allow users to pass a GitHub URL directly (e.g., &lt;code&gt;repo-context-packager https://github.com/user/repo&lt;/code&gt;). The tool will clone it to a temporary directory, package it, and clean up automatically. This significantly reduces friction for quick analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Security Redaction
&lt;/h3&gt;

&lt;p&gt;Pasting code into LLMs carries a risk: accidentally leaking API keys or credentials.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Goal:&lt;/strong&gt; Implement a &lt;code&gt;--safe&lt;/code&gt; flag that scans files for potential secrets (AWS keys, private keys, &lt;code&gt;.env&lt;/code&gt; variables) and replaces them with &lt;code&gt;[REDACTED]&lt;/code&gt;. This makes the tool safer for enterprise use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Automating the Release Process (CI/CD)
&lt;/h3&gt;

&lt;p&gt;Currently, releasing a new version involves a manual checklist: running tests, building the project, bumping versions, and running &lt;code&gt;npm publish&lt;/code&gt;. This is prone to human error.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Goal:&lt;/strong&gt; Implement a GitHub Actions workflow that automatically tests every PR and publishes new versions to npm whenever a new release tag is pushed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Expanding Distribution
&lt;/h3&gt;

&lt;p&gt;While &lt;code&gt;npm install -g&lt;/code&gt; is standard for Node.js developers, many macOS users prefer Homebrew for managing CLI tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Goal:&lt;/strong&gt; Create a Homebrew Tap for &lt;code&gt;repo-context-packager&lt;/code&gt;, allowing users to install it via &lt;code&gt;brew install repo-context-packager&lt;/code&gt;. This lowers the barrier to entry and makes updates easier to manage.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why This Work Matters
&lt;/h2&gt;

&lt;p&gt;I chose to continue working on &lt;code&gt;repo-context-packager&lt;/code&gt; because it solves a real problem I face daily: giving LLMs the right context. However, the &lt;em&gt;engineering&lt;/em&gt; motivation for Release 0.4 is to master the "meta" skills of software development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Feature Development:&lt;/strong&gt; Adding remote repository support and security redaction involves handling temporary files, git operations, and regex pattern matching—a great exercise in robust Node.js development.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;DevOps &amp;amp; Automation:&lt;/strong&gt; Writing code is only half the job. Ensuring that code can be reliably tested and deployed is what separates hobby projects from professional engineering. Learning GitHub Actions in depth is a career-relevant skill.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;User Experience:&lt;/strong&gt; Making installation seamless (via Homebrew) shows respect for the user's time. It shifts the focus from "how do I run this?" to "how do I use this?"&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Maintainability:&lt;/strong&gt; By automating the tedious parts of maintenance, I make it easier for myself (and future contributors) to keep the project alive.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Approach
&lt;/h2&gt;

&lt;p&gt;Here is my roadmap for the coming weeks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Week 1 (Planning):&lt;/strong&gt; Defining the scope (this post) and researching GitHub Actions for npm publishing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Week 2 (Features &amp;amp; Automation):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Implement &lt;strong&gt;Remote Repository Support&lt;/strong&gt; (clone -&amp;gt; package -&amp;gt; cleanup).&lt;/li&gt;
&lt;li&gt;  Implement &lt;strong&gt;Security Redaction&lt;/strong&gt; (regex-based secret scanning).&lt;/li&gt;
&lt;li&gt;  Set up a CI pipeline to run tests on every Pull Request.&lt;/li&gt;
&lt;li&gt;  Set up a CD pipeline to publish to npm on git tag creation.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Deliverable:&lt;/em&gt; A new feature release (v1.1.0) and automated pipeline.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Week 3 (Distribution &amp;amp; Polish):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Create a Homebrew formula and Tap.&lt;/li&gt;
&lt;li&gt;  Incorporate user feedback (bug fixes/UI tweaks).&lt;/li&gt;
&lt;li&gt;  Finalize documentation (CHANGELOG, badges).&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Deliverable:&lt;/em&gt; A polished, professional open source repository.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




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

&lt;p&gt;Release 0.4 is about maturity. It's about taking a raw tool and wrapping it in the professional infrastructure it needs to thrive. By the end of this term, &lt;code&gt;repo-context-packager&lt;/code&gt; won't just be a piece of code—it will be a robust, automated, and easily installable product.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>devops</category>
      <category>opensource</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Implementing Authentication Middleware in Next.js with i18n Support</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 22 Nov 2025 04:03:36 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/implementing-authentication-middleware-in-nextjs-with-i18n-support-3iom</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/implementing-authentication-middleware-in-nextjs-with-i18n-support-3iom</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Building secure web applications requires implementing proper authentication and authorization mechanisms. In Next.js applications, middleware provides an excellent way to protect routes and handle authentication before requests reach your pages. This blog post will walk you through implementing a robust authentication middleware that seamlessly integrates with internationalization (i18n) routing for &lt;a href="https://github.com/TemaDeveloper/library_proj" rel="noopener noreferrer"&gt;library_proj&lt;/a&gt;, one of the project I contributed to doing the hacktoberfest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Authentication Middleware?
&lt;/h2&gt;

&lt;p&gt;Authentication middleware sits between the client request and your application logic, allowing you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protect routes&lt;/strong&gt; before they're rendered&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect unauthenticated users&lt;/strong&gt; to login pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preserve intended destinations&lt;/strong&gt; with redirect parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevent authenticated users&lt;/strong&gt; from accessing auth pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralize authentication logic&lt;/strong&gt; for better maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By handling authentication at the middleware level, you ensure security checks happen early in the request lifecycle, before any server-side rendering or data fetching occurs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;The authentication middleware works in conjunction with Next.js App Router and includes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → Middleware → Authentication Check → Route Protection → i18n Routing → Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The middleware performs these checks in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extract locale&lt;/strong&gt; from the pathname or browser preferences&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check authentication status&lt;/strong&gt; via cookies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Determine route type&lt;/strong&gt; (public vs. protected)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply redirects&lt;/strong&gt; based on authentication state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle locale routing&lt;/strong&gt; for proper i18n support&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implementation Details
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Authentication Check
&lt;/h3&gt;

&lt;p&gt;The middleware checks for authentication tokens stored in cookies. It supports multiple token types for flexibility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Check for either auth_token or session_token&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authToken&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Route Classification
&lt;/h3&gt;

&lt;p&gt;The middleware distinguishes between public and protected routes:&lt;/p&gt;

&lt;h4&gt;
  
  
  Public Routes
&lt;/h4&gt;

&lt;p&gt;Routes accessible without authentication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/signup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/register&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/forgot-password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/reset-password&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Protected Routes
&lt;/h4&gt;

&lt;p&gt;By default, &lt;strong&gt;all routes are protected&lt;/strong&gt; except those explicitly marked as public. This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dashboard routes (&lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/my_books&lt;/code&gt;, &lt;code&gt;/books&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Profile and settings pages&lt;/li&gt;
&lt;li&gt;Any other application routes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Protection Logic
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isProtectedRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pathWithoutLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getPathnameWithoutLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// If it's a public route, it's not protected&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isPublicRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// All other routes are protected by default&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "secure by default" approach ensures that new routes are automatically protected unless explicitly added to the public routes list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Automatic Route Protection
&lt;/h3&gt;

&lt;p&gt;All routes are protected by default, reducing the risk of accidentally exposing sensitive pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Smart Redirects
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unauthenticated users&lt;/strong&gt; accessing protected routes are redirected to &lt;code&gt;/login&lt;/code&gt; with a &lt;code&gt;redirect&lt;/code&gt; parameter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authenticated users&lt;/strong&gt; accessing auth pages (login, signup) are redirected to the home page&lt;/li&gt;
&lt;li&gt;Locale is preserved in all redirects&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. i18n Integration
&lt;/h3&gt;

&lt;p&gt;The middleware seamlessly handles internationalization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extracts locale from pathname&lt;/li&gt;
&lt;li&gt;Preserves locale during redirects&lt;/li&gt;
&lt;li&gt;Works with browser language preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Server Component Support
&lt;/h3&gt;

&lt;p&gt;Authentication status is exposed via headers for server components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-authenticated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server components can access this header to conditionally render content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In a server component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAuthenticated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-authenticated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Secure Cookie Settings
&lt;/h3&gt;

&lt;p&gt;When setting authentication cookies, use secure settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In your login handler&lt;/span&gt;
&lt;span class="nf"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// Prevent XSS attacks&lt;/span&gt;
  &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// HTTPS only in production&lt;/span&gt;
  &lt;span class="na"&gt;sameSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// CSRF protection&lt;/span&gt;
  &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 7 days&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Token Validation
&lt;/h3&gt;

&lt;p&gt;For production, consider validating tokens server-side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Validate token with your backend&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BACKEND_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/auth/verify`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Error Handling
&lt;/h3&gt;

&lt;p&gt;Add proper error handling for edge cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Middleware logic&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Middleware error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Fallback: allow request but log error&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Testing
&lt;/h3&gt;

&lt;p&gt;Test your middleware with different scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Unauthenticated user accessing protected route → redirects to login&lt;/li&gt;
&lt;li&gt;✅ Authenticated user accessing login → redirects to home&lt;/li&gt;
&lt;li&gt;✅ Authenticated user accessing protected route → allowed&lt;/li&gt;
&lt;li&gt;✅ Locale preservation during redirects&lt;/li&gt;
&lt;li&gt;✅ Public routes accessible without authentication&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Implementing authentication middleware in Next.js provides a robust, centralized way to protect your application routes. By combining authentication checks with i18n routing, you create a seamless user experience that works across different languages and locales.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>nextjs</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Publish the repo-context-packager</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 22 Nov 2025 02:00:04 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/publish-the-repo-context-packager-13mp</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/publish-the-repo-context-packager-13mp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;After weeks of development, testing, and CI setup, it was time to share this tool with the world. The &lt;a href="https://github.com/Abdulgafar4/repo-context-packager" rel="noopener noreferrer"&gt;Repository Context Packager&lt;/a&gt; had proven useful locally, but making it installable via npm would let others use it without cloning the repo. Well, this is not my first npm release, but this blog documents my journey from a local CLI tool to a published npm package—the challenges, solutions, and lessons learned along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Executive Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chose npm&lt;/strong&gt; as the package registry (the standard for Node.js/TypeScript projects)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Published as scoped package:&lt;/strong&gt; &lt;code&gt;@tajudeen/repo-context-packager@1.0.3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configured package.json&lt;/strong&gt; with &lt;code&gt;bin&lt;/code&gt; field for CLI installation, &lt;code&gt;files&lt;/code&gt; field for clean publishing, and &lt;code&gt;postbuild&lt;/code&gt; script for shebang injection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolved package name conflict&lt;/strong&gt; by using scoped package naming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updated README.md&lt;/strong&gt; with clear installation and usage instructions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Created git tags&lt;/strong&gt; (v0.9.0 for practice, v1.0.3 for release)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tool is now installable globally via &lt;code&gt;npm install -g @tajudeen/repo-context-packager&lt;/code&gt; and ready for user testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Choosing the Release Tool and Package Registry
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why npm?
&lt;/h3&gt;

&lt;p&gt;For a Node.js/TypeScript CLI tool, &lt;strong&gt;npm&lt;/strong&gt; (Node Package Manager) was the obvious choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native support:&lt;/strong&gt; npm is built into Node.js, so every user already has it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI tool support:&lt;/strong&gt; npm's &lt;code&gt;bin&lt;/code&gt; field makes it trivial to create globally installable commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wide adoption:&lt;/strong&gt; Most JavaScript/TypeScript developers are familiar with npm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free for public packages:&lt;/strong&gt; Publishing public packages to npm is free and straightforward&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Release Process: Step by Step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Preparing package.json
&lt;/h3&gt;

&lt;p&gt;Before publishing, I needed to configure &lt;code&gt;package.json&lt;/code&gt; for CLI distribution:&lt;/p&gt;

&lt;h4&gt;
  
  
  Added &lt;code&gt;bin&lt;/code&gt; Field
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;bin&lt;/code&gt; field tells npm which file to use as the executable command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"repo-context-packager"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/cli.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows users to run &lt;code&gt;repo-context-packager&lt;/code&gt; after installing globally.&lt;/p&gt;

&lt;h4&gt;
  
  
  Added &lt;code&gt;files&lt;/code&gt; Field
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;files&lt;/code&gt; array controls what gets published. I wanted to exclude source files, tests, and development configs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"LICENSE"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduced the package size from ~90KB to ~20KB by excluding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/&lt;/code&gt; (TypeScript source files)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node_modules/&lt;/code&gt; (dependencies are installed separately)&lt;/li&gt;
&lt;li&gt;Test files (not needed for runtime)&lt;/li&gt;
&lt;li&gt;Development configs (&lt;code&gt;tsconfig.json&lt;/code&gt;, &lt;code&gt;vitest.config.ts&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Updated &lt;code&gt;main&lt;/code&gt; Field
&lt;/h4&gt;

&lt;p&gt;Changed from pointing to source to compiled output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/cli.js"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Was:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/cli.ts"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Added &lt;code&gt;postbuild&lt;/code&gt; Script
&lt;/h4&gt;

&lt;p&gt;TypeScript doesn't preserve shebangs, so I added a postbuild script to inject &lt;code&gt;#!/usr/bin/env node&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postbuild"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node -e &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;const fs=require('fs');const f='dist/cli.js';const c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!'))fs.writeFileSync(f,'#!/usr/bin/env node&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n'+c);&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the compiled JavaScript can be executed directly as a CLI tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Creating Practice Tags
&lt;/h3&gt;

&lt;p&gt;Following best practices, I created a practice tag first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git tag &lt;span class="nt"&gt;-a&lt;/span&gt; v0.9.0 &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Practice release v0.9.0"&lt;/span&gt;
git push &lt;span class="nt"&gt;--follow-tags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This let me verify the tagging process worked before creating the real release tag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Building and Testing
&lt;/h3&gt;

&lt;p&gt;Before publishing, I ensured everything compiled and tested correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build      &lt;span class="c"&gt;# Compile TypeScript&lt;/span&gt;
npm run &lt;span class="nb"&gt;test&lt;/span&gt;:run   &lt;span class="c"&gt;# Run test suite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: The First Publishing Attempt
&lt;/h3&gt;

&lt;p&gt;My first attempt failed with a 403 error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm error 403 403 Forbidden - PUT https://registry.npmjs.org/repo-context-packager
npm error 403 You do not have permission to publish "repo-context-packager"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; The package name &lt;code&gt;repo-context-packager&lt;/code&gt; was already taken by a classmate (&lt;code&gt;cynthiafotso&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; Use a scoped package name. Scoped packages are namespaced under your npm username:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@tajudeen/repo-context-packager"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scoped packages are private by default, so I needed to publish with the &lt;code&gt;--access public&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm publish &lt;span class="nt"&gt;--access&lt;/span&gt; public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Version Bumping and Republishing
&lt;/h3&gt;

&lt;p&gt;After resolving the name conflict, I bumped the version and published:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Updated package.json version to 1.0.3&lt;/span&gt;
npm run build
npm publish &lt;span class="nt"&gt;--access&lt;/span&gt; public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Success!&lt;/strong&gt; The package was published as &lt;code&gt;@tajudeen/repo-context-packager@1.0.3&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Verifying Installation
&lt;/h3&gt;

&lt;p&gt;I tested the installation in a fresh directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp
&lt;span class="nb"&gt;mkdir &lt;/span&gt;test-install
&lt;span class="nb"&gt;cd &lt;/span&gt;test-install
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @tajudeen/repo-context-packager
repo-context-packager &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI worked perfectly! ✅&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Creating the Release Tag
&lt;/h3&gt;

&lt;p&gt;After successful publishing, I created the git tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git tag &lt;span class="nt"&gt;-a&lt;/span&gt; v1.0.3 &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Release v1.0.3 - Published to npm"&lt;/span&gt;
git push &lt;span class="nt"&gt;--follow-tags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What I Learned:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Challenge 1: Package Name Conflicts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Issue:&lt;/strong&gt; I assumed &lt;code&gt;repo-context-packager&lt;/code&gt; would be available, but it was already taken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Lesson:&lt;/strong&gt; Always check package name availability before finalizing your project name, or use scoped packages from the start. Scoped packages (&lt;code&gt;@username/package-name&lt;/code&gt;) are less likely to conflict and clearly indicate ownership.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Check:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view package-name  &lt;span class="c"&gt;# Returns 404 if available&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Challenge 2: Scoped Packages Are Private by Default
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Issue:&lt;/strong&gt; After switching to a scoped package, my first publish attempt seemed successful, but the package wasn't visible when trying to install it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Lesson:&lt;/strong&gt; Scoped packages default to private. You must explicitly publish with &lt;code&gt;--access public&lt;/code&gt; for public packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm publish &lt;span class="nt"&gt;--access&lt;/span&gt; public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  User Testing Session (Planned)
&lt;/h2&gt;

&lt;p&gt;As of this writing, user testing is scheduled but not yet completed. The plan is to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ask a colleague or friend&lt;/strong&gt; to install the package fresh:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @tajudeen/repo-context-packager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Have them follow the README&lt;/strong&gt; and try packaging a repository&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Observe and take notes&lt;/strong&gt; on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where they get stuck&lt;/li&gt;
&lt;li&gt;What's unclear in the documentation&lt;/li&gt;
&lt;li&gt;Any installation issues&lt;/li&gt;
&lt;li&gt;Whether the CLI commands are intuitive&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Update README&lt;/strong&gt; based on feedback (per Instruction.md Step 7)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll update this blog post after the user testing session with findings and improvements made.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scoped packages prevent conflicts:&lt;/strong&gt; Using &lt;code&gt;@username/package-name&lt;/code&gt; avoids name collisions and clearly shows ownership.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;code&gt;files&lt;/code&gt; field is essential:&lt;/strong&gt; Explicitly controlling what gets published keeps packages lean and professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shebangs matter for CLI tools:&lt;/strong&gt; Without &lt;code&gt;#!/usr/bin/env node&lt;/code&gt;, globally installed packages won't execute directly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test installation before celebrating:&lt;/strong&gt; Always verify the package installs and works in a fresh environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documentation is part of the release:&lt;/strong&gt; Updated README with installation instructions is crucial for user adoption.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Version management matters:&lt;/strong&gt; Using semantic versioning (semver) helps users understand compatibility and changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automate releases with GitHub Actions:&lt;/strong&gt; Set up a workflow that automatically publishes to npm when a new tag is pushed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add more installation methods:&lt;/strong&gt; Consider providing installation via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Homebrew (for macOS users)&lt;/li&gt;
&lt;li&gt;Direct download links&lt;/li&gt;
&lt;li&gt;Docker image&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Version badges:&lt;/strong&gt; Add npm version badges to README.md to show current version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Release notes:&lt;/strong&gt; Create a CHANGELOG.md to document changes between versions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User testing feedback:&lt;/strong&gt; After user testing, incorporate feedback into documentation and potentially code improvements.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;Publishing to npm transformed the Repository Context Packager from a local development tool into a shareable, installable package. The process was smoother than expected, with most challenges resolved by understanding npm's conventions (scoped packages, &lt;code&gt;files&lt;/code&gt; field, shebang injection).&lt;/p&gt;

&lt;p&gt;The key takeaway: &lt;strong&gt;good project structure makes publishing easy&lt;/strong&gt;. Because the project already had proper TypeScript compilation, dependency management, and build scripts, the publishing process required minimal code changes—mostly just configuration.&lt;/p&gt;

&lt;p&gt;Now that the tool is published, the next steps are user testing, gathering feedback, and iterating based on real-world usage. This is where the real learning begins!&lt;/p&gt;




&lt;h2&gt;
  
  
  NPM RELEASE
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@tajudeen/repo-context-packager" rel="noopener noreferrer"&gt;npm Package: @tajudeen/repo-context-packager&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cli</category>
      <category>npm</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building Confidence: CI, Local Tests</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 15 Nov 2025 03:13:16 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/building-confidence-ci-local-tests-1fn4</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/building-confidence-ci-local-tests-1fn4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This week, I set up automated test runs using GitHub Actions, cleaned up and strengthened our Vitest cases for the utility functions, and wrote documentation to help bring these practices into other repos. Now we’ve got a workflow that flags issues right away and encourages contributors to keep our quality standards high.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Continuous Integration Was the Missing Piece
&lt;/h2&gt;

&lt;p&gt;Until this week, the project relied on developers remembering to run &lt;code&gt;npm test&lt;/code&gt; before pushing. That’s fine when you’re solo and hyper-disciplined, but it doesn’t scale. CI rebuilds on neutral infrastructure, executes the Vitest suite, and blocks merges when tests fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executive Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Added a GitHub Actions workflow (&lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;) that runs &lt;code&gt;npm ci&lt;/code&gt; and &lt;code&gt;npm run test:run&lt;/code&gt; on every push or pull request targeting &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hardened &lt;code&gt;src/utils.test.ts&lt;/code&gt; with boundary cases, empty-input handling, and multi-line formatting checks so regressions surface immediately.&lt;/li&gt;
&lt;li&gt;Outlined an upstream contribution plan (&lt;code&gt;UtilsIncludeTest&lt;/code&gt; in &lt;code&gt;tests/utils_test.cpp&lt;/code&gt;) to ensure &lt;code&gt;onlyIncludedExtensions&lt;/code&gt; handles real-world include lists, whitespace, negative matches, and empty configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repository now fails fast when tests break, documents how to keep contributions safe, and provides a blueprint for sharing those habits beyond this codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow Highlights
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run: npm run test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key lessons:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;YAML indentation matters:&lt;/strong&gt; My first draft began with &lt;code&gt;- name: CI&lt;/code&gt;, so GitHub treated the workflow as an array element and ignored it. Removing the dash turned the lights on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock files are non-negotiable:&lt;/strong&gt; &lt;code&gt;actions/setup-node&lt;/code&gt; with &lt;code&gt;cache: npm&lt;/code&gt; refuses to run if it can’t find &lt;code&gt;package-lock.json&lt;/code&gt;. Before this, I didn't include package-lock in the project; I made it ignore it, committing the lock file, which unblocks deterministic installs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red → Green confidence:&lt;/strong&gt; I intentionally broke a test, let CI fail, studied the logs, and then fixed it. Watching the status flip from red to green proved that the workflow really guards the repo.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>Leveling Up With Automated Testing</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Fri, 07 Nov 2025 23:06:22 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/leveling-up-with-automated-testing-2f0i</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/leveling-up-with-automated-testing-2f0i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This week, I embark on a journey of Testing, which is one of the interesting aspects of Programming. Sometimes you will think you've got everything covered, but no, there are lots of loopholes than you think. So, for this Testing, I went with Vitest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Vitest?
&lt;/h2&gt;

&lt;p&gt;Automated testing was the focus for this lab, so I needed a framework that matched the TypeScript-first nature of the project. I compared Jest and Vitest, and ultimately went with &lt;strong&gt;Vitest&lt;/strong&gt; (&lt;a href="https://vitest.dev/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;) because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It runs tests directly against modern JS/TS without extra transpilation glue.&lt;/li&gt;
&lt;li&gt;Watch mode and focused test runs are built-in (&lt;code&gt;vitest --watch&lt;/code&gt;, &lt;code&gt;vitest run --filter ...&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Coverage via the &lt;code&gt;@vitest/coverage-istanbul&lt;/code&gt; plugin is a single flag away.&lt;/li&gt;
&lt;li&gt;The CLI feels familiar coming from Jest, so there was very little learning curve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only snag was peer dependency alignment: Vitest 4 expects &lt;code&gt;@types/node&lt;/code&gt; ≥ 20, while the project was still on 14. Bumping the type definitions resolved the install conflict without touching runtime Node requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework Setup
&lt;/h2&gt;

&lt;p&gt;Getting Vitest wired in was straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Installed the packages: &lt;code&gt;npm i -D vitest @vitest/coverage-istanbul&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Added a tiny &lt;code&gt;vitest.config.ts&lt;/code&gt; to ensure we use the Node environment and to configure coverage reporters.&lt;/li&gt;
&lt;li&gt;Replaced the placeholder &lt;code&gt;npm test&lt;/code&gt; script with &lt;code&gt;vitest&lt;/code&gt;, added helpers for single runs and watch mode, and exposed coverage via &lt;code&gt;npm run test:coverage&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Documented the commands in &lt;code&gt;README.md&lt;/code&gt; so anyone on the team can run the right workflow quickly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point, &lt;code&gt;npm test&lt;/code&gt; ran (and passed) an empty suite—mission accomplished for Step 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Test Suite
&lt;/h2&gt;

&lt;p&gt;I started small, writing the very first unit tests around the easiest pure functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;calculateTokens&lt;/code&gt;, &lt;code&gt;formatOutput&lt;/code&gt;, and &lt;code&gt;truncateContent&lt;/code&gt; in &lt;code&gt;src/utils.ts&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These covered happy paths as well as a couple of edge cases (rounding behaviour and truncation markers). Once that foundation was in place, I layered on additional suites for other parts of the codebase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Repository statistics&lt;/strong&gt; – verified that &lt;code&gt;RepositoryStatistics&lt;/code&gt; correctly tracks totals, token counts, directory sets, averages, limit checks, and reset behaviour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarizer&lt;/strong&gt; – confirmed that imports, exports, and function metadata are captured, and that the formatted output includes the right cues for summary mode. While writing these tests I discovered that async exports weren’t being picked up; fixing the regex so it recognises &lt;code&gt;export async function&lt;/code&gt; resulted in the first “aha!” bug found by testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Packager&lt;/strong&gt; – used Vitest’s filesystem-friendly test runner to spin up temporary directories, mock Git metadata, and exercise the higher-level workflow. These tests proved that the CLI can:

&lt;ul&gt;
&lt;li&gt;Analyse files and accumulate RepoInfo.&lt;/li&gt;
&lt;li&gt;Generate summary-mode output without throwing.&lt;/li&gt;
&lt;li&gt;Respect &lt;code&gt;maxFileSize&lt;/code&gt; limits and skip oversized files.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Altogether the suite now has 12 tests, touching everything from helper utilities to integration-style Packager runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Focused Tests (Step 4)
&lt;/h2&gt;

&lt;p&gt;One pain point with larger projects is rerunning the entire suite while iterating on a single failing test. Vitest’s command-line options make this easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm run test:watch&lt;/code&gt; keeps tests hot-reloading as files change.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run test:file -- src/packager.test.ts&lt;/code&gt; scopes execution to one file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run test:run -- --filter "Packager"&lt;/code&gt; is handy when I just want the Packager suite.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These scripts, together with the README notes, satisfied Step 4’s “test runner improvements” goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional Coverage
&lt;/h2&gt;

&lt;p&gt;Although not strictly required, the coverage command (&lt;code&gt;npm run test:coverage&lt;/code&gt;) is ready to go thanks to the Istanbul plugin. Running it highlights remaining gaps—logger helpers and some CLI validation branches are still untested—which gives me a roadmap for future edge-case coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Targeted unit tests surface subtle bugs.&lt;/strong&gt; Without the summarizer tests, I might never have noticed async exports disappearing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type alignment matters.&lt;/strong&gt; Even small dependencies like &lt;code&gt;@types/node&lt;/code&gt; can block installation; upgrading them early avoids wasted time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration-style tests add confidence fast.&lt;/strong&gt; The Packager suite spins up temporary workspaces, letting me verify real workflows without touching the actual filesystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, this lab reinforced that investing in a clean testing setup unlocks safer refactoring and faster iteration. The &lt;a href="https://github.com/Abdulgafar4/repo-context-packager" rel="noopener noreferrer"&gt;Repository Context Packager&lt;/a&gt; now has a reliable safety net, and I’m more confident shipping improvements in the future.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>My Hacktoberfest 2025 Journey</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 01 Nov 2025 03:30:34 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/my-hacktoberfest-2025-journey-55n</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/my-hacktoberfest-2025-journey-55n</guid>
      <description>&lt;p&gt;&lt;strong&gt;My Hacktoberfest 2025 Journey: Learning Through Open Source&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hacktoberfest 2025 was my first deep dive into open source contribution, and it taught me far more than I expected—not just about code, but about collaboration, communication, and understanding what projects actually need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Wins&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PhysicsHub Theme Overhaul&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My first major contribution focused on improving the light theme for PhysicsHub. The original design used overly bright colors that caused eye strain, so I softened the palette and improved contrast ratios across the board. I also simplified the theme toggle from a confusing three-mode cycle to a straightforward light/dark switch.&lt;/p&gt;

&lt;p&gt;Beyond the visual improvements, I refactored the entire theme system to eliminate hardcoded colors, making every component properly theme-aware. The simulation pages, chapter cards, and code blocks now seamlessly adapt to user preferences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dark Mode Bug Fixes &amp;amp; Architecture Improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My second PhysicsHub contribution tackled critical visibility issues. The Stars components were nearly invisible in dark mode, and the homepage radial glow wasn't showing up at all due to z-index conflicts. After fixing these visual bugs, I refactored the project structure to use a centralized Layout component instead of duplicating headers and footers across every page.&lt;br&gt;
This architectural change might seem invisible to users, but it dramatically improved code maintainability and fixed footer positioning issues across the site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend Authentication System&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a Next.js project, I built a complete frontend-only authentication system with login and signup pages supporting both English and Japanese locales. Using localStorage for persistence and Zod for validation, I created a self-contained auth flow that works immediately while leaving room for future backend integration.&lt;/p&gt;

&lt;p&gt;The implementation includes reusable UI components, localized error messages, and session management that survives page refreshes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Learning Experience&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration URL History (Closed Without Merge)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every contribution makes it into the codebase, and that's okay. I built a URL history feature for an integration drawer that stored up to 10 previously used URLs per integration type in localStorage. It worked perfectly—but it wasn't what the project needed.&lt;/p&gt;

&lt;p&gt;The maintainer's feedback was direct: "It feels like too many changes for something very simple—I'd just like to see a list of what's already configured." I had interpreted "add history option" as building a comprehensive memory system when they simply wanted to display existing configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Learned&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Communication Matters More Than Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The closed PR taught me the most important lesson: always clarify requirements before diving into implementation. During Hacktoberfest, there's pressure to contribute quickly, but taking time to understand what maintainers actually want saves everyone time and effort.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Theme Systems Are Complex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Working on PhysicsHub's theme system showed me how deeply colors affect user experience. It's not just about aesthetics—proper contrast ratios impact accessibility, and consistent theming across components requires careful architectural planning.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Architecture Beats Duplication&lt;br&gt;
Refactoring duplicated headers and footers into a centralized Layout component was straightforward, but the impact was significant. Good architecture makes future changes easier, and that matters more than clever individual solutions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Frontend-First Can Work&lt;br&gt;
Building authentication without waiting for backend infrastructure proved that you can create functional features by working within constraints. localStorage isn't a database, but for the right use case, it enables rapid prototyping and immediate user value.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Moving Forward&lt;/strong&gt;&lt;br&gt;
Hacktoberfest reminded me that open source isn't just about writing code—it's about understanding problems, communicating solutions, and being willing to adjust when you miss the mark. The merged PRs feel great, but the closed one taught me more.&lt;/p&gt;

&lt;p&gt;Next year, I'll ask more questions upfront, contribute to projects where I genuinely use the software, and remember that simpler solutions often beat clever ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;4 Pull Requests submitted&lt;br&gt;
3 Merged successfully&lt;br&gt;
1 Closed (with valuable lessons learned)&lt;br&gt;
2 Projects contributed to&lt;br&gt;
Countless lines of code refactored&lt;/p&gt;

&lt;p&gt;Thanks to all the maintainers who reviewed my work, provided feedback, and helped me grow as a developer. See you in Hacktoberfest 2026! 🎃&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building a Frontend-Only Authentication System</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 01 Nov 2025 03:20:52 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/building-a-frontend-only-authentication-system-knp</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/building-a-frontend-only-authentication-system-knp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hactoberfest fourth week&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I implemented a complete authentication system for a Next.js project, adding login and signup functionality that works entirely on the frontend using localStorage for data persistence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Authentication Pages&lt;br&gt;
I created fully functional login and signup pages with routes for both English (/en/login, /en/signup) and Japanese (/ja/login, /ja/signup) locales. Each page includes form components with proper validation and error handling.&lt;/p&gt;

&lt;p&gt;Client-Side Authentication Logic&lt;br&gt;
The authentication system lives entirely in the browser. I built a utility module (auth-client.ts) that handles user session management, including getCurrentUser() and setCurrentUser() functions. User data persists in localStorage, and sessions automatically restore when users return to the site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Form Validation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using Zod, I created validation schemas for both login and signup forms. These schemas validate email formats, password requirements, and full name fields, with localized error messages that adapt to the user's language preference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI Enhancements&lt;/strong&gt;&lt;br&gt;
I added a reusable Input component to maintain consistency across forms and integrated logout buttons into both the main sidebar and mobile sidebar, giving users a clear way to end their sessions.&lt;/p&gt;

&lt;p&gt;Internationalization&lt;/p&gt;

&lt;p&gt;All auth-related text supports both English and Japanese, from form labels and placeholders to success messages and validation errors. This ensures a seamless experience regardless of language preference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Approach&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rather than waiting for backend infrastructure, I implemented a self-contained frontend authentication system. This approach allows the UI to be fully functional immediately while leaving room for backend integration later (I even kept the server actions structure in place for future use).&lt;/p&gt;

&lt;p&gt;The validation layer ensures data integrity before it ever touches localStorage, and the session management handles edge cases like page refreshes and navigation between routes.&lt;/p&gt;

&lt;p&gt;Hacktoberfest 2025 Contribution&lt;br&gt;
Issue &lt;a href="https://github.com/TemaDeveloper/library_proj/issues/13" rel="noopener noreferrer"&gt;#13&lt;/a&gt; | Pull Request &lt;a href="https://github.com/TemaDeveloper/library_proj/pull/20" rel="noopener noreferrer"&gt;#20&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Adding URL History to Integration Creation</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 01 Nov 2025 03:13:50 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/adding-url-history-to-integration-creation-92i</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/adding-url-history-to-integration-creation-92i</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hactoberfest third week&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I implemented a URL history feature for PhysicsHub's integration drawer, making it easier to reuse previously entered URLs when creating integrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you open the integration creation drawer now, you'll see a dropdown showing your previously entered URLs. This autocomplete feature remembers up to 10 URLs per integration type (Grafana, Kibana, Datadog, etc.) and stores them in localStorage.&lt;/p&gt;

&lt;p&gt;I created a new utility file (integrationUrlHistory.ts) to handle the URL history management and modified the Integrations page to load, display, and save URLs as users work with integrations. I also fixed some type-related errors that were lingering in the codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why It Didn't Work Out&lt;/strong&gt;&lt;br&gt;
The PR was closed without merging, and honestly, the feedback made sense. The maintainer pointed out that the implementation felt overcomplicated for what should be a simple feature—they just wanted to see a list of already configured integrations, not a full history system with localStorage management.&lt;/p&gt;

&lt;p&gt;Sometimes you build something thinking you're solving the problem elegantly, only to realize you've added unnecessary complexity. The feature worked, but it wasn't what the project actually needed. It's a good reminder to clarify requirements before diving into implementation, especially during Hacktoberfest when you're eager to contribute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;br&gt;
Always make sure you understand the actual problem before proposing a solution. "Add history option" could mean many things, and I interpreted it as building a comprehensive URL memory system when a simpler approach would have sufficed.&lt;/p&gt;

&lt;p&gt;Hacktoberfest 2025 Contribution&lt;br&gt;
Issue &lt;a href="https://github.com/OpsiMate/OpsiMate/issues/466" rel="noopener noreferrer"&gt;#466&lt;/a&gt; | Pull Request &lt;a href="https://github.com/OpsiMate/OpsiMate/pull/482" rel="noopener noreferrer"&gt;#467&lt;/a&gt; (Closed without merge)&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Fixing Dark Mode Issues</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 01 Nov 2025 03:09:09 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/fixing-dark-mode-issues-7cg</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/fixing-dark-mode-issues-7cg</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hactoberfest sencond week&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the second week, I worked on the same issue due to a miscommunication. I tackled critical visual bugs and implemented architectural improvements to PhysicsHub that improved the user experience, especially in dark mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Fixed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dark Mode Visibility Issues&lt;br&gt;
The Stars components scattered across various pages were practically invisible in dark mode. I updated them to use a brighter color (#AEE3FF) that maintains proper visibility in both light and dark themes. No more squinting to see those decorative stars!&lt;br&gt;
The homepage had another issue—the radial glow effect wasn't showing up in dark mode at all. After digging into the z-index layering and transparency settings, I resolved the conflicts that were hiding this visual element.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Architecture Overhaul&lt;/strong&gt;&lt;br&gt;
The project was repeating Header and Footer components on every single page, which isn't just inefficient—it makes maintenance a nightmare. I refactored the entire structure to use a centralized Layout component. Now the header and footer live in one place, wrapping all page content automatically.&lt;/p&gt;

&lt;p&gt;This also fixed footer positioning issues. Using proper flexbox layout, the footer now consistently stays at the bottom of the page regardless of content height.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Matters&lt;/strong&gt;&lt;br&gt;
Dark mode shouldn't feel like a half-finished feature. These visibility fixes ensure users get a consistent, polished experience whether they prefer light or dark themes.&lt;/p&gt;

&lt;p&gt;The architectural changes might seem invisible to users, but they make the codebase significantly cleaner and easier to maintain. Future contributors won't have to update headers and footers in multiple places, and the layout behavior is now predictable across all pages.&lt;/p&gt;

&lt;p&gt;Hacktoberfest 2025 Contribution&lt;br&gt;
Issue &lt;a href="https://github.com/physicshub/physicshub.github.io/issues/15" rel="noopener noreferrer"&gt;#15&lt;/a&gt; | Pull Request &lt;a href="https://github.com/physicshub/physicshub.github.io/pull/70" rel="noopener noreferrer"&gt;#70&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Improved Theme System</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 01 Nov 2025 03:03:41 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/improved-theme-system-36h6</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/improved-theme-system-36h6</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hactoberfest first week&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the first week of Hactoberfest. I refined the light theme on PhysicsHub to create a more comfortable, accessible, and consistent experience across the platform&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Changed&lt;/strong&gt;&lt;br&gt;
The light theme got a complete refresh. I replaced the overly bright backgrounds with softer, easier-on-the-eyes colors. Those harsh whites and near-whites (#e8eefb, #f6f7fb) are now gentler shades (#d1d9e8, #dde6f0) that reduce eye strain during extended use.&lt;/p&gt;

&lt;p&gt;I also simplified how theme switching works. Instead of cycling through three modes (dark → light → system), users now get a straightforward light/dark toggle. The preference persists across sessions, so the app remembers what you like.&lt;/p&gt;

&lt;p&gt;Under the hood, I fixed theme handling across the entire application. Simulation pages, chapter cards, code blocks, and other components now properly adapt to the chosen theme instead of using hardcoded colors. I also improved text contrast, making content more readable in light mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why It Matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The original light theme was too aggressive. Extended reading sessions meant squinting at bright backgrounds, which isn't ideal for anyone spending serious time with the content.&lt;/p&gt;

&lt;p&gt;These changes improve accessibility through better contrast ratios, create a more consistent experience across all pages, and make the codebase more maintainable by eliminating hardcoded color values. Plus, the simpler toggle makes switching themes feel natural rather than confusing.&lt;/p&gt;

&lt;p&gt;Hacktoberfest 2025 Contribution&lt;br&gt;
Issue &lt;a href="https://github.com/physicshub/physicshub.github.io/issues/15" rel="noopener noreferrer"&gt;#15&lt;/a&gt; | Pull Request &lt;a href="https://github.com/physicshub/physicshub.github.io/pull/46" rel="noopener noreferrer"&gt;#46&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Refactoring Journey: Improving Code Quality</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 11 Oct 2025 03:01:15 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/refactoring-journey-improving-code-quality-1bd8</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/refactoring-journey-improving-code-quality-1bd8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This week, I embarked on a comprehensive refactoring journey for my &lt;a href="https://github.com/Abdulgafar4/repo-context-packager" rel="noopener noreferrer"&gt;Repository Context Packager&lt;/a&gt; project. The goal wasn't to add new features or fix bugs, but rather to improve the code's structure, readability, maintainability, and squashing all my &lt;a href="https://github.com/Abdulgafar4/repo-context-packager/commit/d4e4a130879d958328f668328bc4e53651d0617c" rel="noopener noreferrer"&gt;commits&lt;/a&gt; to just one, paying down technical debt that had accumulated during rapid development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Focused On
&lt;/h2&gt;

&lt;p&gt;My refactoring efforts centered on six key areas, all guided by software engineering principles like &lt;strong&gt;DRY (Don't Repeat Yourself)&lt;/strong&gt;, &lt;strong&gt;Single Responsibility Principle (SRP)&lt;/strong&gt;, and &lt;strong&gt;SOLID&lt;/strong&gt; principles:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Reducing Code Duplication&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I found the same token calculation formula (&lt;code&gt;Math.round(content.length / 4)&lt;/code&gt;) repeated in two different places. This is a classic DRY violation—if the formula needed updating, I'd have to remember to change it in multiple locations.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Improving Function Modularity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The command-line option parsing logic was something else, lines of repetitive if-statements, all doing basically the same thing with slight variations. I changed that as well, thanks to Cursor for this.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Breaking Down Large Functions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The main action callback function was a monster at 110 lines, handling validation, parsing, execution, and output all in one place. This violated the Single Responsibility Principle spectacularly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Fixed Each Issue
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Refactoring #1: Extract Default Ignore Patterns
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;collectFiles&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultIgnore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.git/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.log&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_IGNORE_PATTERNS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.git/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.log&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;collectFiles&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; This made the ignore patterns easy to find, document, and modify without touching function logic.&lt;/p&gt;




&lt;h3&gt;
  
  
  Refactoring #2: Extract Token Calculation Function
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileTokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileTokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Single source of truth for token calculation. If the formula changes, update it once.&lt;/p&gt;




&lt;h3&gt;
  
  
  Refactoring #3: Extract Option Parsing Logic
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packagerOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;packagerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;packagerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exclude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseCommandLineOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;PackagerOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packagerOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PackagerOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;packagerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;packagerOptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packagerOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseCommandLineOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; The action callback became readable. Option parsing is now testable in isolation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Refactoring #4: Split Large Action Function
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 110 lines of:&lt;/span&gt;
  &lt;span class="c1"&gt;// - input validation&lt;/span&gt;
  &lt;span class="c1"&gt;// - option parsing&lt;/span&gt;
  &lt;span class="c1"&gt;// - output validation&lt;/span&gt;
  &lt;span class="c1"&gt;// - execution&lt;/span&gt;
  &lt;span class="c1"&gt;// - result display&lt;/span&gt;
  &lt;span class="c1"&gt;// - error handling&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateInputPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateOutputPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;executePackaging&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;displayResults&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;validateInputPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packagerOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseCommandLineOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;validateOutputPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executePackaging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;packagerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;displayResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`❌ Error: &lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Action callback reduced from 110 lines to 24 lines&lt;/li&gt;
&lt;li&gt;Each function has one clear purpose&lt;/li&gt;
&lt;li&gt;Much easier to test and debug&lt;/li&gt;
&lt;li&gt;Other parts of the codebase can reuse these functions&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Refactoring #5: Extract Statistics Collection Class
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Inside the 167-line analyzeRepository() method:&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentTokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;largestFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;totalCharacters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processedDirectories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// 50 lines of statistics tracking mixed with file processing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// New statistics.ts file&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RepositoryStatistics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;totalCharacters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;fileTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;largestFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;trackFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileInfo&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;wouldExceedTokenLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getTotalCharacters&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In packager.ts:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RepositoryStatistics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Statistics logic is now reusable and testable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;analyzeRepository()&lt;/code&gt; became much more readable&lt;/li&gt;
&lt;li&gt;Clear separation of concerns&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Refactoring #6: Create Error Handling Utilities
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Scattered throughout the code:&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error: File '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' not found\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Warning: File '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' no longer exists, skipping\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Skipping &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: file too large\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// New logger.ts file&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logWarning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Warning: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logFileError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ENOENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`File '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' not found`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EACCES&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Permission denied reading '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// ... smart error handling&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In packager.ts:&lt;/span&gt;
&lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Path '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;singlePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' does not exist`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;logWarning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`File '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' no longer exists, skipping`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;logFileError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent error message formatting&lt;/li&gt;
&lt;li&gt;Centralized logging makes it easy to add features like log levels or file logging&lt;/li&gt;
&lt;li&gt;Semantic function names make code self-documenting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Git Rebase Experience
&lt;/h2&gt;

&lt;p&gt;This is where things got interesting! The instructions called for an interactive rebase to squash all commits into one. Here's what happened:&lt;/p&gt;

&lt;h3&gt;
  
  
  Initial Attempt: Branch-Based Refactoring Workflow
&lt;/h3&gt;

&lt;p&gt;Instead of performing everything directly on the &lt;code&gt;main&lt;/code&gt; branch, I decided to use a safer and cleaner approach by creating a separate refactoring branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Update &lt;code&gt;main&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I started by ensuring my local &lt;code&gt;main&lt;/code&gt; branch was up to date:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git pull origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Create a Refactoring Branch
&lt;/h3&gt;

&lt;p&gt;Next, I created a new branch for all my refactoring work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; refactoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Make and Commit Changes
&lt;/h3&gt;

&lt;p&gt;I made several improvements across the codebase, committing each logical change separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Refactored helper functions for clarity"&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Simplified data handling logic"&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Improved maintainability and readability"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Squash Commits
&lt;/h3&gt;

&lt;p&gt;After testing and reviewing, I decided to squash the multiple commits into one for a cleaner commit history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--soft&lt;/span&gt; HEAD~6
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Refactoring codebase to improve maintainability and code quality"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--soft&lt;/code&gt; flag preserved all staged changes while removing the last 6 commits, allowing me to create one detailed and consolidated commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Merge Back to &lt;code&gt;main&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Once everything looked good, I merged the refactoring branch back into &lt;code&gt;main&lt;/code&gt; using a fast-forward merge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git merge &lt;span class="nt"&gt;--ff-only&lt;/span&gt; refactoring  &lt;span class="c"&gt;# &amp;lt;-- This ensures a clean, linear history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Push to GitHub
&lt;/h3&gt;

&lt;p&gt;Finally, I pushed my updated &lt;code&gt;main&lt;/code&gt; branch to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This worked perfectly!&lt;/strong&gt;&lt;br&gt;
This branch-based approach kept my &lt;code&gt;main&lt;/code&gt; branch stable, avoided interactive rebase editor issues, and resulted in a clear and professional commit history.&lt;/p&gt;
&lt;h2&gt;
  
  
  Did I Find Any Bugs?
&lt;/h2&gt;

&lt;p&gt;Surprisingly, &lt;strong&gt;no bugs were found during refactoring!&lt;/strong&gt; However, the refactoring process did reveal several &lt;strong&gt;code smells&lt;/strong&gt; and &lt;strong&gt;potential issues&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hidden Complexity&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testing Difficulty&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintenance Risks&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Did I Break Anything?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Test after each commit:&lt;/strong&gt; After every refactoring step, I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensured TypeScript compilation succeeded and no syntax errors were introduced.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Went Well:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incremental commits:&lt;/strong&gt; Making 6 small commits made the refactoring process manageable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear commit messages:&lt;/strong&gt; Each commit message explained exactly what changed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soft reset technique:&lt;/strong&gt; When interactive rebase failed, the soft reset approach was actually simpler and more intuitive&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The codebase is now significantly more maintainable, and I'm confident that future changes will be easier to implement. When we write automated tests later, having modular, focused functions will make that process much smoother.&lt;/p&gt;

&lt;p&gt;Most importantly, this exercise taught me that &lt;strong&gt;refactoring isn't just about cleaning code—it's about making your future self's life easier.&lt;/strong&gt;&lt;/p&gt;




</description>
      <category>architecture</category>
      <category>git</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Parallel Branch Development with Git</title>
      <dc:creator>Tajudeen Abdulgafar</dc:creator>
      <pubDate>Sat, 27 Sep 2025 01:32:43 +0000</pubDate>
      <link>https://dev.to/tajudeen_abdulgafar_e0363/parallel-branch-development-with-git-1lgm</link>
      <guid>https://dev.to/tajudeen_abdulgafar_e0363/parallel-branch-development-with-git-1lgm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This week, I dive deep into one of Git's most powerful features: parallel branch development. Still working on my &lt;a href="https://github.com/Abdulgafar4/repo-context-packager" rel="noopener noreferrer"&gt;Repository Context Packager&lt;/a&gt; project, I implemented two distinct features simultaneously using separate branches, then merged them back into main. This perfectly demonstrated how Git enables multiple development streams without interference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge: Two Features, One Timeline
&lt;/h2&gt;

&lt;p&gt;For this exercise, I chose to implement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verbose Mode Flag&lt;/strong&gt; (&lt;a href="https://github.com/Abdulgafar4/repo-context-packager/issues/12" rel="noopener noreferrer"&gt;Issue #12&lt;/a&gt;) - Add &lt;code&gt;--verbose&lt;/code&gt;/&lt;code&gt;-v&lt;/code&gt; flag for detailed progress output&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Statistics&lt;/strong&gt; (&lt;a href="https://github.com/Abdulgafar4/repo-context-packager/issues/13" rel="noopener noreferrer"&gt;Issue #13&lt;/a&gt;) - Expand summary with file type breakdowns and detailed metrics&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both features would modify the same core files (&lt;code&gt;src/cli.ts&lt;/code&gt; and &lt;code&gt;src/packager.ts&lt;/code&gt;), making this an ideal test case for Git's merge capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Parallel Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating Topic Branches
&lt;/h3&gt;

&lt;p&gt;Starting from a clean main branch, I created two separate topic branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; issue-12  &lt;span class="c"&gt;# Verbose mode feature&lt;/span&gt;
git checkout main
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; issue-13  &lt;span class="c"&gt;# Statistics enhancement&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach follows the best practice of creating focused, single-purpose branches that can be developed independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Feature 1: Verbose Mode (issue-12 branch)
&lt;/h3&gt;

&lt;p&gt;The verbose mode feature is required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding a new CLI option (&lt;code&gt;--verbose&lt;/code&gt;/&lt;code&gt;-v&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Implementing detailed progress logging to stderr&lt;/li&gt;
&lt;li&gt;Ensuring output doesn't interfere with main functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Processing primary path: .
Processing path: .
Scanning directory: .
Found 8 files in directory: .
Processing 8 files...
Reading file: src/cli.ts
Reading file: src/packager.ts
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Feature 2: Enhanced Statistics (issue-13 branch)
&lt;/h3&gt;

&lt;p&gt;The statistics enhancement involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extending the RepoInfo interface with new fields&lt;/li&gt;
&lt;li&gt;Collecting additional metrics during file processing&lt;/li&gt;
&lt;li&gt;Generating comprehensive summary output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Summary
- Total files: 10
- Total lines: 2254
- File types: .ts (6), .json (2), .md (2)
- Largest file: test-stats.md (575 lines)
- Average file size: 225 lines
- Total characters: 73,314
- Directories processed: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Merge: Fast-Forward vs. Three-Way
&lt;/h2&gt;

&lt;h3&gt;
  
  
  First Merge: Fast-Forward Success
&lt;/h3&gt;

&lt;p&gt;Merging the first feature (issue-12) back to main was seamless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git merge issue-12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Fast-forward merge! Since main hadn't changed since the branch was created, Git simply moved the main pointer forward to include the new commits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second Merge: Three-Way Recursive
&lt;/h3&gt;

&lt;p&gt;The second merge (issue-13) was more interesting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git merge issue-13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Three-way recursive merge! Git automatically created a merge commit because main had diverged from the original branch point.&lt;/p&gt;

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

&lt;p&gt;This parallel development exercise perfectly demonstrated Git's strength in managing concurrent development streams. The ability to work on multiple features simultaneously, then merge them seamlessly, is what makes Git an indispensable tool for software development.&lt;/p&gt;

&lt;p&gt;The workflow taught me that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolation enables innovation&lt;/strong&gt; - Separate branches let you experiment fearlessly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git handles complexity&lt;/strong&gt; - Automatic merging works better than expected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Planning prevents problems&lt;/strong&gt; - Thoughtful feature design reduces merge conflicts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing is crucial&lt;/strong&gt; - Validating merged functionality ensures quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Working with parallel branches isn't just a technical exercise—it's a fundamental skill that enables teams to work efficiently and deliver features faster. This hands-on experience has given me the confidence to tackle more complex branching scenarios in future projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final commit hashes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verbose mode: &lt;a href="https://github.com/Abdulgafar4/repo-context-packager/commit/e83e05f" rel="noopener noreferrer"&gt;e83e05f&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Enhanced statistics: &lt;a href="https://github.com/Abdulgafar4/repo-context-packager/commit/2852691" rel="noopener noreferrer"&gt;2852691&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The journey from parallel development to successful integration showcases Git's elegance in managing the complexity of modern software development. Every developer should master these workflows—they're not just tools, they're superpowers.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
