Skip to content

Commit 6deacde

Browse files
committed
AST
1 parent ab8eb7e commit 6deacde

83 files changed

Lines changed: 4962 additions & 2020 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ Protection marks (CONTENT_MARKUP, CONTENT_REPLACED, etc.) prevent re-processing
9595
- Input Texy source files in `tests/Texy/sources/`
9696
- `tests/bootstrap.php` sets up test environment
9797

98+
**Testing guidelines:**
99+
- **Never use `Assert::contains()`** - it leads to false positives and missed bugs
100+
- **Always test exact output** using `Assert::matchFile()` or `Assert::match()`
101+
- `Assert::match()` ignores line ending differences (`\r\n` vs `\n`)
102+
- Avoid wildcard patterns like `%a%` - test the complete output
103+
- For AST tests, create separate expected files (e.g., `paragraphs-ast.html`)
104+
98105
Example test pattern:
99106
```php
100107
$texy = new Texy\Texy;
@@ -251,7 +258,7 @@ $texy->addHandler('image', function(
251258
**Common elements**: `image`, `linkReference`, `linkEmail`, `linkURL`, `phrase`, `figure`, `heading`, `block`, `emoticon`
252259

253260
### Notification Handlers
254-
Called for side effects (logging, DOM modifications), don't return values:
261+
Called for side effects (logging, modifications), don't return values:
255262

256263
```php
257264
$texy->addHandler('beforeParse', function(
@@ -332,19 +339,63 @@ $texy->registerBlockPattern(
332339

333340
## Protection Marks and Nesting
334341

335-
Texy uses special control characters to prevent re-processing of already-processed content:
342+
Texy uses special control characters to prevent re-processing of already-processed content. These are critical for typography and longwords modules.
343+
344+
### Protection Mark Types
345+
346+
| Mark | Hex | Constant | Usage | In longwords exclusion? |
347+
|------|-----|----------|-------|-------------------------|
348+
| `\x14` | 0x14 | `CONTENT_BLOCK` | Block elements (`<div>`, `<p>`, `<table>`) | YES - splits text processing |
349+
| `\x15` | 0x15 | `CONTENT_TEXTUAL` | Protected text (code, notexy) | YES - skipped entirely |
350+
| `\x16` | 0x16 | `CONTENT_REPLACED` | Replaced elements (`<img>`, `<br>`, URLs, emails) | YES - skipped entirely |
351+
| `\x17` | 0x17 | `CONTENT_MARKUP` | Inline markup (`<strong>`, `<em>`, `<a>`) | NO - text flows through |
352+
353+
### How Protection Works
354+
355+
1. **CONTENT_BLOCK** (`\x14`) - Splits text for post-processing. `invokePostLineHandlers()` uses `explode(CONTENT_BLOCK, $text)` and only processes even-indexed segments.
356+
357+
2. **CONTENT_REPLACED/TEXTUAL** (`\x15`, `\x16`) - Excluded from longwords pattern `[^ \n\t\x14\x15\x16...]`. Content is completely skipped.
336358

337-
- `CONTENT_MARKUP` (\x17) - Regular HTML markup (tags, formatting)
338-
- `CONTENT_REPLACED` (\x16) - Replaced elements (images)
339-
- `CONTENT_TEXTUAL` (\x15) - Escaped/treated text (code blocks)
340-
- `CONTENT_BLOCK` (\x14) - Block elements
359+
3. **CONTENT_MARKUP** (`\x17`) - NOT excluded from longwords. This allows text to flow through inline tags for hyphenation: `<strong>very-long-word</strong>` can be hyphenated.
360+
361+
### Protection Key Format
362+
363+
Protection keys have format: `[TYPE][COUNTER][TYPE]` where:
364+
- TYPE is one of `\x14-\x17`
365+
- COUNTER uses `\x18-\x1F` for octal-encoded digits
366+
367+
Example: `\x17\x18\x17` = CONTENT_MARKUP with counter 0
368+
369+
### Usage in HtmlGenerator
341370

342-
When creating raw HTML strings (not HtmlElement), protect them:
343371
```php
344-
$html = '<iframe src="..."></iframe>';
345-
return $texy->protect($html, Texy\Texy::CONTENT_BLOCK);
372+
// Block elements - use CONTENT_BLOCK
373+
$this->protect("<p>", self::ContentBlock);
374+
375+
// Inline markup - use CONTENT_MARKUP
376+
$this->protect("<strong>", self::ContentMarkup);
377+
378+
// Replaced elements - use CONTENT_REPLACED
379+
$this->protect("<img ...>", self::ContentReplaced);
380+
381+
// Protected text - use CONTENT_TEXTUAL
382+
$this->protect($codeContent, self::ContentTextual);
383+
```
384+
385+
## Space Freezing in Attributes
386+
387+
To prevent line wrapping inside HTML attributes, spaces are "frozen" using `Helpers::freezeSpaces()`:
388+
389+
```php
390+
// Freezes spaces: " " → \x01, "\t" → \x02, "\r" → \x03, "\n" → \x04
391+
$value = Helpers::freezeSpaces($attrValue);
392+
393+
// At the end, unfreeze: \x01 → " ", etc.
394+
$html = Helpers::unfreezeSpaces($html);
346395
```
347396

397+
This ensures that `alt="long description with spaces"` won't be broken across lines by the formatter.
398+
348399
**Patterns** should exclude already-processed content: `[^\x14-\x1F]` excludes all protected content.
349400

350401
## Key Architectural Concepts
@@ -365,20 +416,26 @@ return $texy->protect($html, Texy\Texy::CONTENT_BLOCK);
365416
Modifiers add attributes: `.(title)[class #id]{style:value}<align>^valign`
366417

367418
```php
368-
// Parsing
369-
$mod = new Texy\Modifier($modifierText);
419+
// Parsing (use static factory method)
420+
$mod = Texy\Modifier::parse($modifierText);
421+
$mod = Texy\Modifier::parse($modifierText, $offset); // with position tracking
370422

371423
// Access
372424
$mod->id; // HTML id
373425
$mod->classes; // array of classes
374426
$mod->styles; // array of CSS properties
427+
$mod->attrs; // custom attributes (data-*, aria-*, etc.)
375428
$mod->hAlign; // left, right, center, justify
429+
$mod->vAlign; // top, middle, bottom
376430
$mod->title; // title attribute
431+
$mod->position; // Position object
377432

378-
// Apply to element
433+
// Apply to element (legacy, deprecated)
379434
$mod->decorate($texy, $element);
380435
```
381436

437+
**Note:** Constructor `new Modifier($text)` and `setProperties()` are deprecated. Use `Modifier::parse()` instead.
438+
382439
## Security Practices
383440

384441
Always use `Configurator::safeMode()` for user-generated content. It:

0 commit comments

Comments
 (0)