<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Claudia Nadalin</title>
    <description>The latest articles on DEV Community by Claudia Nadalin (@claudianadalin).</description>
    <link>https://dev.to/claudianadalin</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%2F3681905%2F0c183690-7688-41bd-9ed6-bc4e78009c5a.png</url>
      <title>DEV Community: Claudia Nadalin</title>
      <link>https://dev.to/claudianadalin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/claudianadalin"/>
    <language>en</language>
    <item>
      <title>Why We Don't Tell You What to Build (FrontendCheck)</title>
      <dc:creator>Claudia Nadalin</dc:creator>
      <pubDate>Sun, 04 Jan 2026 10:46:55 +0000</pubDate>
      <link>https://dev.to/claudianadalin/why-we-dont-tell-you-what-to-build-1ac7</link>
      <guid>https://dev.to/claudianadalin/why-we-dont-tell-you-what-to-build-1ac7</guid>
      <description>&lt;p&gt;The following is a blog post from &lt;a href="//frontendcheck.com"&gt;FrontendCheck.com&lt;/a&gt;, a platform that teaches devs how to build unique SaaS with enterprise architecture. Your patterns. Your portfolio. Your thing.&lt;/p&gt;




&lt;p&gt;Every coding tutorial tells you exactly what to build. A todo app. A weather dashboard. A Twitter clone. We do something different—we teach the architecture and let you decide what product to create. Here's the philosophy behind that choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Prescribed Projects
&lt;/h2&gt;

&lt;p&gt;Traditional tutorials have a fundamental tension: they need to teach technical concepts, but they also need to tell you what to build. The result is millions of developers with identical portfolios.&lt;/p&gt;

&lt;p&gt;How many todo apps exist in the world? How many weather dashboards? How many Twitter clones that look exactly like the tutorial they came from?&lt;/p&gt;

&lt;p&gt;When everyone builds the same thing, several problems emerge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your portfolio doesn't stand out. Hiring managers have seen the same projects hundreds of times.&lt;/li&gt;
&lt;li&gt;You don't practice making product decisions. Real work requires deciding what to build, not just how.&lt;/li&gt;
&lt;li&gt;Motivation suffers. Building something you don't care about is a slog.&lt;/li&gt;
&lt;li&gt;You can't explain your work with passion. Try getting excited about todo app #38 in an interview.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Separating Architecture from Product
&lt;/h2&gt;

&lt;p&gt;Here's the insight that changed everything for us: the architectural patterns are the same regardless of what you're building.&lt;/p&gt;

&lt;p&gt;Multi-tenant data isolation works the same way whether you're building a task manager, a CRM, or a cat fashion store. Role-based permissions follow the same patterns whether it's for a notes app or an ex-tracking relationship retrospective tool. Theming systems, internationalization, real-time updates—the architecture is consistent.&lt;/p&gt;

&lt;p&gt;So why force everyone to build the same product?&lt;/p&gt;

&lt;p&gt;We separated the concerns. We teach the architecture—the patterns that transfer to any product. You decide what product to apply them to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain-Adaptive Learning
&lt;/h2&gt;

&lt;p&gt;We call this approach domain-adaptive learning. Each challenge teaches specific architectural patterns, but you choose the domain that interests you.&lt;/p&gt;

&lt;p&gt;Want to build a task manager? Great—maybe it becomes ChoreQuest, a gamified household chore tracker. Or ADHD Brain Dump, a neurodivergent-friendly task capture tool. The domain provides the vocabulary and data structures. You decide the personality.&lt;/p&gt;

&lt;p&gt;Prefer a CRM? It could become Meowdrobe, managing cat fashion influencer relationships. Or Band Manager, tracking touring musician contacts. Same architectural patterns, completely different products.&lt;/p&gt;

&lt;p&gt;Two people completing the same challenge will have entirely different portfolio pieces. Both learned identical skills. Neither can be accused of just copying a tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Your Career
&lt;/h2&gt;

&lt;p&gt;When you interview for a frontend role, you'll be asked about projects you've built. The difference between these two answers is significant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I built a todo app from a tutorial. It has CRUD operations."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;versus:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I built ChoreQuest, a gamified household task manager. It uses multi-tenant architecture so families can have separate workspaces, role-based permissions so parents and kids have different capabilities, and a dynamic theming system so each family can customize their experience. I chose the gamification angle because I wanted to solve the problem of motivating kids to do chores."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second answer demonstrates the same technical skills but shows something more: product thinking, creativity, and genuine investment in the problem being solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creative Ownership Creates Better Learning
&lt;/h2&gt;

&lt;p&gt;There's a pedagogical reason for this approach too. When you care about what you're building, you learn better.&lt;/p&gt;

&lt;p&gt;Motivation isn't just nice to have—it's essential for deep learning. When you're building something you actually want to exist, you push through the hard parts. You go beyond the minimum requirements. You think about edge cases because they matter to your vision, not because a tutorial told you to.&lt;/p&gt;

&lt;p&gt;The architecture we teach is genuinely challenging. Multi-tenant data isolation, permission systems, internationalization—these aren't simple topics. Having a product you care about makes the challenge worth tackling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Weird App Advantage
&lt;/h2&gt;

&lt;p&gt;We encourage weird app ideas. Not because weird is better, but because weird is memorable.&lt;/p&gt;

&lt;p&gt;A cat fashion store CRM sticks in people's minds. A meditation app for programmers called /dev/zen makes people smile. An ex-tracking relationship retrospective tool makes people ask questions.&lt;/p&gt;

&lt;p&gt;Memorable projects get discussed. They get shared. They make interviewers curious. They demonstrate personality.&lt;/p&gt;

&lt;p&gt;And here's the thing: the technical patterns are exactly the same as "serious" apps. A cat fashion store CRM and a real enterprise CRM use identical multi-tenant architecture. The whimsy doesn't diminish the technical achievement—it just makes it more interesting to talk about.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works in Practice
&lt;/h2&gt;

&lt;p&gt;When you start a FrontendCheck challenge, you choose from available domains—task manager, CRM, notes app, inventory, and more. Each domain comes with appropriate vocabulary, data structures, and example applications.&lt;/p&gt;

&lt;p&gt;Then you receive stakeholder emails introducing requirements. These requirements teach architectural patterns: "We need to support multiple organizations" teaches multi-tenancy. "Different user roles need different permissions" teaches RBAC. The patterns are consistent; the product context is yours.&lt;/p&gt;

&lt;p&gt;You build your app using these patterns. You name it. You style it. You deploy it. When you're done, you have a unique portfolio piece that demonstrates enterprise-level skills in a package that's entirely your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Transfers, Products Don't
&lt;/h2&gt;

&lt;p&gt;The skills you learn are the same regardless of what you build. Multi-tenant architecture works identically in a task manager and a CRM. Permission systems follow the same patterns whether you're managing chores or managing inventory.&lt;/p&gt;

&lt;p&gt;But the product? That's yours. That's what makes your portfolio unique. That's what you'll talk about in interviews with genuine enthusiasm.&lt;/p&gt;

&lt;p&gt;We don't tell you what to build because we don't need to. The architecture is what matters, and that we teach thoroughly. The product is what makes it yours—and that should come from you.&lt;/p&gt;

&lt;p&gt;Key takeaway: We teach enterprise architecture patterns. You decide what product to build with them. Same skills, unique portfolio. That's the FrontendCheck philosophy.&lt;/p&gt;




&lt;p&gt;If you'd like to build your own unique SaaS using enterprise frontend techniques, then start the free challenge over at &lt;a href="https://www.frontendcheck.com/challenges/saas-pivot" rel="noopener noreferrer"&gt;FrontendCheck.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>career</category>
      <category>learning</category>
      <category>portfolio</category>
    </item>
    <item>
      <title>I Built a Module System for a Language That Doesn't Have One</title>
      <dc:creator>Claudia Nadalin</dc:creator>
      <pubDate>Sat, 27 Dec 2025 21:26:11 +0000</pubDate>
      <link>https://dev.to/claudianadalin/i-built-a-module-system-for-a-language-that-doesnt-have-one-13kb</link>
      <guid>https://dev.to/claudianadalin/i-built-a-module-system-for-a-language-that-doesnt-have-one-13kb</guid>
      <description>&lt;p&gt;You know what's funny about PineScript? It's 2025 and we're writing trading indicators like it's 1995. One file. Everything global. No modules. No imports. Just you, your code, and the slow descent into madness.&lt;/p&gt;

&lt;p&gt;I'd been putting up with this for a while. I had a fairly complex indicator that used code I'd split across multiple TradingView libraries. Seemed like the right thing to do at the time. Separate concerns. Keep things clean. Very professional.&lt;/p&gt;

&lt;p&gt;Then I needed to change one function.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Workflow From Hell
&lt;/h2&gt;

&lt;p&gt;Here's what updating a library function looked like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit the code locally&lt;/li&gt;
&lt;li&gt;Push to git&lt;/li&gt;
&lt;li&gt;Copy-paste into TradingView's editor&lt;/li&gt;
&lt;li&gt;Republish the library&lt;/li&gt;
&lt;li&gt;Note the new version number&lt;/li&gt;
&lt;li&gt;Open my indicator script&lt;/li&gt;
&lt;li&gt;Update the import statement with the new version&lt;/li&gt;
&lt;li&gt;Save that&lt;/li&gt;
&lt;li&gt;Push that to git&lt;/li&gt;
&lt;li&gt;Copy-paste into TradingView's editor&lt;/li&gt;
&lt;li&gt;Save again&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that's for ONE library. I had five.&lt;/p&gt;

&lt;p&gt;You ever see that Seinfeld episode where George tries to do the opposite of every instinct he has? That's what this workflow felt like, except I wasn't getting a job with the Yankees at the end of it. I was just trying to fix a bug.&lt;/p&gt;

&lt;p&gt;There had to be another way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surely Someone's Solved This
&lt;/h2&gt;

&lt;p&gt;I started researching. Googled things like "PineScript bundler", "PineScript multiple files", "PineScript module system".&lt;/p&gt;

&lt;p&gt;I found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VS Code extensions for syntax highlighting (cool, but not what I need)&lt;/li&gt;
&lt;li&gt;PyneCore/PyneSys, which transpile PineScript to Python for running backtests locally (interesting, but different problem)&lt;/li&gt;
&lt;li&gt;A lot of forum posts from people with the same frustration and no solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I didn't find was a bundler. Nobody had built the thing I wanted.&lt;/p&gt;

&lt;p&gt;But even before searching, I knew why this was hard. I knew what any solution would require. And it wasn't pretty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is Actually Hard
&lt;/h2&gt;

&lt;p&gt;JavaScript has something called scope. When Webpack bundles your code, it can wrap each module in a function and they're isolated from each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;__module_1__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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="nx"&gt;double&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;__module_2__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// No collision - different scope&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;double&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;Two functions named &lt;code&gt;double&lt;/code&gt;, no problem. They live in different scopes. They can't see each other. Webpack leverages this to keep modules isolated.&lt;/p&gt;

&lt;p&gt;PineScript doesn't have this.&lt;/p&gt;

&lt;p&gt;There are no closures. No way to create isolated scopes. Everything is basically global. If you define &lt;code&gt;double&lt;/code&gt; in one file and &lt;code&gt;double&lt;/code&gt; in another file, then smash those files together, you've got a collision. One overwrites the other. Your code breaks.&lt;/p&gt;

&lt;p&gt;So any PineScript bundler would need to rename things. Take the &lt;code&gt;double&lt;/code&gt; function from &lt;code&gt;utils/math.pine&lt;/code&gt; and rename it to something like &lt;code&gt;__utils_math__double&lt;/code&gt;. Do the same for every export from every file. Update all the references. No collisions.&lt;/p&gt;

&lt;p&gt;I knew this was the path before I wrote a single line of code. The question was: how do you actually rename things in code reliably?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Find/Replace Trap
&lt;/h2&gt;

&lt;p&gt;My first instinct was simple: just use find/replace. Find &lt;code&gt;double&lt;/code&gt;, replace with &lt;code&gt;__utils_math__double&lt;/code&gt;. Done.&lt;/p&gt;

&lt;p&gt;Here's why that falls apart immediately. Imagine this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;double(x) =&amp;gt;
    x * 2

myLabel = "Call double() for twice the value"
doubleCheck = true
plot(double(close), title="double")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to rename the &lt;code&gt;double&lt;/code&gt; function to &lt;code&gt;__utils_math__double&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With find/replace, you'd get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;__utils_math__double(x) =&amp;gt;
    x * 2

myLabel = "Call __utils_math__double() for twice the value"  // Broken - changed string content
__utils_math__doubleCheck = true                              // Broken - renamed wrong variable
plot(__utils_math__double(close), title="__utils_math__double")   // Broken - changed string content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've corrupted string literals and renamed a completely unrelated variable that happened to start with "double".&lt;/p&gt;

&lt;p&gt;Find/replace sees code as a flat string of characters. It has no idea that &lt;code&gt;"double"&lt;/code&gt; inside quotes is a string, not a function reference. It can't tell that &lt;code&gt;doubleCheck&lt;/code&gt; is a different identifier. It just sees the letters d-o-u-b-l-e and does its thing.&lt;/p&gt;

&lt;p&gt;I needed a way to understand the &lt;em&gt;structure&lt;/em&gt; of the code. To know that this &lt;code&gt;double&lt;/code&gt; is a function definition, that &lt;code&gt;double&lt;/code&gt; is a function call, and that &lt;code&gt;"double"&lt;/code&gt; is just text inside a string that should be left alone.&lt;/p&gt;

&lt;p&gt;This is where I got stuck. Building something that truly understands PineScript's structure would take months. Parsing is hard. PineScript has weird indentation rules, line continuation, type inference, all sorts of quirks.&lt;/p&gt;

&lt;p&gt;Then I found pynescript.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Missing Piece
&lt;/h2&gt;

&lt;p&gt;pynescript is a Python library that parses PineScript into something called an Abstract Syntax Tree (AST), and can unparse it back into PineScript.&lt;/p&gt;

&lt;p&gt;If "Abstract Syntax Tree" sounds intimidating, don't worry. It's actually a simple concept. An AST is basically the DOM, but for code instead of HTML.&lt;/p&gt;

&lt;p&gt;When your browser gets HTML, it doesn't keep it as a string. It parses it into a tree structure where each node knows what it is. A &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;. A &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;. A text node. You can manipulate these nodes programmatically - add classes, change text, move things around - without doing string manipulation on raw HTML.&lt;/p&gt;

&lt;p&gt;An AST does the same thing for code. When you parse this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;double(x) =&amp;gt;
    x * 2

myLabel = "Call double()"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get a tree like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Script
├── FunctionDefinition
│   ├── name: "double"           ← I'm a function definition
│   ├── parameters: ["x"]
│   └── body: BinaryOp(x * 2)
│
└── Assignment
    ├── target: "myLabel"
    └── value: StringLiteral     ← I'm a string, leave me alone
        └── "Call double()"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now renaming becomes surgical. You say: "Find all nodes of type &lt;code&gt;FunctionDefinition&lt;/code&gt; where name equals &lt;code&gt;double&lt;/code&gt;. Rename those. Find all nodes of type &lt;code&gt;FunctionCall&lt;/code&gt; where the function is &lt;code&gt;double&lt;/code&gt;. Rename those too. Leave &lt;code&gt;StringLiteral&lt;/code&gt; nodes alone."&lt;/p&gt;

&lt;p&gt;The string content is untouched because it's a &lt;code&gt;StringLiteral&lt;/code&gt; node, not a &lt;code&gt;FunctionCall&lt;/code&gt; node. &lt;code&gt;doubleCheck&lt;/code&gt; is untouched because it's a completely different identifier node. The structure tells you what's what.&lt;/p&gt;

&lt;p&gt;pynescript had already done the hard work of parsing PineScript correctly. Months of work with ANTLR (a serious parser generator). I could just &lt;code&gt;pip install pynescript&lt;/code&gt; and get access to that tree.&lt;/p&gt;

&lt;p&gt;I had my strategy (rename with prefixes), and now I had my tool (AST manipulation via pynescript). Time to see if it actually worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spike
&lt;/h2&gt;

&lt;p&gt;Before committing to building a full tool, I wanted to prove the concept. Take two PineScript files, parse them, rename stuff in the AST, merge them, unparse, see if TradingView accepts the output.&lt;/p&gt;

&lt;p&gt;I created two tiny files:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;math_utils.pine:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//@version=5
// @export double

double(x) =&amp;gt;
    x * 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;main.pine:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//@version=5
// @import { double } from "./math_utils.pine"

indicator("Test", overlay=true)

result = double(close)
plot(result)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then wrote some Python to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse both files with pynescript&lt;/li&gt;
&lt;li&gt;Find the function definition for &lt;code&gt;double&lt;/code&gt; in the AST&lt;/li&gt;
&lt;li&gt;Rename it to &lt;code&gt;__math_utils__double&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Find references to &lt;code&gt;double&lt;/code&gt; in main.pine's AST&lt;/li&gt;
&lt;li&gt;Update them to &lt;code&gt;__math_utils__double&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Merge and unparse&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I ran it. Out came:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//@version=5
indicator("Test", overlay=true)

__math_utils__double(x) =&amp;gt;
    x * 2

result = __math_utils__double(close)
plot(result)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I pasted it into TradingView.&lt;/p&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;I sat there for a second, genuinely surprised. Not because it was magic, but because I'd expected to hit some weird edge case or parser limitation that would kill the whole idea. But no. It just... worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Real Thing
&lt;/h2&gt;

&lt;p&gt;With the spike working, I built out the full tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A CLI (&lt;code&gt;pinecone build&lt;/code&gt;, &lt;code&gt;pinecone build --watch&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Config file support&lt;/li&gt;
&lt;li&gt;Proper dependency graph construction&lt;/li&gt;
&lt;li&gt;Topological sorting (so dependencies come before the code that uses them)&lt;/li&gt;
&lt;li&gt;Error messages that point to your original files, not the bundled output&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;--copy&lt;/code&gt; flag that puts the output straight into your clipboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The module syntax uses comments so that unbundled code doesn't break if you accidentally paste it into TradingView:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// @import { customRsi } from "./indicators/rsi.pine"
// @export myFunction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TradingView's parser just sees these as comments and ignores them. PineCone sees them as directives.&lt;/p&gt;

&lt;p&gt;The prefix strategy uses the file path. &lt;code&gt;src/utils/math.pine&lt;/code&gt; becomes &lt;code&gt;__utils_math__&lt;/code&gt;. Every exported function and variable from that file gets that prefix. Every reference to those exports gets updated.&lt;/p&gt;

&lt;p&gt;It's not elegant. Your bundled output has ugly names like &lt;code&gt;__indicators_rsi__customRsi&lt;/code&gt;. But it works. TradingView accepts it. There are no collisions. And you never have to look at the bundled output anyway - it's just an intermediate artifact, like compiled code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Did I Actually Build?
&lt;/h2&gt;

&lt;p&gt;I've been calling it "Webpack for PineScript" but that's not quite right. Webpack does a lot of stuff: code splitting, lazy loading, tree shaking, hot module replacement.&lt;/p&gt;

&lt;p&gt;PineCone does one thing: it lets you write PineScript across multiple files with a module system, and compiles it down to a single file TradingView can understand.&lt;/p&gt;

&lt;p&gt;It's a module system and bundler for a language that has neither.&lt;/p&gt;

&lt;p&gt;PineCone doesn't add features to PineScript. It doesn't make your indicators faster. It doesn't connect to your broker. It just lets you organize your code like a normal human being in 2025.&lt;/p&gt;

&lt;p&gt;And honestly? That's enough. That's the thing I needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;If you're working with a language that's missing something fundamental, you might not be stuck. Look for parsers. Look for AST tools. If someone's already done the work of understanding the language's structure, you can build on top of that.&lt;/p&gt;

&lt;p&gt;pynescript didn't solve my problem directly. It's a parser, not a bundler. But it solved the hard part - correctly parsing PineScript - and let me focus on the part I actually cared about: the module system.&lt;/p&gt;

&lt;p&gt;Anyway, Pinecone is open source. If you're a PineScript developer who's ever felt the pain of managing multiple libraries, give it a try. And if you've got ideas for making it better, I'm all ears.&lt;/p&gt;

&lt;p&gt;Serenity now.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Pinecone is available &lt;a href="https://claudianadalin.github.io/pinecone" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Built with &lt;a href="https://pypi.org/project/pynescript/" rel="noopener noreferrer"&gt;pynescript&lt;/a&gt;, which you should also check out if you're doing anything programmatic with PineScript.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Claudia is a Frontend Developer. You can find more of her work &lt;a href="https://www.claudianadalin.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>showdev</category>
      <category>programming</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
