quarc/cli/helpers/example.md

5.9 KiB

Przykład Użycia Template Helpers

Przykład 1: Podstawowe Parsowanie

import { TemplateParser } from './template-parser';

const parser = new TemplateParser();
const template = `
<div class="container">
    <h1 [title]="pageTitle">{{ title }}</h1>
    <button (click)="save()">Save</button>
</div>
`;

const elements = parser.parse(template);
console.log(elements);
// Output: Drzewo elementów z wyodrębnionymi atrybutami i text nodes

Przykład 1b: Parsowanie z Text Nodes

import { TemplateParser } from './template-parser';

const parser = new TemplateParser();
const template = `
    Some text before
    <div>Inside div</div>
    Some text after
`;

const elements = parser.parse(template);

for (const node of elements) {
    if ('type' in node && node.type === 'text') {
        console.log('Text node:', node.content.trim());
    } else {
        console.log('Element:', node.tagName);
    }
}

// Output:
// Text node: Some text before
// Element: div
// Text node: Some text after

Przykład 2: Przetwarzanie Atrybutów

import { TemplateParser } from './template-parser';
import { InputBindingHelper } from './input-binding-helper';

const parser = new TemplateParser();
const inputHelper = new InputBindingHelper();

const template = '<div [title]="myTitle">Content</div>';
const elements = parser.parse(template);

parser.traverseElements(elements, (element) => {
    for (const attr of element.attributes) {
        if (inputHelper.canHandle(attr)) {
            const result = inputHelper.process({
                element,
                attribute: attr,
                filePath: 'example.component.html',
            });

            console.log('Processed:', result);
        }
    }
});

Przykład 3: Transformacja Control Flow

Wejście:

@if (isLoggedIn) {
    <p>Welcome back!</p>
} @else if (isGuest) {
    <p>Welcome guest!</p>
} @else {
    <p>Please log in</p>
}

Wyjście po transformacji:

<ng-container *ngIf="isLoggedIn">
    <p>Welcome back!</p>
</ng-container>
<ng-container *ngIf="!(isLoggedIn) && isGuest">
    <p>Welcome guest!</p>
</ng-container>
<ng-container *ngIf="!(isLoggedIn) && !(isGuest)">
    <p>Please log in</p>
</ng-container>

Przykład 4: Kompletny Szablon

Wejście:

<div class="user-profile">
    <h1 [title]="user.fullName">{{ user.name }}</h1>

    @if (user.isAdmin) {
        <span class="badge">Admin</span>
    }

    <form>
        <input [(ngModel)]="user.email" #emailInput type="email" />
        <button (click)="saveUser()">Save</button>
    </form>

    <ul *ngFor="let post of user.posts">
        <li [class.active]="post.isActive">{{ post.title }}</li>
    </ul>
</div>

Po przetworzeniu przez TemplateProcessor:

<div class="user-profile">
    <h1 [title]="user.fullName">{{ user.name }}</h1>

    <ng-container *ngIf="user.isAdmin">
        <span class="badge">Admin</span>
    </ng-container>

    <form>
        <input [(ngModel)]="user.email" #emailInput type="email" />
        <button (click)="saveUser()">Save</button>
    </form>

    <ul *ngFor="let post of user.posts">
        <li [class.active]="post.isActive">{{ post.title }}</li>
    </ul>
</div>

Przykład 5: Własny Helper

import { BaseAttributeHelper, AttributeProcessingContext, AttributeProcessingResult } from './base-attribute-helper';
import { AttributeType, ParsedAttribute } from './template-parser';

export class DataAttributeHelper extends BaseAttributeHelper {
    get supportedType(): string {
        return 'data-attribute';
    }

    canHandle(attribute: ParsedAttribute): boolean {
        return attribute.name.startsWith('data-');
    }

    process(context: AttributeProcessingContext): AttributeProcessingResult {
        // Konwersja data-* atrybutów na format Angular
        const dataName = context.attribute.name.replace('data-', '');

        return {
            transformed: true,
            newAttribute: {
                name: `[attr.data-${dataName}]`,
                value: context.attribute.value,
                type: AttributeType.INPUT_BINDING,
            },
        };
    }
}

// Użycie w TemplateProcessor:
// this.attributeHelpers.push(new DataAttributeHelper());

Przykład 6: Debugowanie

import { TemplateParser } from './template-parser';

const parser = new TemplateParser();
const template = '<div [title]="value" (click)="handler()">Text</div>';

const elements = parser.parse(template);

parser.traverseElements(elements, (element) => {
    console.log(`Element: ${element.tagName}`);
    console.log(`Attributes count: ${element.attributes.length}`);

    element.attributes.forEach(attr => {
        console.log(`  ${attr.name} [${attr.type}] = "${attr.value}"`);
    });

    if (element.textContent) {
        console.log(`  Text: ${element.textContent}`);
    }
});

// Output:
// Element: div
// Attributes count: 2
//   [title] [input] = "value"
//   (click) [output] = "handler()"
//   Text: Text

Przykład 7: Wykrywanie Wszystkich Typów Atrybutów

import { TemplateParser, AttributeType } from './template-parser';

const parser = new TemplateParser();
const template = `
<div class="container"
     *ngIf="show"
     [title]="tooltip"
     (click)="onClick()"
     [(ngModel)]="value"
     #myDiv>
    Content
</div>
`;

const elements = parser.parse(template);
const attributeTypes = new Map<AttributeType, number>();

parser.traverseElements(elements, (element) => {
    element.attributes.forEach(attr => {
        const count = attributeTypes.get(attr.type) || 0;
        attributeTypes.set(attr.type, count + 1);
    });
});

console.log('Attribute type statistics:');
attributeTypes.forEach((count, type) => {
    console.log(`  ${type}: ${count}`);
});

// Output:
// Attribute type statistics:
//   regular: 1
//   structural: 1
//   input: 1
//   output: 1
//   two-way: 1
//   reference: 1