18 Commits

Author SHA1 Message Date
jbrechtel 5765829004 refactor: return Either from loadConfig, add Config tests 2026-05-21 10:16:41 -04:00
jbrechtel c33a51d80b test: add step count preservation tests for SchemaOrg → Cooklang conversion
Build and Deploy / build-and-deploy (push) Successful in 1m14s
Adds checkStepCount helper that verifies the number of instructions in
the parsed schema.org recipe matches the number of SecStep items in
the Method section of the resulting Cooklang Recipe. Tests both
fried-rice (4 steps) and carrot-risotto (7 steps).
2026-05-20 15:57:14 -04:00
jbrechtel 3e55f0a7d2 feat: add schemaOrgToCooklang conversion function 2026-05-19 22:50:48 -04:00
jbrechtel 1addddd8fc feat: add parseISODuration for ISO 8601 duration parsing 2026-05-19 22:46:57 -04:00
jbrechtel 9586afcb46 feat: add SchemaOrgRecipe types and FromJSON parsing 2026-05-19 22:44:03 -04:00
jbrechtel 43e1299616 Formats code 2026-05-19 20:21:43 -04:00
jbrechtel f8114af4a9 Add nytToCooklang conversion from NYTRecipe to Data.CookLang.Recipe
- Add nytToCooklang function to Roux.NYTimes
- buildMetadata: maps title, URL, description, time, servings
- buildSections: creates sections for ingredient groups then step groups
- ingredientGroupToSection: converts NYT ingredient items to
  Cooklang step items with @ingredient references
- stepGroupToSection: converts method steps into Cooklang steps
- Add parseDuration, parseServings, parseNYTQuantity helpers
- Add extractIngredientName heuristic for core ingredient extraction
- Add 2 conversion tests verifying both example recipes
- All 32 tests passing, hlint clean
2026-05-19 16:03:43 -04:00
jbrechtel 4055bf62c1 Extract Cooklang types into Data.CookLang module
- Create src/Data/CookLang.hs with all recipe types (Recipe, Section,
  StepItem, Ingredient, Cookware, Timer, RecipeRef, Quantity, Duration,
  Metadata, emptyMetadata)
- Data.CookLang has zero Roux imports — can be extracted to its own
  package
- Roux.Types now just re-exports from Data.CookLang
- Update all Roux.* modules and tests to import Data.CookLang directly
- All 30 tests passing, hlint clean
2026-05-19 15:59:59 -04:00
jbrechtel 21a4cea083 Add NYTimes recipe extraction from __NEXT_DATA__ JSON tag
- Add Roux.NYTimes module with:
  - extractNextData: finds <script id="__NEXT_DATA__"> tag in HTML
    and parses its JSON content via aeson
  - parseNYTRecipe: maps NYTimes recipe JSON structure into a
    typed intermediate representation (NYTRecipe, NYTIngredientGroup,
    NYTIngredientItem, NYTStepGroup, NYTStepItem)
- Supports all NYTimes Cooking data: title, URL, total time, yield,
  topnote, ingredient groups (with section names), step groups
- Add aeson to dependencies
- Add 4 tests: extraction + parsing for both fried-rice and
  carrot-risotto example HTML files
- Wire NYTimesSpec into test runner
2026-05-19 15:51:37 -04:00
jbrechtel 1314c38e85 Commit pending changes: check-recipes tool and reconstructed test file 2026-05-19 13:29:27 -04:00
jbrechtel c55a54796a Fix parser for personal recipes: newlines, ranges, &, markdown-style headings
Three categories of fixes:

1. Multi-line steps: removed \n from pText exclusion list so newlines
   within a step are consumed as regular text
2. Range timers (e.g. ~{14-18%minutes}): handle hyphen-separated
   ranges in parseSimpleRational by taking the lower value
3. & in ingredient names: added & to pSingleNameChar and
   pMultiNameChar char sets
4. Markdown-style # headings: added pAnyChar fallback so # followed
   by invalid cookware name falls through to text consumption
5. Note detection: tightened > check to require >  (with space)
   or > followed by non->, preventing >> metadata from being
   treated as notes
2026-05-19 12:58:43 -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