Skip to content

feat: YAML validation, NRE fix, Cookbook, llms updates#7

Merged
RoboNET merged 17 commits intomainfrom
feat/yaml-validation-cookbook-llms
Mar 8, 2026
Merged

feat: YAML validation, NRE fix, Cookbook, llms updates#7
RoboNET merged 17 commits intomainfrom
feat/yaml-validation-cookbook-llms

Conversation

@RoboNET
Copy link
Copy Markdown
Owner

@RoboNET RoboNET commented Mar 8, 2026

Summary

  • YAML property validation — unknown properties in templates now throw TemplateParseException with Levenshtein-based "Did you mean?" suggestions (e.g., colourcolor)
  • NRE fix — guard for null _imageLoader in RenderingEngine, pass _defaultRenderOptions to RenderToBitmapCore in async render overloads
  • Cookbook — 9 practical recipes in docs/wiki/Cookbook.md (receipts, labels, tickets, NDC content, QR codes, conditional/multi-language)
  • llms updatesllms.txt and llms-full.txt updated with async-only API, YAML validation, and Cookbook references

Test plan

  • 2753/2753 tests pass on net10.0
  • 2752/2753 on net8.0 (1 pre-existing flaky NDC test)
  • Build: 0 errors, 0 warnings
  • 25 new tests for unknown property validation

RoboNET added 17 commits March 8, 2026 20:26
- Add YAML property validation with Levenshtein "Did you mean?" suggestions
- Fix NRE in render pipeline (null-suppression on _imageLoader)
- Fix SkiaRenderer passing _defaultRenderOptions to RenderToBitmapCore
- Add Cookbook wiki page with 9 practical recipes
- Update llms.txt and llms-full.txt with async API, validation, and cookbook info
- Add Quick Start section with common CLI rendering commands
- Add CLI examples to every existing recipe
- Add Images section with 4 recipes: local file, HTTP, base64, fit modes
- Document base64 vs data: URI MIME type requirements
- ContentSourceResolver now delegates all URI resolution to loaders
- Base64ResourceLoader handles data:, data://, base64:, base64:// schemes
- FileResourceLoader uses generic URI scheme detection instead of blacklist
- FileResourceLoader supports file:, file://, file:/// prefixes
- base64: is a shorthand alias for data:application/octet-stream;base64,...
- Cookbook: add CLI commands and image source recipes
Prevent path traversal attacks by blocking absolute paths and verifying
resolved paths stay within the configured BasePath directory.
Reflect new URI scheme support, absolute path security, and
ContentSourceResolver delegation to IResourceLoader chain.
…ncy)

- Reject URL-encoded characters in FileResourceLoader to prevent path traversal
- Replace bare catch with catch (Exception) in TemplateExpander
- Fix step numbering in ContentSourceResolver
- Make Base64ResourceLoader case-insensitive for base64: prefix matching
…n path

- Add CloneWithSubstitution to each TemplateElement subclass so elements
  own their cloning logic — prevents missed properties when adding new ones
- Add WithSrc for ImageElement/SvgElement, CloneWithChildren for FlexElement
- Delete ContentSourceResolver — inline logic into ExpandContentAsync
- Convert ExpandTable to async, remove all sync expansion duplicates
  (ExpandElements, ExpandElement, ExpandEach, ExpandIf, ExpandFlex)
- Extract WalkElements helper for shared tree traversal in RenderingEngine
- Extract LoadImageCache to deduplicate image preload logic
- Use stackalloc in LevenshteinDistance to avoid heap allocations
- Document case-sensitivity in KnownProperties with improved suggestions
- Preserve Bytes through ExprValue.Resolve/Materialize pipeline
- Re-throw OperationCanceledException in TryLoadBytesFromLoadersAsync
- Fix: FontFamily was not copied in TextElement clone
- Fix: Options was not copied in ContentElement clone
@RoboNET RoboNET merged commit e799854 into main Mar 8, 2026
6 checks passed
@RoboNET RoboNET deleted the feat/yaml-validation-cookbook-llms branch March 8, 2026 20:39
RoboNET added a commit that referenced this pull request Mar 11, 2026
* feat: YAML validation, NRE fix, Cookbook, and llms updates

- Add YAML property validation with Levenshtein "Did you mean?" suggestions
- Fix NRE in render pipeline (null-suppression on _imageLoader)
- Fix SkiaRenderer passing _defaultRenderOptions to RenderToBitmapCore
- Add Cookbook wiki page with 9 practical recipes
- Update llms.txt and llms-full.txt with async API, validation, and cookbook info

* docs(cookbook): add CLI commands and image source recipes

- Add Quick Start section with common CLI rendering commands
- Add CLI examples to every existing recipe
- Add Images section with 4 recipes: local file, HTTP, base64, fit modes
- Document base64 vs data: URI MIME type requirements

* refactor: unify resource loading through IResourceLoader chain

- ContentSourceResolver now delegates all URI resolution to loaders
- Base64ResourceLoader handles data:, data://, base64:, base64:// schemes
- FileResourceLoader uses generic URI scheme detection instead of blacklist
- FileResourceLoader supports file:, file://, file:/// prefixes
- base64: is a shorthand alias for data:application/octet-stream;base64,...
- Cookbook: add CLI commands and image source recipes

* fix(security): reject absolute paths in FileResourceLoader

Prevent path traversal attacks by blocking absolute paths and verifying
resolved paths stay within the configured BasePath directory.

* docs: update resource loader documentation

Reflect new URI scheme support, absolute path security, and
ContentSourceResolver delegation to IResourceLoader chain.

* docs: add ExprValue BytesValue unification design and implementation plan

* feat: add BytesValue property to ExprValue

* feat: resolve BytesValue into ExprValue.Bytes in TemplateExpander

* refactor: ContentSourceResolver uses ExprValue.Bytes instead of TryResolveBytes

* feat: load URI sources into ExprValue.Bytes during template expansion

* feat: PreloadImages uses ExprValue.Bytes, skips loader chain when bytes available

* test: add BytesValue image integration tests

* fix: prevent flaky cache tests by disabling parallel execution

* fix: address code review findings (security, error handling, consistency)

- Reject URL-encoded characters in FileResourceLoader to prevent path traversal
- Replace bare catch with catch (Exception) in TemplateExpander
- Fix step numbering in ContentSourceResolver
- Make Base64ResourceLoader case-insensitive for base64: prefix matching

* docs: add KnownProperties and test parallelism rules to checklists

* refactor: move element cloning into elements, eliminate sync expansion path

- Add CloneWithSubstitution to each TemplateElement subclass so elements
  own their cloning logic — prevents missed properties when adding new ones
- Add WithSrc for ImageElement/SvgElement, CloneWithChildren for FlexElement
- Delete ContentSourceResolver — inline logic into ExpandContentAsync
- Convert ExpandTable to async, remove all sync expansion duplicates
  (ExpandElements, ExpandElement, ExpandEach, ExpandIf, ExpandFlex)
- Extract WalkElements helper for shared tree traversal in RenderingEngine
- Extract LoadImageCache to deduplicate image preload logic
- Use stackalloc in LevenshteinDistance to avoid heap allocations
- Document case-sensitivity in KnownProperties with improved suggestions
- Preserve Bytes through ExprValue.Resolve/Materialize pipeline
- Re-throw OperationCanceledException in TryLoadBytesFromLoadersAsync
- Fix: FontFamily was not copied in TextElement clone
- Fix: Options was not copied in ContentElement clone

* chore: remove completed plans, known-issues, and TODO
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant