Skip to content

Conversation

@shsteimer
Copy link
Owner

Overview

This PR adds HTL/Sightly compatibility improvements to make Faintly more familiar to developers with HTL background.

New Features

1. Optional ${} syntax in directives

  • Directives now accept both bare expressions and ${} wrapped expressions
  • data-fly-test="condition" and data-fly-test="${condition}" both work
  • Maintains backward compatibility with existing code
  • Regular attributes and text content still require ${} (unchanged)

2. JavaScript expression evaluation with utils:eval()

  • Support for complex JavaScript expressions in templates
  • Comparisons: >, <, >=, <=, ===, !==
  • Logical operators: &&, ||, !
  • Ternary operator: condition ? true : false
  • String/Array methods: .toUpperCase(), .toLowerCase(), .join(), etc.
  • Arithmetic operations: +, -, *, /, %
  • Includes proper CAUTION warnings about eval and CSP requirements

3. HTL Migration Documentation

  • Created comprehensive docs/HTL_MIGRATION.md
  • Quick reference section with syntax and directive cheat sheets
  • Detailed explanations of key differences
  • 6 common migration patterns with side-by-side examples
  • Coverage of all HTL directives including <sly> tag
  • Linked from README.md

Testing

  • ✅ 165 tests passing (70 new tests added)
  • ✅ 100% code coverage maintained
  • ✅ All linting checks passed
  • ✅ Bundle size constraints met (core: 2804 bytes, combined: 3450 bytes)

Version

  • Bumped from 1.1.0 → 1.2.0 (minor version for new features)

Breaking Changes

  • None - all changes are backwards compatible

… utils:eval()

- #1: Make ${} optional in data-fly-* directives for HTL familiarity
- #2: Create HTL migration documentation explaining key differences
- #3: Add utils:eval() for JavaScript expressions (future consideration)
  - Uses new Function() for full JS power (~150 bytes)
  - Appropriately scary naming with 'eval' to warn developers
  - CSP requires unsafe-eval policy
  - Removed data-fly-use (not needed - context functions work better)
  - Removed context options (DOM manipulation doesn't need HTL's escaping)
Add support for both bare and ${}-wrapped expressions in data-fly-* directives.

Changes:
- Add unwrapExpression() in expressions.js to strip ${} wrapper
- Apply unwrapping to all directive processors (test, repeat, content, attributes, unwrap)
- Add comprehensive tests for unwrapExpression (13 new tests)
- Add tests for ${} syntax in all directive types (9 new tests)
- Update README to document both syntax styles
- Maintain 100% test coverage (117 tests passing)

Bundle size: 2729 bytes core / 3375 bytes total (well within limits)

For HTL/Sightly users, directives now accept both syntaxes:
  data-fly-test="condition" and data-fly-test="${condition}"

Regular attributes still require ${}: class="${myClass}"
- Add evaluate() function in src/expressions.js using Function constructor
- Detect and handle utils:eval() syntax in resolveExpression()
- Update regex to [^}]+] for consistent escaping behavior
- Add 70 comprehensive tests for utils:eval() covering:
  - Comparisons, logical operators, ternary
  - String/array methods, arithmetic, object access
  - Custom helper functions, error handling
  - Whitespace handling, edge cases
- Add 15 tests documenting operator-without-eval behavior
- Update README with:
  - Prominent CAUTION warning about eval and CSP requirements
  - Clear examples of what requires vs doesn't require utils:eval()
  - Guidance on when to use utils:eval() vs context functions
- Update HTL_COMPATIBILITY_PLAN with implementation results
- 187 tests passing with 100% coverage maintained
- Bundle: 2811 bytes core (+82 bytes), 3457 bytes combined
- All under size limits (4KB core, 6KB combined)
- Created comprehensive HTL_MIGRATION.md in docs/ folder
- Added quick reference section at top with syntax and directive mappings
- Documented key differences between HTL and Faintly
- Covered expression syntax, backend integration, context options
- Included 6 common migration patterns with examples
- Added link to migration guide in README.md
- Removed HTL_COMPATIBILITY_PLAN.md (implementation complete)
- Tests use real CSP meta tag that blocks unsafe-eval
- Demonstrates all utils:eval() expressions fail under CSP restrictions
- Shows that non-eval expressions (property paths, context functions) still work
- No mocking needed - uses actual browser CSP enforcement
Runs clean, build:strict, lint, and test in sequence
Simplifies CI pipeline by using single verify command instead of separate lint, test, build:strict steps
- Move expression syntax test out of security integration section
- Remove redundant security initialization test
- Clean up test structure for better organization
- Create wtr-single.config.mjs for running specific test files
- Add 'npm run test:file' script that accepts file paths or globs
- Update AGENTS.md with instructions on how to run individual tests
- Document that npm test -- --files doesn't work with group configs
- Add test/security/xss-vectors.test.js with 29 XSS attack vector tests
  - Event handler injection (onclick, onerror, etc.)
  - JavaScript/VBScript/file: URL schemes
  - Data URI injection
  - srcdoc attributes
  - Content injection via strings
  - Expression injection
  - SVG-based XSS, form actions, edge cases
  - All tests pass, 100% coverage maintained

- Add docs/SECURITY.md with comprehensive security guide
  - Security modes table (Default, Custom, Unsafe)
  - Configuration options table
  - Security model and trust boundaries
  - Best practices with utils:eval() warning
  - Custom security hooks
  - Clear, concise, scannable format (220 lines)

- Update README.md security section
  - Add 'What's NOT protected' list
  - Add utils:eval() security warning
  - Link to detailed SECURITY.md documentation
  - Keep high-level and concise

All 226 tests pass with 100% coverage. Build: 3457 bytes (under 6KB limit).
Critical security documentation improvements:

1. Add expression-injection.test.js (6 tests)
   - Documents that expressions CAN be injected if user controls HTML
   - Tests innerHTML, setAttribute, and text node injection vectors
   - Shows context-only usage is safe
   - Demonstrates attack scenarios

2. Document utils:eval() has full global access
   - Update README.md and SECURITY.md to clarify it uses Function + with()
   - State explicitly it accesses window, document, and all browser globals
   - Provide concrete attack examples (window.location, document.cookie)
   - Emphasize never use with untrusted data

3. Add critical DANGER warnings
   - README.md: Never allow user input in templates/HTML
   - SECURITY.md: User input must ONLY go in context, never templates
   - Clear guidance: no innerHTML, setAttribute, or template files with user content

Security Model Summary:
- Templates/HTML are TRUSTED (expressions are evaluated)
- Context data is TRUSTED (but sanitized when used in attributes)
- User input must be validated before context AND never in templates

All 232 tests pass with 100% coverage.
@shsteimer shsteimer merged commit 399bbd9 into main Oct 30, 2025
1 check passed
@shsteimer shsteimer deleted the htl-compatibility-improvements branch October 30, 2025 20:56
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.

2 participants