<?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>Forem: Cleo Buenaventura</title>
    <description>The latest articles on Forem by Cleo Buenaventura (@cleobnvntra).</description>
    <link>https://forem.com/cleobnvntra</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%2F2022740%2F560675a7-01cc-4543-a167-3ed16e9f329a.jpeg</url>
      <title>Forem: Cleo Buenaventura</title>
      <link>https://forem.com/cleobnvntra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/cleobnvntra"/>
    <language>en</language>
    <item>
      <title>A Final Challenge: Release</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Mon, 09 Dec 2024 22:38:06 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/a-final-challenge-release-2a50</link>
      <guid>https://forem.com/cleobnvntra/a-final-challenge-release-2a50</guid>
      <description>&lt;p&gt;The final week is here, which brings my issue to a conclusion. I think I did a pretty good job with achieving the goals I aimed for in the beginning of this challenge. This task focused on improving how &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;Onlook&lt;/a&gt; detects and handles Tailwind class names, particularly in cases involving dynamic expressions or template literals. The goal was to provide better error detection, ensure static classes are correctly extracted, and allow users to navigate directly to the relevant code sections in their editor. Along the way, I tackled challenges, refined my technical skills, and interacted with the &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;Onlook&lt;/a&gt; maintainer to ensure my contributions aligned with the project's goals.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/onlook-dev" rel="noopener noreferrer"&gt;
        onlook-dev
      &lt;/a&gt; / &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;
        onlook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The open source, local-first Figma for React. Design directly in your live React app and publish your changes to code.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://youtu.be/RSX_3EaO5eU" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Figma for your React App" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F377240008-c4a0db58-ecf2-4461-b6be-ce84749a3922.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzM3ODQzNjQsIm5iZiI6MTczMzc4NDA2NCwicGF0aCI6Ii8xNDEwNDA3NS8zNzcyNDAwMDgtYzRhMGRiNTgtZWNmMi00NDYxLWI2YmUtY2U4NDc0OWEzOTIyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA5VDIyNDEwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWM3Y2RmZmY5N2I1MmY3ZDdlN2IyNmJhOTQ3MjMyZWI5NjQyODJkNzQ4Njc0OTFjNDI2Y2UxZmNiYzRkOGVhYmMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.wLbVaoOkhbQHu8hISzHBHvOqhQEseMhF7EmD_EIWTBA"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Onlook&lt;/h3&gt;
&lt;/div&gt;
  &lt;p&gt;
    The first browser-powered visual editor
    &lt;br&gt;
    &lt;a href="https://github.com/onlook-dev/onlook/wiki" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the docs »&lt;/strong&gt;&lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;a href="https://youtu.be/RSX_3EaO5eU?feature=shared" rel="nofollow noopener noreferrer"&gt;View Demo&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=bug&amp;amp;template=bug-report---.md" rel="noopener noreferrer"&gt;Report Bug&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=enhancement&amp;amp;template=feature-request---.md" rel="noopener noreferrer"&gt;Request Feature&lt;/a&gt;
  &lt;/p&gt;
  


&lt;p&gt;&lt;a href="https://discord.gg/hERDfFZCsH" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eb7a9586d232b66e5c1b00c8c8a5b43d9512a0079637291f3f6f3811622e57fa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d446973636f72642d626c61636b3f6c6f676f3d646973636f726426636f6c6f72423d353535" alt="Discord"&gt;&lt;/a&gt;
&lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/57a916e4c2864d169353415c7619e46866f3a8231ee3834add5a6109ff5eeeef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4c696e6b6564496e2d626c61636b2e7376673f6c6f676f3d6c696e6b6564696e26636f6c6f72423d353535" alt="LinkedIn"&gt;&lt;/a&gt;
&lt;a href="https://x.com/onlookdev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e6529281499872a5363998eb49b4e9f16f76e30ff4e080135da4d6867259aab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d547769747465722d626c61636b3f6c6f676f3d7826636f6c6f72423d353535" alt="Twitter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;


  Table of Contents
  &lt;ol&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#roadmap" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contact" rel="noopener noreferrer"&gt;Contact&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#acknowledgments" rel="noopener noreferrer"&gt;Acknowledgments&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;The open-source visual editor for your React Apps&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Seamlessly integrate with any website or web app running on React + TailwindCSS, and make live edits directly in the browser DOM. Customize your design, control your codebase, and push changes your changes without compromise.&lt;/p&gt;

  
    
    

    &lt;span class="m-1"&gt;Onlook.Studio.Component.Demo.for.GitHub.mp4&lt;/span&gt;
    
  

  

  


&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzM3ODQzNjQsIm5iZiI6MTczMzc4NDA2NCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA5VDIyNDEwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTM5NjM3YWYwYmFjMjk1YTg5YjY1YTA2NTM2YmE0NjY3NWVkMGExNjYzN2MyNGU0OWRlYzIzYzMwMjIxOWU3YzcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.75wHV8jGYDA2xd0t7Ch1RmX9F5kuwv6pO8lsaz9fBgM"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzM3ODQzNjQsIm5iZiI6MTczMzc4NDA2NCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA5VDIyNDEwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTM5NjM3YWYwYmFjMjk1YTg5YjY1YTA2NTM2YmE0NjY3NWVkMGExNjYzN2MyNGU0OWRlYzIzYzMwMjIxOWU3YzcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.75wHV8jGYDA2xd0t7Ch1RmX9F5kuwv6pO8lsaz9fBgM" alt="Export-1724891449817"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Built With&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ecf64c6d80398d3ccc24b7b519fc4a12338b1d04a920469c82b52bb6c019fad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f72656163742d2532333230323332612e7376673f6c6f676f3d7265616374266c6f676f436f6c6f723d253233363144414642" alt="React"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.electronjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bc7dd648f0612624a32043879e92ed614f6c68c0c59f935a11066071f9c235/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f456c656374726f6e2d3139313937303f6c6f676f3d456c656374726f6e266c6f676f436f6c6f723d7768697465" alt="Electron"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b435bd99f814e0329b35cd70c9140c2bbaf00df96ac5bcdc91c9c6fbd1766b23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7461696c77696e646373732d2532333338423241432e7376673f6c6f676f3d7461696c77696e642d637373266c6f676f436f6c6f723d7768697465" alt="Tailwind"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/161124b7f44a3572ef26947bbf0184e0b34be3c45b30de132034838cdeedf4b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f766974652d2532333634364346462e7376673f6c6f676f3d76697465266c6f676f436f6c6f723d7768697465" alt="Vite"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stay up-to-date&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Onlook officially launched our first version of Onlook on July 08, 2024 and we've shipped a ton since then. Watch releases of this repository to be notified of future updates, and you can follow along with us on &lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://onlook.substack.com/" rel="nofollow noopener noreferrer"&gt;Substack&lt;/a&gt; where we write a weekly newsletter.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzM3ODQzNjQsIm5iZiI6MTczMzc4NDA2NCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA5VDIyNDEwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTAyYzc0ZjhmYWQ2NDc2MGQxODg4NDgwNDdkY2M0OTMzZjEwYjRlNWZmYWFiODRiNDZhZWRkYWE2ODM5MDdjMDgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.VeTmQh0a47ymgEMsBoOUnVIwfSWxnqN61irXJQWLUGg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzM3ODQzNjQsIm5iZiI6MTczMzc4NDA2NCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA5VDIyNDEwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTAyYzc0ZjhmYWQ2NDc2MGQxODg4NDgwNDdkY2M0OTMzZjEwYjRlNWZmYWFiODRiNDZhZWRkYWE2ODM5MDdjMDgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.VeTmQh0a47ymgEMsBoOUnVIwfSWxnqN61irXJQWLUGg" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://onlook.dev/" rel="nofollow noopener noreferrer"&gt;onlook.dev&lt;/a&gt; to download the app.&lt;/li&gt;
&lt;li&gt;Run locally following &lt;a href="https://github.com/onlook-dev/onlook/wiki/Building-from-source" rel="noopener noreferrer"&gt;this guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Usage&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Onlook will run on any React project, bring your own React project…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Achieving My Goals
&lt;/h2&gt;

&lt;p&gt;The primary goal was to improve how &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;Onlook&lt;/a&gt; detects and handles Tailwind class names within React components, particularly when dynamic expressions or template literals are used. I believe I achieved this effectively through:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Detection for Dynamic Classes&lt;/strong&gt;: Implemented logic to detect and return errors when dynamic expressions are present in class names. This ensures users are informed and can take appropriate action.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Static Class Extraction&lt;/strong&gt;: Ensured that static classes wrapped in &lt;code&gt;TemplateLiteral&lt;/code&gt; constructs are parsed and returned when no dynamic variables are present.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source Navigation&lt;/strong&gt;: Added a button in the UI that lets users navigate directly to the relevant code when dynamic variables are detected.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this task, the feature was functional, user-friendly, and aligned with &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;Onlook's&lt;/a&gt; architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Methods
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pull Request&lt;/strong&gt;: &lt;a href="https://github.com/onlook-dev/onlook/pull/849" rel="noopener noreferrer"&gt;https://github.com/onlook-dev/onlook/pull/849&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Class Parsing Logic&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The main function at the core of this feature is getNodeClasses, which is responsible for traversing a JSX element's AST (Abstract Syntax Tree) and extracting the className attribute. The function handles multiple scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missing &lt;code&gt;className&lt;/code&gt; Attribute&lt;/strong&gt;: If no &lt;code&gt;className&lt;/code&gt; attribute exists in the JSX element, the function immediately returns an error, allowing the system to handle this case gracefully.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Static Classes&lt;/strong&gt;: If the &lt;code&gt;className&lt;/code&gt; is a simple string or part of a &lt;code&gt;TemplateLiteral&lt;/code&gt; without any dynamic variables, the function extracts the classes and returns them as a list. For &lt;code&gt;TemplateLiteral&lt;/code&gt;, the function parses its &lt;code&gt;quasis&lt;/code&gt; (static portions) to ensure all classes are properly extracted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dynamic Classes&lt;/strong&gt;: If a &lt;code&gt;TemplateLiteral&lt;/code&gt; contains dynamic expressions (e.g., &lt;code&gt;${variable}&lt;/code&gt;), the function detects this and returns an error with a specific reason. This ensures users are notified of unsupported dynamic constructs in &lt;code&gt;className&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the relevant portion of the function that handles &lt;code&gt;TemplateLiteral&lt;/code&gt; cases which I was responsible for:&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isJSXExpressionContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classNameAttr&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isTemplateLiteral&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classNameAttr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;templateLiteral&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;classNameAttr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expression&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;templateLiteral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expressions&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;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dynamic classes detected. Dynamic variables in the className prevent extraction of Tailwind classes.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quasis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templateLiteral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quasis&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;quasi&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;quasi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raw&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="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;quasis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&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;This logic ensures the function is robust enough to handle both valid and invalid class declarations while giving clear feedback for edge cases. This modular design not only simplifies testing but also allows for easy extensions if new requirements arise.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;UI Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To integrate this functionality into the UI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I updated the &lt;code&gt;TailwindInput&lt;/code&gt; component where the &lt;code&gt;textarea&lt;/code&gt; is implemented to handle and display warnings when dynamic classes were detected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Added a button labeled "Go to source" that appears alongside the warning. Clicking this button navigates users to the exact location in their code where the dynamic class is defined.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;One of the most valuable lessons I gained from this experience was the importance of understanding code deeply and learning how to dig through layers of files in a codebase. Open-source projects can be intricate, with logic spread across multiple files and modules. Successfully implementing this feature required me to navigate the project's structure, understand its existing logic, and integrate my changes seamlessly. It was a constant process of reading, analyzing, and piecing together different parts of the system.&lt;/p&gt;

&lt;p&gt;A key breakthrough for me was discovering the capabilities of &lt;code&gt;@babel/types&lt;/code&gt;. Specifically, the &lt;code&gt;isTemplateLiteral&lt;/code&gt; method allowed me to identify template literals within the JSX AST (Abstract Syntax Tree). This discovery greatly simplified my logic for handling className attributes. Without understanding how to leverage this utility, implementing a robust solution would have been significantly more challenging.&lt;/p&gt;

&lt;p&gt;Another critical step was learning how to extract static classes from a &lt;code&gt;TemplateLiteral&lt;/code&gt;. Using the &lt;code&gt;quasis&lt;/code&gt; property of the &lt;code&gt;TemplateLiteral&lt;/code&gt; node, I was able to parse the static portions of the string and filter out dynamic variables. This approach ensured that I could reliably return static classes while gracefully handling dynamic constructs.&lt;/p&gt;

&lt;p&gt;More about &lt;a href="https://babeljs.io/docs/babel-types" rel="noopener noreferrer"&gt;Babel's AST documentation&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;This task was a rewarding experience. I successfully improved &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;Onlook's&lt;/a&gt; handling of dynamic Tailwind classes, providing users with better error detection and navigation tools. Along the way, I honed my skills in TypeScript and JSX parsing, while contributing meaningful enhancements to the project.&lt;/p&gt;

&lt;p&gt;I’m proud of the work I’ve done and look forward to further contributions to &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;Onlook&lt;/a&gt; and other open-source projects. This experience reaffirms my belief in the power of community-driven development to produce high-quality, user-friendly software.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>A Final Challenge: The Progress</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Wed, 04 Dec 2024 02:13:09 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/a-final-challenge-the-progress-4dn7</link>
      <guid>https://forem.com/cleobnvntra/a-final-challenge-the-progress-4dn7</guid>
      <description>&lt;p&gt;It's been a week since I started working on this &lt;a href="https://github.com/onlook-dev/onlook/issues/799" rel="noopener noreferrer"&gt;issue&lt;/a&gt; in the &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;onlook&lt;/a&gt; repo.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/onlook-dev" rel="noopener noreferrer"&gt;
        onlook-dev
      &lt;/a&gt; / &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;
        onlook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The open source, local-first Figma for React. Design directly in your live React app and publish your changes to code.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://youtu.be/RSX_3EaO5eU" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Figma for your React App" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F377240008-c4a0db58-ecf2-4461-b6be-ce84749a3922.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzMyNzkxNzIsIm5iZiI6MTczMzI3ODg3MiwicGF0aCI6Ii8xNDEwNDA3NS8zNzcyNDAwMDgtYzRhMGRiNTgtZWNmMi00NDYxLWI2YmUtY2U4NDc0OWEzOTIyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA0VDAyMjExMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTEwZDg1NzViMDFhZmFkYzJmODE2MDFjYjBiODRlMWJiMmNmYjRkMzFmNWRmNWYyZDMzN2I3MWE4MmI0NjRhOTMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.jyuzz1W0OYln13srLdyb-YDGSjEOj59BbNIm5b3fCrE"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Onlook&lt;/h3&gt;
&lt;/div&gt;
  &lt;p&gt;
    The first browser-powered visual editor
    &lt;br&gt;
    &lt;a href="https://github.com/onlook-dev/onlook/wiki" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the docs »&lt;/strong&gt;&lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;a href="https://youtu.be/RSX_3EaO5eU?feature=shared" rel="nofollow noopener noreferrer"&gt;View Demo&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=bug&amp;amp;template=bug-report---.md" rel="noopener noreferrer"&gt;Report Bug&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=enhancement&amp;amp;template=feature-request---.md" rel="noopener noreferrer"&gt;Request Feature&lt;/a&gt;
  &lt;/p&gt;
  


&lt;p&gt;&lt;a href="https://discord.gg/hERDfFZCsH" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eb7a9586d232b66e5c1b00c8c8a5b43d9512a0079637291f3f6f3811622e57fa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d446973636f72642d626c61636b3f6c6f676f3d646973636f726426636f6c6f72423d353535" alt="Discord"&gt;&lt;/a&gt;
&lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/57a916e4c2864d169353415c7619e46866f3a8231ee3834add5a6109ff5eeeef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4c696e6b6564496e2d626c61636b2e7376673f6c6f676f3d6c696e6b6564696e26636f6c6f72423d353535" alt="LinkedIn"&gt;&lt;/a&gt;
&lt;a href="https://x.com/onlookdev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e6529281499872a5363998eb49b4e9f16f76e30ff4e080135da4d6867259aab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d547769747465722d626c61636b3f6c6f676f3d7826636f6c6f72423d353535" alt="Twitter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;


  Table of Contents
  &lt;ol&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#roadmap" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contact" rel="noopener noreferrer"&gt;Contact&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#acknowledgments" rel="noopener noreferrer"&gt;Acknowledgments&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;The open-source visual editor for your React Apps&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Seamlessly integrate with any website or web app running on React + TailwindCSS, and make live edits directly in the browser DOM. Customize your design, control your codebase, and push changes your changes without compromise.&lt;/p&gt;

  
    
    

    &lt;span class="m-1"&gt;Onlook.Studio.Component.Demo.for.GitHub.mp4&lt;/span&gt;
    
  

  

  


&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzMyNzkxNzIsIm5iZiI6MTczMzI3ODg3MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA0VDAyMjExMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI0Nzk2YmQzMzlmNjUxYmY3NzExM2MyMDYxNWNkNzVmNjA4NjkzZGRhZmY3MTkyNjA5YTIzNzAxZGQ0NTBhY2MmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.kTDIAGFoOlSnNJaQ85hwCR7VjvFYU-fNeXUsNJ6YQTc"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzMyNzkxNzIsIm5iZiI6MTczMzI3ODg3MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA0VDAyMjExMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI0Nzk2YmQzMzlmNjUxYmY3NzExM2MyMDYxNWNkNzVmNjA4NjkzZGRhZmY3MTkyNjA5YTIzNzAxZGQ0NTBhY2MmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.kTDIAGFoOlSnNJaQ85hwCR7VjvFYU-fNeXUsNJ6YQTc" alt="Export-1724891449817"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Built With&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ecf64c6d80398d3ccc24b7b519fc4a12338b1d04a920469c82b52bb6c019fad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f72656163742d2532333230323332612e7376673f6c6f676f3d7265616374266c6f676f436f6c6f723d253233363144414642" alt="React"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.electronjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bc7dd648f0612624a32043879e92ed614f6c68c0c59f935a11066071f9c235/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f456c656374726f6e2d3139313937303f6c6f676f3d456c656374726f6e266c6f676f436f6c6f723d7768697465" alt="Electron"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b435bd99f814e0329b35cd70c9140c2bbaf00df96ac5bcdc91c9c6fbd1766b23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7461696c77696e646373732d2532333338423241432e7376673f6c6f676f3d7461696c77696e642d637373266c6f676f436f6c6f723d7768697465" alt="Tailwind"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/161124b7f44a3572ef26947bbf0184e0b34be3c45b30de132034838cdeedf4b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f766974652d2532333634364346462e7376673f6c6f676f3d76697465266c6f676f436f6c6f723d7768697465" alt="Vite"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stay up-to-date&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Onlook officially launched our first version of Onlook on July 08, 2024 and we've shipped a ton since then. Watch releases of this repository to be notified of future updates, and you can follow along with us on &lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://onlook.substack.com/" rel="nofollow noopener noreferrer"&gt;Substack&lt;/a&gt; where we write a weekly newsletter.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzMyNzkxNzIsIm5iZiI6MTczMzI3ODg3MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA0VDAyMjExMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQxMmQ4NTFiZTRlNDIzZmZiY2E2NjYyNjZjNjE1ZTU3MjE3NTc1NjFmYWY2MzQ2NjM1OWU5YjA5ZTE0YzQxYjcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Mlx7LjYj0SUR2Yt7FVu7zz0DCVn5VLIZEm2bx_UbUqc"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzMyNzkxNzIsIm5iZiI6MTczMzI3ODg3MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMDQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjA0VDAyMjExMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQxMmQ4NTFiZTRlNDIzZmZiY2E2NjYyNjZjNjE1ZTU3MjE3NTc1NjFmYWY2MzQ2NjM1OWU5YjA5ZTE0YzQxYjcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Mlx7LjYj0SUR2Yt7FVu7zz0DCVn5VLIZEm2bx_UbUqc" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://onlook.dev/" rel="nofollow noopener noreferrer"&gt;onlook.dev&lt;/a&gt; to download the app.&lt;/li&gt;
&lt;li&gt;Run locally following &lt;a href="https://github.com/onlook-dev/onlook/wiki/Building-from-source" rel="noopener noreferrer"&gt;this guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Usage&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Onlook will run on any React project, bring your own React project…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  The Issue
&lt;/h2&gt;

&lt;p&gt;The main issue is that when a &lt;code&gt;className&lt;/code&gt; is using template literals, the &lt;code&gt;textarea&lt;/code&gt; that should show the Tailwind Classes used in the div shows nothing. The &lt;code&gt;textarea&lt;/code&gt; displays the Tailwind Classes used in the currently selected div in the application.&lt;/p&gt;

&lt;p&gt;In these examples, I selected a div that uses a static string, and then a div that uses template literals to show what it looks like:&lt;/p&gt;

&lt;h3&gt;
  
  
  Using static string
&lt;/h3&gt;

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

&lt;h3&gt;
  
  
  Using template literals
&lt;/h3&gt;

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

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

&lt;p&gt;As I have mentioned from my previous post, I proceeded with understanding the code and the logic behind the parsing of these classNames from the project file. One of the maintainers of the repo also mentioned the function and which file it can be located as a good place to start, which helped a lot.&lt;/p&gt;

&lt;h3&gt;
  
  
  getTemplateNodeClass
&lt;/h3&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;getTemplateNodeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templateNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateNode&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="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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;codeBlock&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;readCodeBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templateNode&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;ast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseJsxCodeBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;codeBlock&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;ast&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="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;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNodeClasses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&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;classes&lt;/span&gt; &lt;span class="o"&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;This is the main function that orchestrates the parsing process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calls &lt;code&gt;readCodeBlock&lt;/code&gt; to retrieve the relevant section of the JSX/HTML code for the selected &lt;code&gt;TemplateNode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Converts the retrieved code into an &lt;code&gt;AST&lt;/code&gt; using &lt;code&gt;parseJsxCodeBlock&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Passes the &lt;code&gt;AST&lt;/code&gt; to &lt;code&gt;getNodeClasses&lt;/code&gt; to extract the class names.&lt;/li&gt;
&lt;li&gt;Outputs an array of class names or an empty array if nothing is found.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  readCodeBlock
&lt;/h3&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;readCodeBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templateNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateNode&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="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="k"&gt;try&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;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templateNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&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;startTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templateNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTag&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;startRow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;line&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;startColumn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;column&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;endTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templateNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endTag&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;startTag&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;endRow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;endTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;line&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;endColumn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;endTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;column&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;fileContent&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;readFile&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileContent&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="se"&gt;\n&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;selectedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endRow&lt;/span&gt;&lt;span class="p"&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;line&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="na"&gt;index&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="na"&gt;array&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="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;index&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;array&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;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Only one line&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endColumn&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;index&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="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// First line of multiple&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startColumn&lt;/span&gt; &lt;span class="o"&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="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;index&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;array&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;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Last line&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endColumn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="c1"&gt;// Full lines in between&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;line&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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;selectedText&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="na"&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="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;Error reading range from file:&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="k"&gt;throw&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes an AST node and attempts to extract the &lt;code&gt;className&lt;/code&gt; attribute.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the &lt;code&gt;className&lt;/code&gt; is a plain string, it splits the string into individual classes.&lt;/li&gt;
&lt;li&gt;If the &lt;code&gt;className&lt;/code&gt; is wrapped in a JSX expression but is still a static string, it extracts the value similarly.&lt;/li&gt;
&lt;li&gt;For anything else, it currently returns an empty array, which leads to the issue.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  getNodeClasses
&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;getNodeClasses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JSXElement&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openingElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openingElement&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;classNameAttr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;openingElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;attr&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JSXAttribute&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isJSXAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;className&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;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;classNameAttr&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="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;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isStringLiteral&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classNameAttr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;classNameAttr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&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;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isJSXExpressionContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classNameAttr&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isStringLiteral&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classNameAttr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expression&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;classNameAttr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expression&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="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&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="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 function is responsible for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reading the source file where the selected &lt;code&gt;div&lt;/code&gt; resides.&lt;/li&gt;
&lt;li&gt;Extracts the specific range of code based on the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; positions of the &lt;code&gt;TemplateNode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Returns the extracted code block as a string.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Understanding these methods are crucial as this will be the foundation for this issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progress
&lt;/h2&gt;

&lt;p&gt;So within a week, I can say that I was able to make some progress with the issue. I now understand what I am working with, and where the issue stems from.&lt;/p&gt;

&lt;p&gt;Based on my plans from last week, it was actually more simpler than I thought. I mentioned that I will need to figure out how to determine whether a &lt;code&gt;className&lt;/code&gt; is using template literals or static strings. To my surprise, the code uses a method called &lt;code&gt;isStringLiteral&lt;/code&gt;, which is a function from the &lt;code&gt;@babel/types&lt;/code&gt; library. So I figured, searching through the methods, and I found that a method called &lt;code&gt;isTemplateLiteral&lt;/code&gt; exists. This method easily allows me to determine whether a className uses a template literal or not, and then build the logic from there.&lt;/p&gt;

&lt;p&gt;With that said, I have made my modifications with the code to achieve something like this:&lt;/p&gt;

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

&lt;p&gt;Currently, I made it so that when a div has a &lt;code&gt;className&lt;/code&gt; that uses template literals, a &lt;code&gt;readOnly&lt;/code&gt; warning is shown in the &lt;code&gt;textarea&lt;/code&gt; instead of the Tailwind Classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems Encountered
&lt;/h2&gt;

&lt;p&gt;There was only one problem I encountered so far, which is not really concerned with the code I was working on (which I initially thought it was).&lt;/p&gt;

&lt;p&gt;After working on the code, I realized that I have not pulled the latest main from the repo. So I have been working on an older version of the app. After pulling main and updating my branch, the feature I am working on suddenly stopped working.&lt;/p&gt;

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

&lt;p&gt;The &lt;code&gt;textarea&lt;/code&gt; suddenly stopped getting displayed. I had to reach out to the maintainers and had to confirm whether this was a new bug in the newer version or it was just an issue on my end.&lt;/p&gt;

&lt;p&gt;Thankfully, there was just a new feature implemented that requires running the project through the built-in terminal in the app rather than running the project in another IDE separately.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The next step
&lt;/h2&gt;

&lt;p&gt;So I have now reached out to the maintainers of the repo and showed what I have so far, and they have made a few suggestions.&lt;br&gt;
So for finalizing this issue, the important changes I will have to implement are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The warning should only appear when a user cannot edit the text. Meaning, this should only happen when dynamic variables are involved. This means, that other than determining whether a &lt;code&gt;className&lt;/code&gt; uses template literals or not, I should also make a logic whether that template literal contains a dynamic variable or not. If there are no dynamic variables, then it should still be able to display the Tailwind Classes as if it is a static string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A button should be displayed for the user along with the warning. This button when clicked, should bring the user to that specific &lt;code&gt;templateNode&lt;/code&gt;. Basically bringing the user to the specific &lt;code&gt;className&lt;/code&gt; in the source code the warning is referring to.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next week, will be the final update of this issue hopfully having it done and merged.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>A Final Challenge: The Planning Phase</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Wed, 27 Nov 2024 02:48:36 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/a-final-challenge-the-planning-phase-2p10</link>
      <guid>https://forem.com/cleobnvntra/a-final-challenge-the-planning-phase-2p10</guid>
      <description>&lt;p&gt;The end of the semester is drawing near, which also means the conclusion of the open source course. For the final assignment, I will be tackling an issue that will be outside of my comfort zone as a little push for myself to grow as a developer.&lt;/p&gt;

&lt;p&gt;I have the remaining weeks of the semester to work on an issue that is not too difficult that I wouldn't be able to succeed, but also not too easy that I won't really be learning anything.&lt;/p&gt;

&lt;p&gt;For this week, I will be choosing an issue and layout the plans on how I will be taking on this issue. For starters, I have decided to look for issues again from &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;Onlook&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/onlook-dev" rel="noopener noreferrer"&gt;
        onlook-dev
      &lt;/a&gt; / &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;
        onlook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The open source, local-first Figma for React. Design directly in your live React app and publish your changes to code.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://youtu.be/RSX_3EaO5eU" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Figma for your React App" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F377240008-c4a0db58-ecf2-4461-b6be-ce84749a3922.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzI2NzYxODgsIm5iZiI6MTczMjY3NTg4OCwicGF0aCI6Ii8xNDEwNDA3NS8zNzcyNDAwMDgtYzRhMGRiNTgtZWNmMi00NDYxLWI2YmUtY2U4NDc0OWEzOTIyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTI3VDAyNTEyOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWU2ZTE4NzFhYWVkM2Q2MmFkMDBhNDgxN2UzOTYyYzQ2MjgyZDZlZGMzMzBkOTFkMTE1M2E5YThmMjljNjNjMjAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.DWdIJIvXzYuhdCFV0muPMp_lSh7BRHqviBw0xTmeuio"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Onlook&lt;/h3&gt;
&lt;/div&gt;
  &lt;p&gt;
    The first browser-powered visual editor
    &lt;br&gt;
    &lt;a href="https://github.com/onlook-dev/onlook/wiki" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the docs »&lt;/strong&gt;&lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;a href="https://youtu.be/RSX_3EaO5eU?feature=shared" rel="nofollow noopener noreferrer"&gt;View Demo&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=bug&amp;amp;template=bug-report---.md" rel="noopener noreferrer"&gt;Report Bug&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=enhancement&amp;amp;template=feature-request---.md" rel="noopener noreferrer"&gt;Request Feature&lt;/a&gt;
  &lt;/p&gt;
  


&lt;p&gt;&lt;a href="https://discord.gg/hERDfFZCsH" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eb7a9586d232b66e5c1b00c8c8a5b43d9512a0079637291f3f6f3811622e57fa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d446973636f72642d626c61636b3f6c6f676f3d646973636f726426636f6c6f72423d353535" alt="Discord"&gt;&lt;/a&gt;
&lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/57a916e4c2864d169353415c7619e46866f3a8231ee3834add5a6109ff5eeeef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4c696e6b6564496e2d626c61636b2e7376673f6c6f676f3d6c696e6b6564696e26636f6c6f72423d353535" alt="LinkedIn"&gt;&lt;/a&gt;
&lt;a href="https://x.com/onlookdev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e6529281499872a5363998eb49b4e9f16f76e30ff4e080135da4d6867259aab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d547769747465722d626c61636b3f6c6f676f3d7826636f6c6f72423d353535" alt="Twitter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;


  Table of Contents
  &lt;ol&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#roadmap" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contact" rel="noopener noreferrer"&gt;Contact&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#acknowledgments" rel="noopener noreferrer"&gt;Acknowledgments&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;The open-source, local-first visual editor for your React Apps&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Seamlessly integrate with any website or webapp running on React + TailwindCSS, and make live edits directly in the browser DOM. Customize your design, control your codebase, and push changes your changes without compromise.&lt;/p&gt;

  
    
    

    &lt;span class="m-1"&gt;Onlook.Studio.Component.Demo.for.GitHub.mp4&lt;/span&gt;
    
  

  

  


&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzI2NzYxODgsIm5iZiI6MTczMjY3NTg4OCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTI3VDAyNTEyOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTFjMWFhODc3MGFiMjJkN2Y1NWJhZTBlMjJkMDE4MWMxZWJiMWQxYTdhMzQ0NTgyYzU3YmI5YzUxNDIxNWRlNTEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Q0PZF-N-6PkQtvromrH_aipMHjBrNAkCBsEpQNGHWNQ"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzI2NzYxODgsIm5iZiI6MTczMjY3NTg4OCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTI3VDAyNTEyOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTFjMWFhODc3MGFiMjJkN2Y1NWJhZTBlMjJkMDE4MWMxZWJiMWQxYTdhMzQ0NTgyYzU3YmI5YzUxNDIxNWRlNTEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Q0PZF-N-6PkQtvromrH_aipMHjBrNAkCBsEpQNGHWNQ" alt="Export-1724891449817"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Built With&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ecf64c6d80398d3ccc24b7b519fc4a12338b1d04a920469c82b52bb6c019fad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f72656163742d2532333230323332612e7376673f6c6f676f3d7265616374266c6f676f436f6c6f723d253233363144414642" alt="React"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.electronjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bc7dd648f0612624a32043879e92ed614f6c68c0c59f935a11066071f9c235/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f456c656374726f6e2d3139313937303f6c6f676f3d456c656374726f6e266c6f676f436f6c6f723d7768697465" alt="Electron"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b435bd99f814e0329b35cd70c9140c2bbaf00df96ac5bcdc91c9c6fbd1766b23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7461696c77696e646373732d2532333338423241432e7376673f6c6f676f3d7461696c77696e642d637373266c6f676f436f6c6f723d7768697465" alt="Tailwind"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/161124b7f44a3572ef26947bbf0184e0b34be3c45b30de132034838cdeedf4b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f766974652d2532333634364346462e7376673f6c6f676f3d76697465266c6f676f436f6c6f723d7768697465" alt="Vite"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stay up-to-date&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Onlook officially launched our first version of Onlook on July 08, 2024 and we've shipped a ton since then. Watch releases of this repository to be notified of future updates, and you can follow along with us on &lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://onlook.substack.com/" rel="nofollow noopener noreferrer"&gt;Substack&lt;/a&gt; where we write a weekly newsletter.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzI2NzYxODgsIm5iZiI6MTczMjY3NTg4OCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTI3VDAyNTEyOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTc0NGNkNDgxNDlhZTk1NGExMWUyMGU3ZjEyMTJjYWJjOGNiYjJjYmJiZGU2MTQwMDNiZjdjZWQyNDM2MmMyN2ImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.UQTT-qT_dhOq2dApGuk5tNeyQ3nq-NpVHEX3J5oPYHQ"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzI2NzYxODgsIm5iZiI6MTczMjY3NTg4OCwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTI3VDAyNTEyOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTc0NGNkNDgxNDlhZTk1NGExMWUyMGU3ZjEyMTJjYWJjOGNiYjJjYmJiZGU2MTQwMDNiZjdjZWQyNDM2MmMyN2ImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.UQTT-qT_dhOq2dApGuk5tNeyQ3nq-NpVHEX3J5oPYHQ" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Option 1: Download from website&lt;/h4&gt;

&lt;/div&gt;
&lt;p&gt;Visit &lt;a href="https://onlook.dev/" rel="nofollow noopener noreferrer"&gt;onlook.dev&lt;/a&gt; to download the pre-built app.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Optione 2: Run locally&lt;/h4&gt;

&lt;/div&gt;
&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;We require the &lt;a href="https://bun/" rel="nofollow noopener noreferrer"&gt;Bun.sh&lt;/a&gt; runtime. You can…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;As a quick recap, I contributed to this project previously during the Hacktoberfest. This is important as this is one of the main reasons why I decided to contribute to this project again. I really liked the concept of the project. It is something that would prove to be helpful to both developers AND aspiring developers.&lt;/p&gt;

&lt;p&gt;So with that being said, I dont think I would want to end the course any other way than getting an opportunity to improve and contributing to a project that interests me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues
&lt;/h2&gt;

&lt;p&gt;Here are a couple of issues that I've been looking at and planning to take on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue #1&lt;/strong&gt;: &lt;a href="https://github.com/onlook-dev/onlook/issues/479" rel="noopener noreferrer"&gt;https://github.com/onlook-dev/onlook/issues/479&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Issue #2&lt;/strong&gt;: &lt;a href="https://github.com/onlook-dev/onlook/issues/799" rel="noopener noreferrer"&gt;https://github.com/onlook-dev/onlook/issues/799&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After looking at the issues and doing some quick research, I am leaning more towards &lt;a href="https://github.com/onlook-dev/onlook/issues/799" rel="noopener noreferrer"&gt;&lt;code&gt;Issue #2&lt;/code&gt;&lt;/a&gt; as it seems more doable at my current level within the remaining time.&lt;/p&gt;

&lt;p&gt;I have been looking at Issue #1 since Hacktoberfest, and technically even tried to solve it without asking for the task just because I was curious, and it seemed more complicated than I thought. Then weeks later, Issue #2 appeared, and the issues have some similarity which is handling dynamic variables. The part that differentiates the difficulty between the two issues is that Issue #1 deals with how dynamic variables should be handled in the DOM, while Issue #2 is about detecting and providing meaningful feedback when dynamic variables are used in Tailwind class names, improving the developer experience.&lt;/p&gt;

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

&lt;p&gt;So far these are the first few steps I will be taking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Find the relevant code and files.&lt;/strong&gt;&lt;br&gt;
For a big project with an already existing huge code base, it is important that I figure out which files and code I will most likely be working on. I think that dealing with this first hand will save me time once I actually start putting in some work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Understanding the code and the flow.&lt;/strong&gt;&lt;br&gt;
This one should be a no brainer. But it is still worth mentioning because I may have contributed to the project twice during Hacktoberfest, the issues from then and now are two different things and are completely different areas of the app. So this would require some time again to understand this specific segment of the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Define the approach for detecting dynamic variables.&lt;/strong&gt;&lt;br&gt;
Once I have identified and understood the relevant code, the next step will be to figure out how to detect dynamic className values effectively. This will involve analyzing patterns in the className property, such as template literals, concatenated strings, or computed functions. I will then implement logic to handle these cases by displaying warnings or feedback in the UI and ensuring the changes integrate smoothly with the existing functionality.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Releasing GENEREADME</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Sun, 24 Nov 2024 07:53:04 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/releasing-genereadme-v100-4fi5</link>
      <guid>https://forem.com/cleobnvntra/releasing-genereadme-v100-4fi5</guid>
      <description>&lt;p&gt;For this week's lab, I am now to release &lt;a href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;GENEREADME&lt;/a&gt;. &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cleobnvntra" rel="noopener noreferrer"&gt;
        cleobnvntra
      &lt;/a&gt; / &lt;a href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;
        genereadme
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GENEREADME is a command-line tool that takes in a source code file and generates a README.md file that explains the code in the file by utilizing an LLM.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Contrubutions&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Contributions to &lt;code&gt;GENEREADME&lt;/code&gt; are welcome! Please checkout &lt;a href="https://github.com/cleobnvntra/genereadme./CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; for guidelines on setting up the environment, how to run and test the tool, and submitting changes.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;GENEREADME&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;GENEREADME&lt;/code&gt; is a command-line tool that takes in a file, processes it, and generates a README file with an explanation or documentation of the contents of the file. The tool utilizes OpenAI chat completion to analyze the file and generate content.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/965a9f6318044798c9d5c20cc994e91c6eb1b3fd37e88bd235969308f90480df/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f74703532716165666a64756131676769313565342e676966"&gt;&lt;img src="https://camo.githubusercontent.com/965a9f6318044798c9d5c20cc994e91c6eb1b3fd37e88bd235969308f90480df/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f74703532716165666a64756131676769313565342e676966" alt="genereadme demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Usage&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt; the tool by running the following command:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm i -g genereadme&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The tool currently supports &lt;a href="https://console.groq.com/docs/openai" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;Groq&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://openrouter.ai/docs/quick-start" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;OpenRouter&lt;/code&gt;&lt;/a&gt;, which uses &lt;code&gt;Groq&lt;/code&gt; by default. A valid API key for the appropriate provider must be provided.&lt;/p&gt;
&lt;p&gt;Provide a valid API key either by creating a .env file or through the -a or --api-key flag when using the command:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;API_KEY=API_KEY

or

genereadme &amp;lt;files&amp;gt; -a API_KEY
genereadme &amp;lt;files&amp;gt; --api-key API_KEY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run the tool with the existing sample files or start using your own:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  The Process
&lt;/h2&gt;

&lt;p&gt;Publishing the tool itself was no trouble at all however, there were some extra steps I had to take to ensure a proper release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Research
&lt;/h3&gt;

&lt;p&gt;Before I focused on the release process, I took some time to research best practices and steps for publishing a package to the npm registry. Here's what I learned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. How to publish a package to npm&lt;/strong&gt;&lt;br&gt;
To understand the basic process, I referred to the official &lt;a href="https://docs.npmjs.com/cli/v9/commands/npm-publish" rel="noopener noreferrer"&gt;npm documentation&lt;/a&gt;. This guide provided an overview of essential steps, including setting up a &lt;code&gt;package.json&lt;/code&gt;, running &lt;code&gt;npm publish&lt;/code&gt;, and managing versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Using Semantic Versioning&lt;/strong&gt;&lt;br&gt;
Versioning plays a crucial role in signaling changes to users. I looked at the principles of Semantic Versioning, which uses the &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt; format to describe breaking changes, new features, and bug fixes. This ensured my tool would have a meaningful version number for each release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Managing &lt;code&gt;.npmignore&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
I researched how to effectively use the &lt;code&gt;.npmignore&lt;/code&gt; file to ensure my npm package includes only the necessary files for end-users. By carefully creating this file, I was able to exclude development-specific files like configuration files, tests, and documentation that aren't required in the published package. This not only reduced the size of the package but also made it more professional by focusing solely on what the users actually need to run the tool. Properly managing &lt;code&gt;.npmignore&lt;/code&gt; is a critical step in preparing a polished release.&lt;/p&gt;
&lt;h3&gt;
  
  
  Release
&lt;/h3&gt;

&lt;p&gt;After doing my research, I double checked any requirements, any possible bugs, and any failing tests.&lt;br&gt;
After everything looked all good to me, I proceeded to publish the package by running:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Running this command will require the user to be logged in to their npm account by running the command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Now that I have publish v1.0.0 of &lt;code&gt;GENEREADME&lt;/code&gt;, it was time to ask some end-users to test if the package works.&lt;br&gt;
As expected, there were a couple of bugs that made it through. One which does not affect how the tool performs, and one that actually breaks it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Adjustment
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Version command bug
&lt;/h4&gt;

&lt;p&gt;The simple bug that was found is about using the command &lt;code&gt;genereadme -v&lt;/code&gt;. This command should print the tool's name and the current version. However, the way I coded this part is that I retrieve the project name and version from the &lt;code&gt;package.json&lt;/code&gt; in the current directory. This means that if an end-user runs this command, it will display the name and version of &lt;strong&gt;THEIR&lt;/strong&gt; project instead of mine. So this was a simple fix to just make sure that it will always retrieve it from the correct project.&lt;/p&gt;
&lt;h4&gt;
  
  
  Outputs directory bug
&lt;/h4&gt;

&lt;p&gt;Now this one is a bug that breaks the tool which technically worked in my local testing, but I forgot a simple test case.&lt;br&gt;
The folder structure of the project only had developers and contributors in mind, so having the &lt;code&gt;outputs&lt;/code&gt; folder in the project is expected, which I also pushed to the main repo containing a sample result of an output.&lt;/p&gt;

&lt;p&gt;Now, I had to keep in mind that it will be slightly different for the end-user.&lt;br&gt;
Previously, the code was written to just write to the &lt;code&gt;outputs/&lt;/code&gt; directory without checking for its existence, and to make one if it doesn't. This caused the manual testing of the published package fail since the end-user did not have a &lt;code&gt;outputs/&lt;/code&gt; directory, the tool will just fail instead of making one if it doesn't exist.&lt;/p&gt;

&lt;p&gt;After this discovery, I thought pretty simple, right?&lt;br&gt;
Until I tried pushing the changes thinking "Okay, that fixes it!" but to my surprise, my &lt;code&gt;CI&lt;/code&gt; failed!&lt;/p&gt;

&lt;p&gt;The culprit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./outputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./outputs&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;p&gt;So this is how I check and create the &lt;code&gt;outputs/&lt;/code&gt; directory. However, in my end-to-end testing, I was mocking the &lt;code&gt;fs.existsSync()&lt;/code&gt; to return a value of &lt;code&gt;false&lt;/code&gt; for this reason:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;readConfigFile&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;homeDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;homedir&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;configFilePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;homeDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./genereadme-config.toml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;))&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configFileContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;toml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFileContent&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error parsing the config file:&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="nx"&gt;message&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;span class="k"&gt;return&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 function checks for a &lt;code&gt;toml&lt;/code&gt; config file which uses &lt;code&gt;fs.existsSync()&lt;/code&gt;, and I did not want to use a &lt;code&gt;toml&lt;/code&gt; config file for my end-to-end testing, I mocked this method to return false, which is now conflicting with the bugfix I did.&lt;/p&gt;

&lt;p&gt;I am yet to master mocking and find out ways to possibly make different mock values for the same method for different conditions. So until I learn that procedure, I made the temporary fix to ensure that the &lt;code&gt;outputs/&lt;/code&gt; directory gets removed before every test case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputsPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./outputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputsPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rmdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputsPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GENEREADME v1.0.4
&lt;/h2&gt;

&lt;p&gt;And that concludes the important patches I made! &lt;a href="https://www.npmjs.com/package/genereadme" rel="noopener noreferrer"&gt;GENEREADME&lt;/a&gt; is now available for use!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>npm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Learning and Growing Through Open Source Contributions</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Wed, 20 Nov 2024 03:54:51 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/learning-and-growing-through-open-source-contributions-78j</link>
      <guid>https://forem.com/cleobnvntra/learning-and-growing-through-open-source-contributions-78j</guid>
      <description>&lt;p&gt;Contributing to open-source projects is always an opportunity to refine skills and face new challenges. This time, I worked on improving unit test coverage for two components ,LoadingSpinner and FileAttachmentButton, in the React project &lt;a href="https://github.com/tjtanjin/react-chatbotify" rel="noopener noreferrer"&gt;react-chatbotify&lt;/a&gt;. These contributions allowed me to explore more advanced testing techniques, particularly mocking, and ensured robust functionality and styling validation.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tjtanjin" rel="noopener noreferrer"&gt;
        tjtanjin
      &lt;/a&gt; / &lt;a href="https://github.com/tjtanjin/react-chatbotify" rel="noopener noreferrer"&gt;
        react-chatbotify
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A modern React library for creating flexible and extensible chatbots.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/tjtanjin/react-chatbotify/main/assets/logo.png"&gt;&lt;img width="200px" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ftjtanjin%2Freact-chatbotify%2Fmain%2Fassets%2Flogo.png"&gt;&lt;/a&gt;
  &lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;React ChatBotify&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;
  &lt;a href="https://github.com/tjtanjin/react-chatbotify/actions/workflows/ci-cd-pipeline.yml" rel="noopener noreferrer"&gt; &lt;img src="https://github.com/tjtanjin/react-chatbotify/actions/workflows/ci-cd-pipeline.yml/badge.svg"&gt; &lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/react-chatbotify" rel="nofollow noopener noreferrer"&gt; &lt;img src="https://camo.githubusercontent.com/fb3773ab75de92c24d466b5a023c1640fc8d9256120d416e61b7e0cbb8ab2c56/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f72656163742d63686174626f746966793f6c6f676f3d73656d766572266c6162656c3d76657273696f6e26636f6c6f723d253233333163383534"&gt; &lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/react-chatbotify" rel="nofollow noopener noreferrer"&gt; &lt;img src="https://camo.githubusercontent.com/ad94a564be4bfae27036c0cb5df5b51100e42a535409bc25d2f9bceb48efdc1f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f72656163742d31362d2d31392d6f72616e67653f6c6f676f3d7265616374266c6162656c3d7265616374"&gt; &lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/react-chatbotify" rel="nofollow noopener noreferrer"&gt; &lt;img src="https://camo.githubusercontent.com/d7f78201d133ddb856c63cf8aa2b13e00e2adf2ff3e577e70ad87bd7d02ba2ab/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6431386d2f72656163742d63686174626f746966793f6c6f676f3d6e706d266c6162656c3d6e706d253230646f776e6c6f61647326636f6c6f723d253233323238316332"&gt; &lt;/a&gt;
  &lt;a href="https://discord.gg/6R4DK4G5Zh" rel="nofollow noopener noreferrer"&gt; &lt;img src="https://camo.githubusercontent.com/e74f291d41feda1fc3873634c0c932b1de96e5209a01a9efa09fadc4a6d69605/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f75726c3d68747470733a2f2f6d792d6170692e746a74616e6a696e2e636f6d2f61676772656761746f722f6170692f76312f6765742f7263625f646973636f72645f6d656d6265725f636f756e74266c6f676f3d646973636f7264266c6f676f436f6c6f723d666666666666"&gt; &lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of Contents&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#introduction" rel="noopener noreferrer"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#features" rel="noopener noreferrer"&gt;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#technologies" rel="noopener noreferrer"&gt;Technologies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#quickstart" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#documentation" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#team" rel="noopener noreferrer"&gt;Team&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#support" rel="noopener noreferrer"&gt;Support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tjtanjin/react-chatbotify#attributions" rel="noopener noreferrer"&gt;Attributions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Introduction&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/43908963/376082271-6153cd2e-dc21-4c8a-8d91-388fc01d974b.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzIwNzU4MDMsIm5iZiI6MTczMjA3NTUwMywicGF0aCI6Ii80MzkwODk2My8zNzYwODIyNzEtNjE1M2NkMmUtZGMyMS00YzhhLThkOTEtMzg4ZmMwMWQ5NzRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTIwVDA0MDUwM1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWIyYzQzNTE3YzU1OGRiMjg4YTk5OTAzMmUxZTViZGYxYWVmNGYxZTA3ODJlM2U4MjE4YmQzN2Q2ZWFkNWY1ZTgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.bRmvP3IjPIXxWJmaRGZBA3xpWQvhjIw_3QZXxEirTek"&gt;&lt;img height="400px" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F43908963%2F376082271-6153cd2e-dc21-4c8a-8d91-388fc01d974b.gif%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzIwNzU4MDMsIm5iZiI6MTczMjA3NTUwMywicGF0aCI6Ii80MzkwODk2My8zNzYwODIyNzEtNjE1M2NkMmUtZGMyMS00YzhhLThkOTEtMzg4ZmMwMWQ5NzRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTIwVDA0MDUwM1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWIyYzQzNTE3YzU1OGRiMjg4YTk5OTAzMmUxZTViZGYxYWVmNGYxZTA3ODJlM2U4MjE4YmQzN2Q2ZWFkNWY1ZTgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.bRmvP3IjPIXxWJmaRGZBA3xpWQvhjIw_3QZXxEirTek"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Welcome to React ChatBotify, an intuitive and versatile library that allows you to build responsive chatbots with ease. Whether you're aiming to create a simple FAQ bot or a sophisticated conversational interface integrated with Large Language Models (LLMs), React ChatBotify provides the tools and flexibility you need to bring your vision to life.&lt;/p&gt;

&lt;p&gt;Designed with developers in mind, React ChatBotify simplifies the chatbot development process without compromising on functionality. Its intuitive API and comprehensive customization options allow you to tailor your chatbot to meet specific project requirements seamlessly. From handling basic interactions to managing complex and advanced conversational flows, our library empowers you to deliver engaging user experiences. Head over to our &lt;a href="https://github.com/tjtanjin/react-chatbotify/blob/main/SHOWCASES.md" rel="noopener noreferrer"&gt;&lt;strong&gt;community showcases&lt;/strong&gt;&lt;/a&gt; or join &lt;a href="https://discord.gg/6R4DK4G5Zh" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;our discord&lt;/strong&gt;&lt;/a&gt; to get inspired and start crafting your chatbot today!&lt;/p&gt;

&lt;p&gt;React ChatBotify is currently compatible with &lt;strong&gt;React versions&lt;/strong&gt;…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tjtanjin/react-chatbotify" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Issues and PR
&lt;/h2&gt;

&lt;h3&gt;
  
  
  LoadingSpinner Component
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Issue&lt;/strong&gt;: &lt;a href="https://github.com/tjtanjin/react-chatbotify/issues/160" rel="noopener noreferrer"&gt;Add unit test cases for &lt;code&gt;LoadingSpinner&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;strong&gt;PR&lt;/strong&gt;: &lt;a href="https://github.com/tjtanjin/react-chatbotify/pull/267" rel="noopener noreferrer"&gt;Validating the rendering and styling of the &lt;code&gt;LoadingSpinner&lt;/code&gt; component&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The goal of this contribution was to ensure that the &lt;code&gt;LoadingSpinner&lt;/code&gt; component behaves as expected across various contexts, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rendering Verification&lt;/strong&gt;: Ensuring that all spinner elements are correctly rendered in the DOM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary Color Application&lt;/strong&gt;: Validating that the spinner's border color aligns with the primary color set in the settings context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Style Application&lt;/strong&gt;: Verifying that additional styles passed via the styles context are correctly applied, including properties like border-radius, width, and height.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach guaranteed that the spinner maintains visual and functional consistency within the app's design system.&lt;/p&gt;

&lt;h3&gt;
  
  
  FileAttachmentButton Component
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Issue&lt;/strong&gt;: &lt;a href="https://github.com/tjtanjin/react-chatbotify/issues/141" rel="noopener noreferrer"&gt;Add unit test cases for &lt;code&gt;FileAttachmentButton&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;strong&gt;PR&lt;/strong&gt;: &lt;a href="https://github.com/tjtanjin/react-chatbotify/pull/271" rel="noopener noreferrer"&gt;Testing the behavior and rendering of the &lt;code&gt;FileAttachmentButton&lt;/code&gt; component&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The complexity of the &lt;code&gt;FileAttachmentButton&lt;/code&gt; component required testing various states and functionalities, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State-Dependent Icon Rendering&lt;/strong&gt;: Validating different icons for enabled and disabled states based on context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Upload Handling&lt;/strong&gt;: Ensuring the &lt;code&gt;handleUpload&lt;/code&gt; function processes files correctly and calls necessary callbacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preventing Invalid Actions&lt;/strong&gt;: Ensuring that file uploads do not proceed if preconditions (e.g., valid file path) are not met.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The testing strategy ensured reliability in user interaction and maintained robust support for various configurations and edge cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning and Challenges
&lt;/h2&gt;

&lt;p&gt;Unit testing is an area I have been aiming to improve, especially in mocking dependencies and isolating components effectively. These contributions were a great chance to apply my newfound knowledge from a recent lab task.&lt;/p&gt;

&lt;p&gt;A significant challenge was understanding how the existing components functioned to write meaningful tests without altering the code being tested. This required delving into the codebase and determining how to simulate scenarios accurately. Another challenge was achieving comprehensive test coverage while avoiding redundant tests, which required identifying edge cases and state-specific behavior.&lt;/p&gt;

&lt;p&gt;Mocking dependencies, such as contexts and hooks, played a pivotal role in testing these components efficiently. Through this experience, I developed a deeper appreciation for the design of testable code and the importance of clear boundaries between logic and presentation.&lt;/p&gt;

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

&lt;p&gt;This contribution emphasized the value of testing in maintaining and scaling open-source projects. By thoroughly validating the &lt;code&gt;LoadingSpinner&lt;/code&gt; and &lt;code&gt;FileAttachmentButton&lt;/code&gt; components, I ensured they remain reliable across different use cases. The challenges I faced in mocking and achieving good coverage further honed my testing skills, preparing me for future contributions and projects.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementing CI with GitHub Actions Workflow</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Sun, 17 Nov 2024 01:14:08 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/implementing-ci-with-github-actions-workflow-3oh4</link>
      <guid>https://forem.com/cleobnvntra/implementing-ci-with-github-actions-workflow-3oh4</guid>
      <description>&lt;p&gt;For this week's activity, I am tasked to further improve my project &lt;a href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;GENEREADME&lt;/a&gt;, by adding unit tests and implementing &lt;code&gt;Continuous Integration&lt;/code&gt; through GitHub Actions workflow.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cleobnvntra" rel="noopener noreferrer"&gt;
        cleobnvntra
      &lt;/a&gt; / &lt;a href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;
        genereadme
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GENEREADME is a command-line tool that takes in a source code file and generates a README.md file that explains the code in the file by utilizing an LLM.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Contrubutions&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Contributions to &lt;code&gt;GENEREADME&lt;/code&gt; are welcome! Please checkout &lt;a href="https://github.com/cleobnvntra/genereadme./CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; for guidelines on setting up the environment, how to run and test the tool, and submitting changes.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;GENEREADME&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;GENEREADME&lt;/code&gt; is a command-line tool that takes in a file, processes it, and generates a README file with an explanation or documentation of the contents of the file. The tool utilizes OpenAI chat completion to analyze the file and generate content.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/965a9f6318044798c9d5c20cc994e91c6eb1b3fd37e88bd235969308f90480df/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f74703532716165666a64756131676769313565342e676966"&gt;&lt;img src="https://camo.githubusercontent.com/965a9f6318044798c9d5c20cc994e91c6eb1b3fd37e88bd235969308f90480df/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f74703532716165666a64756131676769313565342e676966" alt="genereadme demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Usage&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The tool currently supports &lt;a href="https://console.groq.com/docs/openai" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;Groq&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://openrouter.ai/docs/quick-start" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;OpenRouter&lt;/code&gt;&lt;/a&gt;, which uses &lt;code&gt;Groq&lt;/code&gt; by default. A valid API key for the appropriate provider must be provided.&lt;/p&gt;
&lt;p&gt;Provide a valid API key either by creating a .env file or through the -a or --api-key flag when using the command:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;API_KEY=API_KEY

or

genereadme &amp;lt;files&amp;gt; -a API_KEY
genereadme &amp;lt;files&amp;gt; --api-key API_KEY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Install the dependencies:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm install -g
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run the tool with the existing sample files or start using your own:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;genereadme &amp;lt;files&amp;amp;gt
genereadme examples/sum.js
genereadme examples/createUser.js&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  GitHub Actions Workflow
&lt;/h2&gt;

&lt;p&gt;I primarily used the &lt;code&gt;Node.js&lt;/code&gt; setup for my GitHub Actions, which generates a &lt;code&gt;.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&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;Node.js 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;build&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;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&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="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;18.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;20.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;22.x&lt;/span&gt;&lt;span class="pi"&gt;]&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js ${{ matrix.node-version }}&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="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&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&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build --if-present&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 run test:silent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will run the test whenever changes are either &lt;code&gt;pushed&lt;/code&gt; or merged by &lt;code&gt;pull requests&lt;/code&gt; to the main branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing to OptimizeIt
&lt;/h2&gt;

&lt;p&gt;For this task, I am also required to make a contribution to another project by adding more possible tests. I chose to contribute to &lt;a href="https://github.com/Mounayer/OptimizeIt" rel="noopener noreferrer"&gt;OptimizeIt&lt;/a&gt;.&lt;br&gt;
Since this project also uses &lt;code&gt;jest&lt;/code&gt; for unit testing, and &lt;code&gt;nock&lt;/code&gt; for mocking, it wasn't as difficult adding another test. However, the main challenge is that my partner has already written A LOT of test cases, having a 98% overall coverage. So I had to look for something that is either not tested or any lines that weren't covered, to which I ended up going for the latter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The impact of Continuous Integration
&lt;/h2&gt;

&lt;p&gt;Setting up CI for GENEREADME has been transformative. By automating tests for every push or pull request, it ensures that new changes don’t break existing functionality. For GENEREADME, this means maintaining stability across multiple Node.js versions and saving time on manual testing. CI enhances collaboration, enforces best practices, and builds confidence in the project’s quality, making it an essential addition for sustainable development.&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubactions</category>
      <category>opensource</category>
      <category>jest</category>
    </item>
    <item>
      <title>Formatting and Linting for consistency</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Wed, 06 Nov 2024 14:58:43 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/formatting-and-linting-for-consistency-1hpl</link>
      <guid>https://forem.com/cleobnvntra/formatting-and-linting-for-consistency-1hpl</guid>
      <description>&lt;p&gt;This activity involves implementing statistic analysis tools into my open source project &lt;a href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;GENEREADME&lt;/a&gt; to improve code quality and consistency.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cleobnvntra" rel="noopener noreferrer"&gt;
        cleobnvntra
      &lt;/a&gt; / &lt;a href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;
        genereadme
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GENEREADME is a command-line tool that takes in a source code file and generates a README.md file that explains the code in the file by utilizing an LLM.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Contrubutions&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Contributions to &lt;code&gt;GENEREADME&lt;/code&gt; are welcome! Please checkout &lt;a href="https://github.com/cleobnvntra/genereadme./CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; for guidelines on setting up the environment, how to run and test the tool, and submitting changes.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;GENEREADME&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;GENEREADME&lt;/code&gt; is a command-line tool that takes in a file, processes it, and generates a README file with an explanation or documentation of the contents of the file. The tool utilizes OpenAI chat completion to analyze the file and generate content.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/965a9f6318044798c9d5c20cc994e91c6eb1b3fd37e88bd235969308f90480df/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f74703532716165666a64756131676769313565342e676966"&gt;&lt;img src="https://camo.githubusercontent.com/965a9f6318044798c9d5c20cc994e91c6eb1b3fd37e88bd235969308f90480df/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f74703532716165666a64756131676769313565342e676966" alt="genereadme demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Usage&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The tool currently supports &lt;a href="https://console.groq.com/docs/openai" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;Groq&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://openrouter.ai/docs/quick-start" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;OpenRouter&lt;/code&gt;&lt;/a&gt;, which uses &lt;code&gt;Groq&lt;/code&gt; by default. A valid API key for the appropriate provider must be provided.&lt;/p&gt;
&lt;p&gt;Provide a valid API key either by creating a .env file or through the -a or --api-key flag when using the command:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;API_KEY=API_KEY

or

genereadme &amp;lt;files&amp;gt; -a API_KEY
genereadme &amp;lt;files&amp;gt; --api-key API_KEY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Install the dependencies:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm install -g
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run the tool with the existing sample files or start using your own:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;genereadme &amp;lt;files&amp;amp;gt
genereadme examples/sum.js
genereadme examples/createUser.js&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Formatter
&lt;/h2&gt;

&lt;p&gt;For my formatter, I chose to use &lt;a href="https://prettier.io/docs/en/" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt;. For simple reasons, I chose this because I have simply used its basic features before, and I plan to learn more of it.&lt;/p&gt;

&lt;p&gt;Technically, I already setup my IDE to use prettier by default so I already had my formatter from the beginning. However, now with the prettier setup in the project itself, this will allow contributors to also use the formatter, keeping the project's code consistent in terms of formatting.&lt;/p&gt;

&lt;p&gt;I simply added the rules on how I want the code to be formatted in my &lt;code&gt;.prettierrc&lt;/code&gt; file, and some settings in &lt;code&gt;settings.json&lt;/code&gt; under &lt;code&gt;.vscode/&lt;/code&gt; for options like formatting on save.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linter
&lt;/h2&gt;

&lt;p&gt;For my linter, I chose to use &lt;a href="https://eslint.org/docs/latest/" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt;. Since I am using JavaScript, I used one of the popular linters, which I have also had experience using before, but not really setup myself. So because of that, I went with ESLinter.&lt;/p&gt;

&lt;p&gt;Setting up ESLinter wasn't really complicated. A simple install and setting up the rules in &lt;code&gt;eslint.config.js&lt;/code&gt; is enough to get the linter working. However, since I am both using a formatter and a linter at the same time, I have to make sure that both of them can work together properly. Which basically includes additional rules to ensure that there won't be any conflicts with the linter and formatter.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the tools
&lt;/h2&gt;

&lt;p&gt;There are many ways the tools can be used in the project, and I personally prefer these specific configurations: format on save for prettier and run on type for eslint. This way, the linter will always check for linting issues as the developer types, and then the formatter will auto format the changes when a save is triggered.&lt;/p&gt;

&lt;p&gt;For this week's task however, I also added scripts to allow the user to run the formatter and linter manually through the CLI. A pre-commit hook is also implemented to ensure that any code committed to the repository meets the project’s formatting and linting standards. By adding this hook, I can automatically run Prettier and ESLint before each commit, catching any issues early and maintaining code consistency across contributions. This setup helps reduce the chances of minor formatting issues slipping through and improves code readability for anyone working on the project.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>opensource</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Reflecting on Hacktoberfest 2024</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Sun, 03 Nov 2024 16:55:22 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/reflecting-on-hacktoberfest-2024-43k4</link>
      <guid>https://forem.com/cleobnvntra/reflecting-on-hacktoberfest-2024-43k4</guid>
      <description>&lt;p&gt;Joining Hacktoberfest 2024 has been a great learning experience. As a first-time contributor, I was both excited and a bit nervous about working on open-source projects. I chose issues that helped me gradually build up my skills in different areas of web development. Each project came with its own set of challenges and showed me just how valuable it is to work together in the open-source community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue and PR Recap
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Week 1 - Food Data Scrapper:
&lt;/h3&gt;

&lt;p&gt;Issue: &lt;a href="https://github.com/surreal30/Food-Data-Scrapper/issues/2" rel="noopener noreferrer"&gt;Create requirements.txt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PR: &lt;a href="https://github.com/surreal30/Food-Data-Scrapper/pull/3" rel="noopener noreferrer"&gt;DOCS: Create requirements.txt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first contribution involved creating a requirements.txt file for the Food Data Scrapper project, which was straightforward but introduced me to uv, a package manager I hadn’t encountered before. I learned the importance of project-specific formatting standards after receiving feedback on my &lt;a href="https://github.com/surreal30/Food-Data-Scrapper/pull/3" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; regarding an unintended change from Prettier. This experience underscored the need to be cautious with auto-formatters and adapt to each project’s standards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 2 - Q-Vote:
&lt;/h3&gt;

&lt;p&gt;Issue: &lt;a href="https://github.com/vigneshs-dev/Q-Vote/issues/22" rel="noopener noreferrer"&gt;Bug: No error message on Wrong credentials at Login page.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PR: &lt;a href="https://github.com/vigneshs-dev/Q-Vote/pull/26" rel="noopener noreferrer"&gt;added error messages to login page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My next issue was a bug fix on the Q-Vote project’s sign-in page, where error messages weren’t displaying for invalid login attempts. Working with Flask templates to render these messages was new to me and aligned with my goal to deepen my web development skills. This task allowed me to explore the back-end and front-end aspects of user interaction, enhancing the usability of the sign-in page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 3 - Onlook:
&lt;/h3&gt;

&lt;p&gt;Issue: &lt;a href="https://github.com/onlook-dev/onlook/issues/524" rel="noopener noreferrer"&gt;feat: Add existing functionalities to right click menu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PR: &lt;a href="https://github.com/onlook-dev/onlook/pull/558" rel="noopener noreferrer"&gt;feat: Added existing functionalities to right click menu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For my third contribution, I tackled a feature request on the Onlook project, implementing a functioning right-click menu. Navigating this TypeScript and object-oriented codebase was a significant step up in complexity, and understanding the structure of a large project was both challenging and rewarding. I learned to work with classes and existing functionalities, and after a suggestion from the repo owner, I went the extra mile to make additional modifications within the same PR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 4 - Onlook:
&lt;/h3&gt;

&lt;p&gt;Issue: &lt;a href="https://github.com/onlook-dev/onlook/issues/147" rel="noopener noreferrer"&gt;Bug: Need minimum values for numeric style inputs that can't be negative&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PR: &lt;a href="https://github.com/onlook-dev/onlook/pull/646" rel="noopener noreferrer"&gt;Enforce min/max values in editor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Returning to Onlook for my final contribution, I addressed a bug that required implementing validation logic to prevent invalid inputs in styling properties. Enforcing min and max attributes within a centralized component reduced code repetition and ensured consistent behavior across the app. This contribution deepened my understanding of modular code practices and the importance of clean, maintainable solutions.&lt;/p&gt;

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

&lt;p&gt;Hacktoberfest provided a great opportunity to work with a variety of technologies and projects. I started with simpler issues, gaining confidence in interacting with repo owners and handling basic PRs, and progressed to more complex tasks that challenged me to read, understand, and modify large codebases effectively. This journey has reinforced my passion for web development and prepared me to approach future projects with greater insight and confidence.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>github</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Hacktoberfest 2024 - Part 4</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Sat, 26 Oct 2024 00:59:02 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/hacktoberfest-2024-part-4-887</link>
      <guid>https://forem.com/cleobnvntra/hacktoberfest-2024-part-4-887</guid>
      <description>&lt;p&gt;For this week's and final contribution for &lt;code&gt;Hacktoberfest 2024&lt;/code&gt;, I decided to contribute in the same project, &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;onlook&lt;/a&gt;. As a Software Developer that is in the process of improving my skills in Web Development, I found this project interesting and also helpful to anyone in the field.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/onlook-dev" rel="noopener noreferrer"&gt;
        onlook-dev
      &lt;/a&gt; / &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;
        onlook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The open source, local-first Figma for React. Design directly in your live React app and publish your changes to code.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://youtu.be/RSX_3EaO5eU" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Figma for your React App" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F377240008-c4a0db58-ecf2-4461-b6be-ce84749a3922.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDUwMjEsIm5iZiI6MTcyOTkwNDcyMSwicGF0aCI6Ii8xNDEwNDA3NS8zNzcyNDAwMDgtYzRhMGRiNTgtZWNmMi00NDYxLWI2YmUtY2U4NDc0OWEzOTIyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAxMDUyMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTY4NDEwNmM1NTliMmI2YjdjN2YxOTYzMWFmZDkxNzhmMmRlZTIxODgyYWE0YzE1MTg5NTdjMDRlODI5ZDhlMDgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.q6GEJbvkQSAE0n-LTjIMh5d-uZGPyltvaDHMX-KM2ik"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Onlook&lt;/h3&gt;
&lt;/div&gt;
  &lt;p&gt;
    The first browser-powered visual editor
    &lt;br&gt;
    &lt;a href="https://github.com/onlook-dev/onlook/wiki" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the docs »&lt;/strong&gt;&lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;a href="https://youtu.be/RSX_3EaO5eU?feature=shared" rel="nofollow noopener noreferrer"&gt;View Demo&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=bug&amp;amp;template=bug-report---.md" rel="noopener noreferrer"&gt;Report Bug&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=enhancement&amp;amp;template=feature-request---.md" rel="noopener noreferrer"&gt;Request Feature&lt;/a&gt;
  &lt;/p&gt;
  


&lt;p&gt;&lt;a href="https://discord.gg/hERDfFZCsH" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eb7a9586d232b66e5c1b00c8c8a5b43d9512a0079637291f3f6f3811622e57fa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d446973636f72642d626c61636b3f6c6f676f3d646973636f726426636f6c6f72423d353535" alt="Discord"&gt;&lt;/a&gt;
&lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/57a916e4c2864d169353415c7619e46866f3a8231ee3834add5a6109ff5eeeef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4c696e6b6564496e2d626c61636b2e7376673f6c6f676f3d6c696e6b6564696e26636f6c6f72423d353535" alt="LinkedIn"&gt;&lt;/a&gt;
&lt;a href="https://x.com/onlookdev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e6529281499872a5363998eb49b4e9f16f76e30ff4e080135da4d6867259aab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d547769747465722d626c61636b3f6c6f676f3d7826636f6c6f72423d353535" alt="Twitter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;


  Table of Contents
  &lt;ol&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#roadmap" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contact" rel="noopener noreferrer"&gt;Contact&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#acknowledgments" rel="noopener noreferrer"&gt;Acknowledgments&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;The open-source, local-first visual editor for your React Apps&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Seamlessly integrate with any website or webapp running on React + TailwindCSS, and make live edits directly in the browser DOM. Customize your design, control your codebase, and push changes your changes without compromise.&lt;/p&gt;

  
    
    

    &lt;span class="m-1"&gt;Onlook.Studio.Component.Demo.for.GitHub.mp4&lt;/span&gt;
    
  

  

  


&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDUwMjEsIm5iZiI6MTcyOTkwNDcyMSwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAxMDUyMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTE0ZGVhN2E0NTRlNzJjMjA1ZWM0YjE4MmYwODZmODdiODUwMTFkYWRlNGExM2IzZmM5YzJjYzQ1YTMxMjQ2YmEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Yp6hm2wiJP9OT-kLf3pcjmSIsVKK15oSLj-P5_rI8Jk"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDUwMjEsIm5iZiI6MTcyOTkwNDcyMSwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAxMDUyMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTE0ZGVhN2E0NTRlNzJjMjA1ZWM0YjE4MmYwODZmODdiODUwMTFkYWRlNGExM2IzZmM5YzJjYzQ1YTMxMjQ2YmEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Yp6hm2wiJP9OT-kLf3pcjmSIsVKK15oSLj-P5_rI8Jk" alt="Export-1724891449817"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Built With&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ecf64c6d80398d3ccc24b7b519fc4a12338b1d04a920469c82b52bb6c019fad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f72656163742d2532333230323332612e7376673f6c6f676f3d7265616374266c6f676f436f6c6f723d253233363144414642" alt="React"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.electronjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bc7dd648f0612624a32043879e92ed614f6c68c0c59f935a11066071f9c235/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f456c656374726f6e2d3139313937303f6c6f676f3d456c656374726f6e266c6f676f436f6c6f723d7768697465" alt="Electron"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b435bd99f814e0329b35cd70c9140c2bbaf00df96ac5bcdc91c9c6fbd1766b23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7461696c77696e646373732d2532333338423241432e7376673f6c6f676f3d7461696c77696e642d637373266c6f676f436f6c6f723d7768697465" alt="Tailwind"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/161124b7f44a3572ef26947bbf0184e0b34be3c45b30de132034838cdeedf4b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f766974652d2532333634364346462e7376673f6c6f676f3d76697465266c6f676f436f6c6f723d7768697465" alt="Vite"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stay up-to-date&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Onlook officially launched our first version of Onlook on July 08, 2024 and we've shipped a ton since then. Watch releases of this repository to be notified of future updates, and you can follow along with us on &lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://onlook.substack.com/" rel="nofollow noopener noreferrer"&gt;Substack&lt;/a&gt; where we write a weekly newsletter.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDUwMjEsIm5iZiI6MTcyOTkwNDcyMSwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAxMDUyMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTNjOTZiNzUzM2Y0MmQzOWY2ZWNjZTI2NjM2YTI0NzExNTE4MWE3ODE3ODVhMGJiYjc3MDkxMmU4YWM4YTNhYTImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.3P3Tq1G5GNuA0JOQga4Hm2-tkP_GuY--1J1n-IlXFD8"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDUwMjEsIm5iZiI6MTcyOTkwNDcyMSwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAxMDUyMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTNjOTZiNzUzM2Y0MmQzOWY2ZWNjZTI2NjM2YTI0NzExNTE4MWE3ODE3ODVhMGJiYjc3MDkxMmU4YWM4YTNhYTImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.3P3Tq1G5GNuA0JOQga4Hm2-tkP_GuY--1J1n-IlXFD8" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Run locally&lt;/h4&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repo
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/onlook-dev/onlook.git&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to app folder inside the project
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; onlook/app&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Install NPM packages
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Run the…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Issue #4
&lt;/h2&gt;

&lt;p&gt;This time, I worked with a bugfix &lt;a href="https://github.com/onlook-dev/onlook/issues/147" rel="noopener noreferrer"&gt;issue&lt;/a&gt;. The task requires implementing a validation logic to prevent users from inputting invalid values to some of the styling properties.&lt;/p&gt;

&lt;p&gt;It is important to not allow users to input invalid values in styling such as negative values especially in styling properties where it doesn't make sense to have them. However, there are still styling properties where negative values have their own effect, to which this functionality should be kept available.&lt;/p&gt;

&lt;h2&gt;
  
  
  PR #4
&lt;/h2&gt;

&lt;p&gt;For my &lt;a href="https://github.com/onlook-dev/onlook/pull/646" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;, is the solution I made to fix this bug. The repo owner has given me a tip that they already have implemented the necessary interfaces for the styles which contains the &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; attributes. They also already have the appropriate initialization of the classes of the styles, with the exception of enforcing the min/max attributes.&lt;/p&gt;

&lt;p&gt;So the process is to figure out how the classes for the styles work, how I can enforce the min and max attributes, and where to put the validation logic.&lt;/p&gt;

&lt;p&gt;It was easy to implement once I found where the classes are initialized since I just had to enforce the min and max values, which I will be able to use for the validation logic since these attributes are public attributes of the class.&lt;/p&gt;

&lt;p&gt;Initially, I just added the validation logic directly in the handlers of the input. However, I noticed the amount of code repetition since I had to implement the validation to every handler for the different styles properties. So I tracked the main input component used by these styles properties and implemented the validation logic there instead. This prevents the code repetition for the validation. One of my concerns was that this solution wouldn't work if this input component is used somewhere else other than the styles properties, to which I made sure that it wasn't before implementing this solution.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>hacktoberfest</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Hacktoberfest 2024 - part 3</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Fri, 25 Oct 2024 23:43:30 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/hacktoberfest-2024-part-3-2jlo</link>
      <guid>https://forem.com/cleobnvntra/hacktoberfest-2024-part-3-2jlo</guid>
      <description>&lt;p&gt;For this week's hacktoberfest contribution, I had the privilege of working with &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;&lt;code&gt;onlook&lt;/code&gt;&lt;/a&gt;, a Figma-like visual editor for React applications. For my contribution, I was able to work on an issue to add a new feature to the project.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/onlook-dev" rel="noopener noreferrer"&gt;
        onlook-dev
      &lt;/a&gt; / &lt;a href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;
        onlook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The open source, local-first Figma for React. Design directly in your live React app and publish your changes to code.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://youtu.be/RSX_3EaO5eU" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Figma for your React App" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F377240008-c4a0db58-ecf2-4461-b6be-ce84749a3922.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDE1ODIsIm5iZiI6MTcyOTkwMTI4MiwicGF0aCI6Ii8xNDEwNDA3NS8zNzcyNDAwMDgtYzRhMGRiNTgtZWNmMi00NDYxLWI2YmUtY2U4NDc0OWEzOTIyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAwMDgwMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTZhNTU2ZjVlZWJlNDE5MmMxYmM4Y2FmMGJhZGUyZDBjZjgyZDE3ZTZkNTdlZGQ2ZDU2MmYyZTg1YzZjNzE2YzImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.FVir0ok-iyNetF8RaGVtkUQxEaVJth29A0z2x43Ydnc"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Onlook&lt;/h3&gt;
&lt;/div&gt;
  &lt;p&gt;
    The first browser-powered visual editor
    &lt;br&gt;
    &lt;a href="https://github.com/onlook-dev/onlook/wiki" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the docs »&lt;/strong&gt;&lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;a href="https://youtu.be/RSX_3EaO5eU?feature=shared" rel="nofollow noopener noreferrer"&gt;View Demo&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=bug&amp;amp;template=bug-report---.md" rel="noopener noreferrer"&gt;Report Bug&lt;/a&gt;
    ·
    &lt;a href="https://github.com/onlook-dev/onlook/issues/new?labels=enhancement&amp;amp;template=feature-request---.md" rel="noopener noreferrer"&gt;Request Feature&lt;/a&gt;
  &lt;/p&gt;
  


&lt;p&gt;&lt;a href="https://discord.gg/hERDfFZCsH" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eb7a9586d232b66e5c1b00c8c8a5b43d9512a0079637291f3f6f3811622e57fa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d446973636f72642d626c61636b3f6c6f676f3d646973636f726426636f6c6f72423d353535" alt="Discord"&gt;&lt;/a&gt;
&lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/57a916e4c2864d169353415c7619e46866f3a8231ee3834add5a6109ff5eeeef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4c696e6b6564496e2d626c61636b2e7376673f6c6f676f3d6c696e6b6564696e26636f6c6f72423d353535" alt="LinkedIn"&gt;&lt;/a&gt;
&lt;a href="https://x.com/onlookdev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e6529281499872a5363998eb49b4e9f16f76e30ff4e080135da4d6867259aab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d547769747465722d626c61636b3f6c6f676f3d7826636f6c6f72423d353535" alt="Twitter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;


  Table of Contents
  &lt;ol&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#roadmap" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#contact" rel="noopener noreferrer"&gt;Contact&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#acknowledgments" rel="noopener noreferrer"&gt;Acknowledgments&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/onlook-dev/onlook#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;The open-source, local-first visual editor for your React Apps&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Seamlessly integrate with any website or webapp running on React + TailwindCSS, and make live edits directly in the browser DOM. Customize your design, control your codebase, and push changes your changes without compromise.&lt;/p&gt;

  
    
    

    &lt;span class="m-1"&gt;Onlook.Studio.Component.Demo.for.GitHub.mp4&lt;/span&gt;
    
  

  

  


&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDE1ODIsIm5iZiI6MTcyOTkwMTI4MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAwMDgwMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTU4Njg3ZGE0M2YzYTdjM2VjZGVlM2JlYjIzYTExMmY3NGExNDlmMDA2YzZhYjQ0ZTZhNDgwOGRjYTBhYWY2ZGMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Fzln7h5fIBEeuBfPMxo2CunyD16KvigW-KQyApUZUkE"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362491970-1f317ae1-6453-4a00-8801-f005ccc7efdb.gif%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDE1ODIsIm5iZiI6MTcyOTkwMTI4MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI0OTE5NzAtMWYzMTdhZTEtNjQ1My00YTAwLTg4MDEtZjAwNWNjYzdlZmRiLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAwMDgwMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTU4Njg3ZGE0M2YzYTdjM2VjZGVlM2JlYjIzYTExMmY3NGExNDlmMDA2YzZhYjQ0ZTZhNDgwOGRjYTBhYWY2ZGMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Fzln7h5fIBEeuBfPMxo2CunyD16KvigW-KQyApUZUkE" alt="Export-1724891449817"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Built With&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ecf64c6d80398d3ccc24b7b519fc4a12338b1d04a920469c82b52bb6c019fad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f72656163742d2532333230323332612e7376673f6c6f676f3d7265616374266c6f676f436f6c6f723d253233363144414642" alt="React"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.electronjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bc7dd648f0612624a32043879e92ed614f6c68c0c59f935a11066071f9c235/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f456c656374726f6e2d3139313937303f6c6f676f3d456c656374726f6e266c6f676f436f6c6f723d7768697465" alt="Electron"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b435bd99f814e0329b35cd70c9140c2bbaf00df96ac5bcdc91c9c6fbd1766b23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7461696c77696e646373732d2532333338423241432e7376673f6c6f676f3d7461696c77696e642d637373266c6f676f436f6c6f723d7768697465" alt="Tailwind"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/161124b7f44a3572ef26947bbf0184e0b34be3c45b30de132034838cdeedf4b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f766974652d2532333634364346462e7376673f6c6f676f3d76697465266c6f676f436f6c6f723d7768697465" alt="Vite"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stay up-to-date&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Onlook officially launched our first version of Onlook on July 08, 2024 and we've shipped a ton since then. Watch releases of this repository to be notified of future updates, and you can follow along with us on &lt;a href="https://www.linkedin.com/company/onlook-dev" rel="nofollow noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://onlook.substack.com/" rel="nofollow noopener noreferrer"&gt;Substack&lt;/a&gt; where we write a weekly newsletter.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/14104075/362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDE1ODIsIm5iZiI6MTcyOTkwMTI4MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAwMDgwMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTIzNzNhYzczNzNkOWI3NTliMmJmZGY0MGM4ZmMxNjNiZWU3MmM2MmVmODliZTg1MDZjM2RiOWVmZjQ4MjlhOTYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.iKjX-t1FzTCc5GUsr9RsYBScYBSXRaWQWZwEd7iGwrY"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F14104075%2F362515730-18b6ad5a-1d5a-4396-af8c-8b85936acf39.png%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk5MDE1ODIsIm5iZiI6MTcyOTkwMTI4MiwicGF0aCI6Ii8xNDEwNDA3NS8zNjI1MTU3MzAtMThiNmFkNWEtMWQ1YS00Mzk2LWFmOGMtOGI4NTkzNmFjZjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEwMjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMDI2VDAwMDgwMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTIzNzNhYzczNzNkOWI3NTliMmJmZGY0MGM4ZmMxNjNiZWU3MmM2MmVmODliZTg1MDZjM2RiOWVmZjQ4MjlhOTYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.iKjX-t1FzTCc5GUsr9RsYBScYBSXRaWQWZwEd7iGwrY" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Run locally&lt;/h4&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repo
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/onlook-dev/onlook.git&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to app folder inside the project
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; onlook/app&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Install NPM packages
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Run the…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/onlook-dev/onlook" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Issue #3
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/onlook-dev/onlook/issues/524" rel="noopener noreferrer"&gt;issue&lt;/a&gt; I had to work with requires implementing a new feature which includes using existing functionalities in the project.&lt;/p&gt;

&lt;p&gt;The feature is to implement a functioning right-click menu with the appropriate functionalities. Even though the project can still be considered in the early stages of development, there is already a lot of functionalities implemented. Which is where the challenge arises from.&lt;br&gt;
Reading and understanding the structure of the project and the code, which is utilizing object-oriented programming and taking advantage of &lt;code&gt;TypeScript&lt;/code&gt; to which I'm still learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  PR #3
&lt;/h2&gt;

&lt;p&gt;My &lt;a href="https://github.com/onlook-dev/onlook/pull/558" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; contains the solution to implementing the requested feature. Since the functionalities of the actions are already implemented, the solution to implementing the feature was simple.&lt;/p&gt;

&lt;p&gt;So the main process is to figure out the classes that has the necessary methods and how to use them appropriately. Next is where to implement the existing methods. Luckily, the project already has an existing right-click menu feature, so I just had to add the new options required in the feature with their respective methods to do the action.&lt;/p&gt;

&lt;p&gt;In the end, one of the repo owners made a suggestion as a review to which he suggested I could make it as a separate issue. But since I think that it would be a minor modification, I took on the task and completed it in the same issue and just made another commit in the same PR.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>hacktoberfest</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Hacktoberfest 2024 - part 2</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Wed, 16 Oct 2024 20:58:25 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/hacktoberfest-2024-part-2-1ldj</link>
      <guid>https://forem.com/cleobnvntra/hacktoberfest-2024-part-2-1ldj</guid>
      <description>&lt;p&gt;For this week's hacktoberfest contribution, I had the opportunity to make my first bug fix PR. Moving up from my previous PR, I chose another project written in python.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vigneshs-dev" rel="noopener noreferrer"&gt;
        vigneshs-dev
      &lt;/a&gt; / &lt;a href="https://github.com/vigneshs-dev/Q-Vote" rel="noopener noreferrer"&gt;
        Q-Vote
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A quantum voting system utilizing quantum superposition and entanglement for secure and private voting
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;div&gt; Q-Vote 🗳️&lt;/div&gt;&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;i&gt;  &lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;i&gt; A quantum voting system utilizing quantum superposition and entanglement for secure and private voting&lt;/i&gt; &lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt; &lt;/h2&gt;
&lt;p&gt; &lt;b&gt;Quantum Voting meets Blockchain!&lt;/b&gt; &lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;

&lt;p&gt;🚀 Project Overview&lt;/p&gt;

&lt;/div&gt;
&lt;p&gt;Q-Vote simulates a secure voting process using quantum computing, with future plans for blockchain integration and a user-friendly web interface. This project uses Qiskit to simulate quantum voting and lays the groundwork for secure, private voting systems of the future.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;

&lt;p&gt; 🏗️ Architecture &lt;/p&gt;

&lt;/div&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;graph TD
    A[Client Browser] --&amp;gt;|Request| B[Flask Web Server]
    B --&amp;gt;|Render| C[index.html]
    B --&amp;gt;|Vote| D[Voting Simulation]
    D --&amp;gt; E[Classical Voting]
    D --&amp;gt; F[Quantum Voting]
    E --&amp;gt; G[Collect Votes]
    G --&amp;gt; H[Identify Winner]
    F --&amp;gt; I[Quantum Circuit]
    I --&amp;gt; J[Amplitude Encoding]
    J --&amp;gt; K[Apply Gates]
    K --&amp;gt; L[Measurement]
    L --&amp;gt; M[Interpret Results]
    
    H --&amp;gt; N[Check Ties]
    M --&amp;gt; N
    N --&amp;gt; O[Final Winner]
    
    O --&amp;gt; P[Generate Plot]
    P --&amp;gt; Q[Base64 Image]
    D --&amp;gt; R[JSON Response]
    Q --&amp;gt; R
    R --&amp;gt;|Response| A
    
    subgraph Classical Logic
    E
    G
    H&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vigneshs-dev/Q-Vote" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Issue #2
&lt;/h2&gt;

&lt;p&gt;This will be the second &lt;a href="https://github.com/vigneshs-dev/Q-Vote/issues/22" rel="noopener noreferrer"&gt;issue&lt;/a&gt; that I work on for hacktoberfest. This issue simply requires a bug fix on the sign in page.&lt;br&gt;
Before the fix, the sign in page of the web app does not display any error messages. This means that when a user inputs invalid credentials, they wouldn't know what happened as it does not provide any feedback.&lt;br&gt;
The repo owner uses &lt;code&gt;Flask&lt;/code&gt;, so I had to familiarize myself with Flask's templates to be able to display the appropriate messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  PR #2
&lt;/h2&gt;

&lt;p&gt;In this &lt;a href="https://github.com/vigneshs-dev/Q-Vote/pull/26" rel="noopener noreferrer"&gt;Pull Request&lt;/a&gt;, I only needed to work mostly with the html file where the sign in page is rendered. Since the logic behind the sign in page was already implemented, all I had to do was implement the code needed to display the error messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overall
&lt;/h2&gt;

&lt;p&gt;It was a great learning experience as this kind of issue aligns with my goals for taking the open source course, which is to improve my web development skills and knowledge.&lt;br&gt;
It may be a simple task of writing an html code to render messages, but slowly expanding my knowledge with different languages and frameworks will surely help me in the long run.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>hacktoberfest</category>
      <category>python</category>
    </item>
    <item>
      <title>Refactoring GENEREADME</title>
      <dc:creator>Cleo Buenaventura</dc:creator>
      <pubDate>Tue, 08 Oct 2024 04:08:52 +0000</pubDate>
      <link>https://forem.com/cleobnvntra/refactoring-genereadme-3fo6</link>
      <guid>https://forem.com/cleobnvntra/refactoring-genereadme-3fo6</guid>
      <description>&lt;p&gt;For this week's lab, I was tasked to refactor my code, &lt;a href="https://github.com/cleobnvntra/genereadme" rel="noopener noreferrer"&gt;genereadme&lt;/a&gt; with the opportunity to learn &lt;code&gt;rebasing&lt;/code&gt;, &lt;code&gt;squashing&lt;/code&gt;, and &lt;code&gt;amending&lt;/code&gt; commits. I am tasked to refactor &lt;strong&gt;at least 3&lt;/strong&gt; things in my code, which in a normal case shouldn't be an issue. However, before someone asked to contribute to my project last week for last week's lab, I did a major refactoring since all the code was only in a single &lt;code&gt;index.js&lt;/code&gt; file. The task for last week was to add another feature, which means the project is going to get even bigger. So with that in mind, I decided to refactor it.&lt;br&gt;
Because of this, I struggled a little bit to find more things to refactor in my code as I have refactored it to as much as I think I can, leaving me a bit surprised as I did not expect refactoring to be a part of the labs.&lt;/p&gt;
&lt;h2&gt;
  
  
  What to look for
&lt;/h2&gt;

&lt;p&gt;Well, there are many ways to refactor code. It could be renaming variables, extracting functions, creating classes, splitting code, or optimization. My code isn't really that complex, I am confident that the variable names were self explanatory. So I focused in trying to look for any remaining code duplication or shared functions that I could refactor.&lt;/p&gt;
&lt;h2&gt;
  
  
  Refactoring
&lt;/h2&gt;

&lt;p&gt;I was able to find &lt;strong&gt;2&lt;/strong&gt; files to refactor, which I extracted more functions and split them into separate files. Since I just did a major refactoring a week ago, my goal here is to improve readability and maintainability.&lt;/p&gt;

&lt;p&gt;First, I had a file &lt;code&gt;setup.js&lt;/code&gt; which contains the initialization of &lt;a href="https://www.npmjs.com/package/commander" rel="noopener noreferrer"&gt;Commander&lt;/a&gt; that also includes adding the basic settings, added options, added arguments, and any custom error handling. By looking at it, this file will end up getting bigger as more possible option flags can be added, possibly more custom error handling for new features, or accept an entirely new argument for a different feature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&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;Command&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;program&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packageJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;filename&amp;gt; [options]&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;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLI tool to generate a README file explaining a source code file&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;helpCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addHelpText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;after&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="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Supported providers: [Groq, OpenRouter]&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;version&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;packageJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;packageJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-v, --version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Outputs the tool name and current version&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;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-p, --provider &amp;lt;provider&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Provider for the chat completions&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;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-o, --output &amp;lt;filename&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;output result to specified filename&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;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-a, --api-key &amp;lt;key&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API key for the Groq API&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;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-t, --temperature &amp;lt;temperature&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Temperature for the chat completions&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;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-tu, --token-usage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Show prompt and completion token usage&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;configureOutput&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;outputError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error: missing required argument&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error: No source code file provided. Please provide a valid source code file to process.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;use command: genereadme &amp;lt;files...&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;file...&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Source code file to process&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what I did, is separate them into different functions categorically. Mainly, I have a &lt;code&gt;createProgram()&lt;/code&gt; function which contains the construction of the &lt;code&gt;Command&lt;/code&gt; object and the basic settings, such as program name, version command, help command, and etc.&lt;br&gt;
Then, I created the other functions by category to organize them, making the code readable and maintainable. For example, adding an additional option would require adding &lt;code&gt;.option()&lt;/code&gt; to the &lt;code&gt;Command&lt;/code&gt; object. Having them all in one function makes it readable as these methods are grouped into one function, which I then did the same to the remaining program settings.&lt;/p&gt;

&lt;p&gt;Second, a simple change I made is I basically extracted a logic into a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;baseURL&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;model&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;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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="s2"&gt;groq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.groq.com/openai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llama-3.1-70b-versatile&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;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;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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="s2"&gt;openrouter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://openrouter.ai/api/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meta-llama/llama-3.1-8b-instruct:free&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&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;provider&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is invalid or is currently unsupported. Please choose from the supported providers:\n`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1. Groq&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2. OpenRouter&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;p&gt;This is the logic I have which allows users to use different LLM providers, which I had included in the same file where I am constructing the OpenAI client object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merging
&lt;/h2&gt;

&lt;p&gt;So far, through the use of &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;source control&lt;/code&gt;, or &lt;code&gt;github desktop&lt;/code&gt;, I would normally just make my commits, push the commits to my working branch, then either make a merge or PR. Now I know how to &lt;code&gt;rebase&lt;/code&gt; and &lt;code&gt;squash&lt;/code&gt; multiple commits into one, and using &lt;code&gt;amend&lt;/code&gt; whenever I need to fix something from the last commit.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>github</category>
      <category>refactorit</category>
    </item>
  </channel>
</rss>
