Files
lux/PACKAGES.md
Brandon Lucas 4909ff9fff docs: add package ecosystem plan and error documentation workflow
Add PACKAGES.md analyzing the Lux package ecosystem gaps vs stdlib,
with prioritized implementation plans for markdown, xml, rss, frontmatter,
path, and sitemap packages. Add CLAUDE.md instructions for documenting
Lux language errors in ISSUES.md during every major task.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:01:56 -05:00

12 KiB

Lux Package Ecosystem Plan

Current State

Stdlib (built-in)

Module Coverage
String Comprehensive (split, join, trim, indexOf, replace, etc.)
List Good (map, filter, fold, head, tail, concat, range, find, any, all, take, drop)
Option Basic (map, flatMap, getOrElse, isSome, isNone)
Result Basic (map, flatMap, getOrElse, isOk, isErr)
Math Basic (abs, min, max, sqrt, pow, floor, ceil, round)
Json Comprehensive (parse, stringify, get, typed extractors, constructors)
File Good (read, write, append, exists, delete, readDir, isDir, mkdir)
Console Good (print, read, readLine, readInt)
Process Good (exec, execStatus, env, args, exit, cwd)
Http Basic (get, post, put, delete, setHeader)
HttpServer Basic (listen, accept, respond)
Time Minimal (now, sleep)
Random Basic (int, float, bool)
Sql Good (SQLite: open, query, execute, transactions)
Postgres Good (connect, query, execute, transactions)
Schema Niche (versioned data migration)
Test Good (assert, assertEqual, assertTrue)
Concurrent Experimental (spawn, await, yield, cancel)
Channel Experimental (create, send, receive)

Registry (pkgs.lux) - 3 packages

Package Version Notes
json 1.0.0 Wraps stdlib Json with convenience functions (getPath, getString, etc.)
http-client 0.1.0 Wraps stdlib Http with JSON helpers, URL encoding
testing 0.1.0 Wraps stdlib Test with describe/it structure

Gap Analysis

What's Missing vs Other Languages

Compared to ecosystems like Rust/cargo, Go, Python, Elm, Gleam:

Category Gap Impact Notes
Collections No HashMap, Set, Queue, Stack Critical List-of-pairs with O(n) lookup is the only option
Sorting No List.sort or List.sortBy High Must implement insertion sort manually
Date/Time Only Time.now() (epoch ms), no parsing/formatting High blu-site does string-based date formatting manually
Markdown No markdown parser High blu-site has 300+ lines of hand-rolled markdown
XML/RSS No XML generation High Can't generate RSS feeds or sitemaps
Regex No pattern matching on strings High Character-by-character scanning required
Path No file path utilities Medium basename/dirname manually reimplemented
YAML/TOML No config file parsing (beyond JSON) Medium Frontmatter parsing is manual
Template No string templating Medium HTML built via raw string concatenation
URL No URL parsing/encoding Medium http-client has basic urlEncode but no parser
Crypto No hashing (SHA256, etc.) Medium Can't do checksums, content hashing
Base64 No encoding/decoding Low Needed for data URIs, some auth
CSV No CSV parsing Low Common data format
UUID No UUID generation Low Useful for IDs
Logging No structured logging Low Just Console.print
CLI No argument parsing library Low Manual arg handling

What Should Be Stdlib vs Package

Should be stdlib additions (too fundamental to be packages):

  • HashMap / Map type (requires runtime support)
  • List.sort / List.sortBy (fundamental operation)
  • Better Time module (date parsing, formatting)
  • Regex (needs runtime/C support for performance)
  • Path module (cross-platform file path handling)

Should be packages (application-level, opinionated, composable):

  • markdown
  • xml
  • rss/atom
  • frontmatter
  • template
  • csv
  • crypto
  • ssg (static site generator framework)

Priority Package Plans

Ordered by what unblocks blu-site fixes first, then general ecosystem value.


Package 1: markdown (Priority: HIGHEST)

Why: The 300-line markdown parser in blu-site's main.lux is general-purpose code that belongs in a reusable package. It's also the most complex part of blu-site and has known bugs (e.g., ### inside list items renders literally).

Scope:

markdown/
  lux.toml
  lib.lux          # Public API: parse, parseInline
  src/
    inline.lux     # Inline parsing (bold, italic, links, images, code)
    block.lux      # Block parsing (headings, lists, code blocks, blockquotes, hr)
    types.lux      # AST types (optional - could emit HTML directly)

Public API:

// Convert markdown string to HTML string
pub fn toHtml(markdown: String): String

// Convert inline markdown only (no blocks)
pub fn inlineToHtml(text: String): String

// Escape HTML entities
pub fn escapeHtml(s: String): String

Improvements over current blu-site code:

  • Fix heading-inside-list-item rendering (- ### Title should work)
  • Support nested lists (currently flat only)
  • Support reference-style links [text][ref]
  • Handle edge cases (empty lines in code blocks, nested blockquotes)
  • Proper HTML entity escaping in more contexts

Depends on: Nothing (pure string processing)

Estimated size: ~400-500 lines of Lux


Package 2: xml (Priority: HIGH)

Why: Needed for RSS/Atom feed generation, sitemap.xml, and robots.txt generation. General-purpose XML builder that doesn't try to parse XML (which would need regex), just emits it.

Scope:

xml/
  lux.toml
  lib.lux          # Public API: element, document, serialize

Public API:

type XmlNode =
    | Element(String, List<XmlAttr>, List<XmlNode>)
    | Text(String)
    | CData(String)
    | Comment(String)
    | Declaration(String, String)  // version, encoding

type XmlAttr =
    | Attr(String, String)

// Build an XML element
pub fn element(tag: String, attrs: List<XmlAttr>, children: List<XmlNode>): XmlNode

// Build a text node (auto-escapes)
pub fn text(content: String): XmlNode

// Build a CDATA section
pub fn cdata(content: String): XmlNode

// Serialize XML tree to string
pub fn serialize(node: XmlNode): String

// Serialize with XML declaration header
pub fn document(version: String, encoding: String, root: XmlNode): String

// Convenience: self-closing element
pub fn selfClosing(tag: String, attrs: List<XmlAttr>): XmlNode

Depends on: Nothing

Estimated size: ~150-200 lines


Package 3: rss (Priority: HIGH)

Why: Directly needed for blu-site's #6 priority fix (add RSS feed). Builds on xml package.

Scope:

rss/
  lux.toml         # depends on xml
  lib.lux          # Public API: feed, item, toXml, toAtom

Public API:

type FeedInfo =
    | FeedInfo(String, String, String, String, String)
    // title, link, description, language, lastBuildDate

type FeedItem =
    | FeedItem(String, String, String, String, String, String)
    // title, link, description, pubDate, guid, categories (comma-separated)

// Generate RSS 2.0 XML string
pub fn toRss(info: FeedInfo, items: List<FeedItem>): String

// Generate Atom 1.0 XML string
pub fn toAtom(info: FeedInfo, items: List<FeedItem>): String

Depends on: xml

Estimated size: ~100-150 lines


Package 4: frontmatter (Priority: HIGH)

Why: blu-site has ~50 lines of fragile frontmatter parsing. This is a common need for any content-driven Lux project. The current parser uses String.indexOf(line, ": ") which breaks on values containing : .

Scope:

frontmatter/
  lux.toml
  lib.lux          # Public API: parse

Public API:

type FrontmatterResult =
    | FrontmatterResult(List<(String, String)>, String)
    // key-value pairs, remaining body

// Parse frontmatter from a string (--- delimited YAML-like header)
pub fn parse(content: String): FrontmatterResult

// Get a value by key from parsed frontmatter
pub fn get(pairs: List<(String, String)>, key: String): Option<String>

// Get a value or default
pub fn getOrDefault(pairs: List<(String, String)>, key: String, default: String): String

// Parse a space-separated tag string into a list
pub fn parseTags(tagString: String): List<String>

Improvements over current blu-site code:

  • Handle values with : in them (only split on first : )
  • Handle multi-line values (indented continuation)
  • Handle quoted values with embedded newlines
  • Strip quotes from values consistently

Depends on: Nothing

Estimated size: ~100-150 lines


Package 5: path (Priority: MEDIUM)

Why: blu-site manually implements basename and dirname. Any file-processing Lux program needs these. Tiny but universally useful.

Scope:

path/
  lux.toml
  lib.lux

Public API:

// Get filename from path: "/foo/bar.txt" -> "bar.txt"
pub fn basename(p: String): String

// Get directory from path: "/foo/bar.txt" -> "/foo"
pub fn dirname(p: String): String

// Get file extension: "file.txt" -> "txt", "file" -> ""
pub fn extension(p: String): String

// Remove file extension: "file.txt" -> "file"
pub fn stem(p: String): String

// Join path segments: join("foo", "bar") -> "foo/bar"
pub fn join(a: String, b: String): String

// Normalize path: "foo//bar/../baz" -> "foo/baz"
pub fn normalize(p: String): String

// Check if path is absolute
pub fn isAbsolute(p: String): Bool

Depends on: Nothing

Estimated size: ~80-120 lines


Package 6: sitemap (Priority: MEDIUM)

Why: Directly needed for blu-site's #9 priority fix. Simple package that generates sitemap.xml.

Scope:

sitemap/
  lux.toml         # depends on xml
  lib.lux

Public API:

type SitemapEntry =
    | SitemapEntry(String, String, String, String)
    // url, lastmod (ISO date), changefreq, priority

// Generate sitemap.xml string
pub fn generate(entries: List<SitemapEntry>): String

// Generate a simple robots.txt pointing to the sitemap
pub fn robotsTxt(sitemapUrl: String): String

Depends on: xml

Estimated size: ~50-70 lines


Package 7: ssg (Priority: LOW - future)

Why: Once markdown, frontmatter, rss, sitemap, and path packages exist, the remaining logic in blu-site's main.lux is generic SSG framework code: read content dirs, parse posts, sort by date, generate section indexes, generate tag pages, copy static assets. This could be extracted into a framework package that other Lux users could use to build their own static sites.

This should wait until the foundation packages above are stable and battle-tested through blu-site usage.


Non-Package Stdlib Improvements Needed

These gaps are too fundamental to be packages and should be added to the Lux language itself:

HashMap (Critical)

Every package above that needs key-value lookups (frontmatter, xml attributes, etc.) is working around the lack of HashMap with List<(String, String)>. This is O(n) per lookup and makes code verbose. A stdlib Map module would transform the ecosystem.

List.sort / List.sortBy (High)

blu-site implements insertion sort manually. Every content-driven app needs sorting. This should be a stdlib function.

Time.format / Time.parse (High)

blu-site manually parses "2025-01-15" by substring extraction and maps month numbers to names. A proper date/time library (even just ISO 8601 parsing and basic formatting) would help every package above.


Implementation Order

Phase 1 (unblock blu-site fixes):
  1. markdown     - extract from blu-site, fix bugs, publish
  2. frontmatter  - extract from blu-site, improve robustness
  3. path         - tiny, universally useful
  4. xml          - needed by rss and sitemap

Phase 2 (complete blu-site features):
  5. rss          - depends on xml
  6. sitemap      - depends on xml

Phase 3 (ecosystem growth):
  7. template     - string templating (mustache-like)
  8. csv          - data processing
  9. cli          - argument parsing
  10. ssg         - framework extraction from blu-site

Each package should be developed in its own directory under ~/src/, published to the git.qrty.ink registry, and tested by integrating it into blu-site.