quarc/cli/ARCHITECTURE.md

287 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Architektura CLI
## Przegląd
System CLI składa się z dwóch głównych komponentów:
- **Processors** - Transformują kod źródłowy (template, style, DI)
- **Helpers** - Przetwarzają szczegółowe aspekty szablonów (atrybuty Angular)
## Diagram Architektury
```
┌─────────────────────────────────────────────────────────────┐
│ Build Process │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Lite Transformer │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Processor Pipeline │ │
│ │ │ │
│ │ 1. ClassDecoratorProcessor │ │
│ │ └─ Process class decorators │ │
│ │ │ │
│ │ 2. SignalTransformerProcessor │ │
│ │ ├─ Transform signal calls (input, output, etc.) │ │
│ │ ├─ Add 'this' as first argument │ │
│ │ └─ Ensure _nativeElement in constructor │ │
│ │ │ │
│ │ 3. TemplateProcessor │ │
│ │ ├─ Read template file │ │
│ │ ├─ Transform control flow (@if → *ngIf) │ │
│ │ ├─ Parse HTML (TemplateParser) │ │
│ │ ├─ Process attributes (AttributeHelpers) │ │
│ │ ├─ Reconstruct HTML │ │
│ │ └─ Escape template string │ │
│ │ │ │
│ │ 4. StyleProcessor │ │
│ │ ├─ Read style files │ │
│ │ └─ Inline styles │ │
│ │ │ │
│ │ 5. DIProcessor │ │
│ │ └─ Add __di_params__ metadata │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Transformed Source │
└─────────────────────────────────────────────────────────────┘
```
## Szczegółowy Przepływ TemplateProcessor
```
Template File (HTML)
┌──────────────────────┐
│ transformControlFlow │ @if/@else → *ngIf
└──────────────────────┘
┌──────────────────────┐
│ TemplateParser │ HTML → Element Tree
└──────────────────────┘
┌──────────────────────────────────────────────────────┐
│ Attribute Processing Loop │
│ │
│ For each element: │
│ For each attribute: │
│ ┌────────────────────────────────────────────┐ │
│ │ Find matching AttributeHelper │ │
│ │ │ │
│ │ • StructuralDirectiveHelper (*ngIf) │ │
│ │ • InputBindingHelper ([property]) │ │
│ │ • OutputBindingHelper ((event)) │ │
│ │ • TwoWayBindingHelper ([(model)]) │ │
│ │ • TemplateReferenceHelper (#ref) │ │
│ └────────────────────────────────────────────┘ │
│ │
│ Process attribute → Update element tree │
└──────────────────────────────────────────────────────┘
┌──────────────────────┐
│ reconstructTemplate │ Element Tree → HTML
└──────────────────────┘
┌──────────────────────┐
│ escapeTemplateString │ Escape \, `, $
└──────────────────────┘
Inline Template String
```
## Hierarchia Klas
### Processors
```
BaseProcessor (abstract)
├── ClassDecoratorProcessor
├── SignalTransformerProcessor
├── TemplateProcessor
│ ├── parser: TemplateParser
│ └── attributeHelpers: BaseAttributeHelper[]
├── StyleProcessor
└── DIProcessor
```
### Helpers
```
BaseAttributeHelper (abstract)
├── StructuralDirectiveHelper
│ └── Handles: *ngIf, *ngFor, *ngSwitch
├── InputBindingHelper
│ └── Handles: [property]
├── OutputBindingHelper
│ └── Handles: (event)
├── TwoWayBindingHelper
│ └── Handles: [(model)]
└── TemplateReferenceHelper
└── Handles: #ref
```
## Interfejsy Danych
### ProcessorContext
```typescript
{
filePath: string; // Ścieżka do pliku źródłowego
fileDir: string; // Katalog pliku
source: string; // Zawartość pliku
}
```
### ParsedElement
```typescript
{
tagName: string; // Nazwa tagu HTML
attributes: ParsedAttribute[]; // Lista atrybutów
children: (ParsedElement | ParsedTextNode)[]; // Elementy potomne i text nodes
textContent?: string; // Zawartość tekstowa (legacy)
}
```
### ParsedTextNode
```typescript
{
type: 'text'; // Identyfikator typu
content: string; // Zawartość tekstowa z białymi znakami
}
```
### ParsedAttribute
```typescript
{
name: string; // Nazwa atrybutu
value: string; // Wartość atrybutu
type: AttributeType; // Typ atrybutu
}
```
### AttributeType (enum)
```typescript
STRUCTURAL_DIRECTIVE // *ngIf, *ngFor
INPUT_BINDING // [property]
OUTPUT_BINDING // (event)
TWO_WAY_BINDING // [(model)]
TEMPLATE_REFERENCE // #ref
REGULAR // class, id, etc.
```
## Rozszerzalność
### Dodawanie Nowego Processora
```typescript
export class CustomProcessor extends BaseProcessor {
get name(): string {
return 'custom-processor';
}
async process(context: ProcessorContext): Promise<ProcessorResult> {
// Implementacja transformacji
return { source: context.source, modified: false };
}
}
```
### Dodawanie Nowego Helpera
```typescript
export class CustomAttributeHelper extends BaseAttributeHelper {
get supportedType(): string {
return 'custom';
}
canHandle(attribute: ParsedAttribute): boolean {
// Logika wykrywania
return attribute.name.startsWith('custom-');
}
process(context: AttributeProcessingContext): AttributeProcessingResult {
// Logika przetwarzania
return { transformed: true };
}
}
```
## Wzorce Projektowe
### Strategy Pattern
- **BaseAttributeHelper** - Interfejs strategii
- **Concrete Helpers** - Konkretne strategie dla różnych typów atrybutów
- **TemplateProcessor** - Kontekst używający strategii
### Visitor Pattern
- **TemplateParser.traverseElements()** - Odwiedzanie elementów drzewa
- **Callback function** - Visitor wykonujący operacje na elementach
### Pipeline Pattern
- **Processor chain** - Sekwencyjne przetwarzanie przez kolejne procesory
- Każdy processor otrzymuje wynik poprzedniego
### Factory Pattern
- **Constructor TemplateProcessor** - Tworzy instancje wszystkich helperów
- Centralizacja tworzenia zależności
## Wydajność
### Optymalizacje
1. **Single-pass parsing** - Jeden przebieg przez szablon
2. **Lazy evaluation** - Przetwarzanie tylko zmodyfikowanych plików
3. **Reverse iteration** - Unikanie problemów z offsetami przy zamianie
### Złożoność
- **Parsing**: O(n) gdzie n = długość szablonu
- **Attribute processing**: O(m × h) gdzie m = liczba atrybutów, h = liczba helperów
- **Reconstruction**: O(e + t) gdzie e = liczba elementów, t = liczba text nodes
### Obsługa Text Nodes
Parser automatycznie wykrywa i zachowuje text nodes jako osobne węzły:
- Text nodes mogą występować na poziomie root lub jako dzieci elementów
- Zachowują wszystkie białe znaki (spacje, nowe linie, tabulatory)
- Są pomijane przez `traverseElements()` (tylko elementy HTML)
- Są prawidłowo rekonstruowane podczas budowania HTML
- Używają type guard `isTextNode()` do rozróżnienia od elementów
## Testowanie
### Unit Tests
```typescript
// Test parsera
const parser = new TemplateParser();
const result = parser.parse('<div [title]="value"></div>');
expect(result[0].attributes[0].type).toBe(AttributeType.INPUT_BINDING);
// Test helpera
const helper = new InputBindingHelper();
expect(helper.canHandle({ name: '[title]', value: 'x', type: AttributeType.INPUT_BINDING })).toBe(true);
```
### Integration Tests
```typescript
// Test całego procesora
const processor = new TemplateProcessor();
const result = await processor.process({
filePath: '/test/component.ts',
fileDir: '/test',
source: 'templateUrl = "./template.html"'
});
expect(result.modified).toBe(true);
```
## Dokumentacja
- **[processors/README.md](./processors/README.md)** - Dokumentacja procesorów
- **[helpers/README.md](./helpers/README.md)** - Dokumentacja helperów
- **[helpers/example.md](./helpers/example.md)** - Przykłady użycia