Conversation
Replace str_replace('"', '\"', $val) with proper encoding of & and
" characters in quoted attribute values. This produces valid HTML output
where & is rendered as & and " as ".
Update existing test expectations to match the corrected output.
Closes #77
…ames setAttribute() now throws InvalidArgumentException when a structurally invalid attribute name is passed (e.g., names with spaces, quotes, =). Previously these were silently discarded. The TemplateCompiler uses a safeSetAttribute() helper to gracefully skip invalid names encountered during HTML parsing. Closes #76
Wrap the ob_start/require/ob_get_clean sequence in a try-catch block. If the template throws, ob_end_clean() is called before re-throwing the exception, preventing a permanently leaked output buffer. Closes #59
Use a static closure to execute the template require, preventing templates from accessing the TemplateCompiler instance via $this. Also eliminates variable name collisions by using __ prefixed names for internal variables. Closes #62
Replace manual $rows and $cols counters with methods that read from the actual DOM state. rows() returns childrenCount() and cols() returns the first row's child count. This eliminates desync when rows are added or removed via addRow() or inherited methods. Closes #71
Extend the existing <?php escaping to also handle <?= (short echo) and <? (short open tag) before splitting on <. This prevents InvalidNodeNameException when these sequences appear in parsed text. Closes #60
Copy attributes from parsed <html> and <body> elements to the HTMLDoc instance in parseHTMLDoc(). Previously these attributes (lang, dir, class, id, etc.) were silently discarded. Closes #56
Change the script content extraction regex from a fixed lookbehind (?<=<script>) to a capturing group <script[^>]*>(.*?)</script>. This correctly handles script tags with attributes like type or src, preventing their content from being corrupted by the HTML parser. Closes #55
Replace restricted ASCII character class [\t-!#-~] in attribute value regex with [^"]* (and [^']* for single quotes). This correctly matches UTF-8 multibyte characters and prevents > inside quoted attribute values from being interpreted as the tag closing delimiter. Closes #58
Extract comment bodies that contain < into placeholders before the
explode('<', ...) split, preserving the <!-- --> wrapper so the parser
still recognizes them as comment nodes. Only comments with < are
replaced to avoid disrupting normal comment parsing.
Closes #63
Fix array_indentation rule in php_cs.php.dist (was passed empty array instead of true). Run php-cs-fixer on all source files.
fix: resolve 10 bugs in HTMLNode, HTMLTable, and TemplateCompiler
Replace LinkedList (O(n) index access) with Vector (O(1) index access) for the internal children list. This eliminates O(n²) patterns in rendering, ID searches, and tag searches. Benchmarks with 1000 children: - toHTML(): 9x faster (134ms → 15ms) - getChildByID(): 35x faster (239ms → 7ms) - index-based loop: 363x faster (105ms → 0.3ms) BREAKING CHANGE: children() now returns Vector instead of LinkedList. Code that type-hints LinkedList for children() return must update. Closes #66
perf!: replace LinkedList with Vector for child node storage
Add HtmlRenderer class with per-instance rendering configuration (formatted, quoted, useForwardSlash). This eliminates shared mutable static state in the rendering path, making it safe for concurrent use in async contexts (Swoole, ReactPHP, RoadRunner). The renderer can be used standalone: $renderer = new HtmlRenderer(formatted: true, quoted: true); echo $renderer->render($node); Existing toHTML()/toXML() methods on HTMLNode remain unchanged for backward compatibility. 100% test coverage on HtmlRenderer (92 lines, 11 methods). Closes #64 Closes #61
refactor: extract rendering logic into dedicated HtmlRenderer class
Add three new static methods that wrap fromFile() with explicit return types and fail-fast validation: - fromFileAsDocument(): returns HTMLDoc, throws if not a full document - fromFileAsNode(): returns HTMLNode, throws if multiple roots or empty - fromFileAsArray(): returns array, always succeeds by normalizing The existing fromFile() remains unchanged for backward compatibility. Closes #65
feat(HTMLNode): add type-specific factory methods for template loading
Align README with the WebFiori ecosystem standard (webfiori/collections): - Plain markdown headers (no emoji) - Centered badges with PHP 8.1+ badge - Table of Contents - Supported PHP Versions table - Key Features bullet list - Quick Start with working example - Testing, Contributing, License, Support, Changelog sections Closes #54
Add self-contained, runnable examples following the webfiori/database pattern (folder per example with README.md and example.php): - 01-basic-document: Complete HTML5 document creation - 02-elements-and-attributes: Chaining, styles, iteration - 03-forms-and-input: Form building with various input types - 04-tables: Table creation and dynamic columns - 05-html-templates: Slot-based HTML templates - 06-php-templates: PHP templates with logic - 07-standalone-renderer: HtmlRenderer per-instance config - 08-xml-output: XML generation
When an HTMLNode instance is passed as a slot value, render it as raw
HTML instead of escaping it. String values remain escaped via
htmlspecialchars() for XSS safety.
Usage:
$badge = new HTMLNode('span', ['class' => 'badge']);
$badge->text('New');
$card = HTMLNode::fromFileAsNode('card.html', ['title' => $badge]);
docs: standardize README.md structure
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #83 +/- ##
============================================
+ Coverage 98.44% 98.48% +0.04%
- Complexity 898 979 +81
============================================
Files 6 7 +1
Lines 1799 1981 +182
============================================
+ Hits 1771 1951 +180
- Misses 28 30 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Merge all development work from
devintomainfor release.Changes Included
Testing
All tests pass (362 tests, 1083 assertions) across PHP 8.1–8.5.
Breaking Changes
children()returnsVectorinstead ofLinkedListsetAttribute()throwsInvalidArgumentExceptionfor invalid names&now render as&,"as"HTMLTable::rows()/cols()derive from DOM state, not counters