Commit Graph

12 Commits

Author SHA1 Message Date
jbrechtel 95a7521584 Fix all hlint warnings
- Html.hs: replace lambdas with section/composition where possible
- Html.hs: replace case/fromMaybe with fromMaybe
- Html.hs: add fromMaybe to imports, use unqualified
- Parser.hs: replace span with break (2 locations)
- Parser.hs: replace if/then/else with list comprehension
- Parser.hs: remove redundant catch-all patterns (break is exhaustive)
- Server.hs: eta reduce htmlResponse
- Add .hlint.yaml to suppress 'Avoid lambda' (suggested fix has
  precedence issues with blaze-html's infix (!) operator)
- All 26 tests passing, hlint: No hints, exit code 0
2026-05-19 07:25:59 -04:00
jbrechtel b775fd4f3f Recipe detail page with server-side HTML rendering
- Add Roux.Html.recipePage: full recipe detail page with:
  - Back navigation link
  - Title and metadata (servings, times, difficulty, etc.)
  - Ingredients summary list with quantities
  - Sections with named headings
  - Steps with inline element rendering:
    - Ingredients highlighted in pumpkin (with quantity badge)
    - Cookware in violet italic
    - Timers in azure with ⏱ icon
    - Comments in sand italic
    - Recipe refs as links
    - Line breaks
- Update Roux.Server: route /recipes/FILENAME to recipe page
  - Case-insensitive filename lookup, .cook extension optional
  - URL decoding for filenames
- Fix ingredient name parsing: restrict name characters to
  alphaNum + spaces/hyphens/apostrophes, preventing greedy
  consumption across special chars like ) and #
- Split name chars into pMultiNameChar (with spaces, before braces)
  and pSingleNameChar (without spaces, fallback)
- Suppress -Wname-shadowing in Html.hs (blaze-html exports clash
  with common variable names)
- All 26 tests passing, server smoke-tested with examples
2026-05-19 07:12:14 -04:00
jbrechtel 4943d4d42e Web server with recipe index page
- Add Roux.Server: WAI application using wai+warp directly
  - Scans .cook files from recipe directory on startup
  - GET / → HTML index page listing all recipes
  - Other routes → 404
- Add Roux.RecipeIndex: directory scanning and recipe parsing
  - scanRecipes: lists .cook files, parses each, extracts titles
  - Falls back to filename when metadata title is absent
- Add Roux.Html: blaze-html rendering with Pico CSS
  - indexPage: renders recipe list with links
  - urlEncode: percent-encodes filenames for URLs
- Update Roux.hs: re-exports Server.app and Types
- Add filepath to dependencies
2026-05-19 07:04:22 -04:00
jbrechtel ffb1931c7d Phase 5: Compound quantities, trailing-unit format, and edge cases
- Add splitAmountUnit to parse quantities with unit attached without
  % separator (e.g., @water{1,1/2cups}, @gelatine{3tsp})
- Add isNumericChar helper for detecting numeric quantity characters
- Add compound quantity test (1,1/2 cups = 3/2)
- Add no-separator unit test (3tsp)
- All 26 tests passing, all 4 example files parse correctly
2026-05-18 23:02:53 -04:00
jbrechtel c68d80e9c1 Phase 4: Recipe references + all 4 example file validation
- Fix pRecipeRef to include ./ prefix in stored path
- Add recipe reference test
- Add parse-validation tests for all 4 example .cook files
  (EasyPancakes, FriedRice, CoffeeSouffle, OlivierSalad)
- All 24 tests passing, all examples parse without error
2026-05-18 22:59:44 -04:00
jbrechtel b5482d8785 Phase 3: End-of-line and inline block comment parsing
- Add pEndComment parser for -- end-of-line comments
- Add pInlineComment parser for [- ... -] block comments
- Update pText to stop before -- and [- sequences using notFollowedBy
- Add tests for both comment types (2 new tests, 19 total)
2026-05-18 22:58:01 -04:00
jbrechtel e63aeedc39 Phase 2: Ingredient, cookware, and timer parsing
- Add ingredient parser: @name{quantity%unit}(preparation)
  - Handles single-word names without braces
  - Handles multi-word names with braces
  - Handles quantity (with unit) and preparation text
- Add cookware parser: #name or #multi word name{}
  - Uses shared pNameWithBraces helper
- Add timer parser: ~name{duration%unit} or ~{duration%unit}
  - Separate named/unnamed timer branches for correct brace handling
- Add quantity parsing: {2}, {1%kg}, {1/2%tbsp}, {=1%tsp}
  - Handles simple integers, fractions (1/2), compound (1,1/2)
- Extract shared pNameWithQuantity and pNameWithBraces helpers
- Update EasyPancakes tests to verify ingredient/cookware/timer parsing
- All 17 tests passing
2026-05-18 22:51:24 -04:00
jbrechtel 30dd268f2c Phase 1: Model update + file-level parser (text-only steps)
- Update Roux.Types: add SectionBodyItem (SecStep/SecComment/SecNote),
  StepEndComment, remove StepNote (notes are now section-level)
- Rewrite Roux.Parser using Parsec for inline elements, text-splitting
  for file-level structure
- Handle full-line -- comments, > notes, = Name = section headers
- Handle = Name (w/ and w/o closing =), == Name == variations
- Handle end-of-line backslash line breaks within steps
- Update tests to match new model + 3 EasyPancakes integration tests
- Add expectTextStep helper at module level
2026-05-18 22:41:38 -04:00
jbrechtel 9759a4c3a3 Add fourmolu + hlint with scripts and git hooks (Atlas-style)
- Create scripts/build, scripts/test, scripts/run, scripts/install-hooks
- Create git-hooks/pre-commit (auto-format staged .hs files)
- Create git-hooks/pre-push (check formatting + hlint before push)
- Handle git worktrees correctly in hook installation
- Run fourmolu on all source files to fix existing formatting
2026-05-18 22:24:59 -04:00
jbrechtel 235adce596 Add minimal Cooklang parser with first tests
- Create Roux.Parser with parseCookFile (splits paragraphs, treats
  each as a plain-text step, no metadata parsing yet)
- Add emptyMetadata to Roux.Types for convenience
- Add test dependencies: hspec, tasty-golden, tasty-hspec
- Add ParserSpec with 4 tests covering single step, multiple steps,
  empty input, and whitespace trimming
- Wire ParserSpec into test runner via tasty-hspec
2026-05-18 22:21:32 -04:00
jbrechtel e907a03b09 Define Cooklang data model and add DerivingStrategies + containers deps
- Add full Cooklang (.cook) recipe data model to Roux.Types:
  Recipe, Section, Step, StepItem (with StepText/StepIngredient/
  StepCookware/StepTimer/StepRecipeRef/StepNote/StepComment/StepBreak),
  Ingredient, Cookware, Timer, RecipeRef, Quantity, Duration, Metadata
- Enable DerivingStrategies extension project-wide
- Add containers to build dependencies
2026-05-18 22:15:21 -04:00
jbrechtel 130dc5326d Haskell project 2026-05-18 22:00:30 -04:00