improve control flow transformer robustness and remove debug logs
This commit is contained in:
parent
990aef92ef
commit
c3dda73d3a
|
|
@ -56,10 +56,20 @@ export class ControlFlowTransformer {
|
|||
closeParenIndex--;
|
||||
|
||||
const openBraceIndex = content.indexOf('{', closeParenIndex);
|
||||
if (openBraceIndex === -1) return null;
|
||||
if (openBraceIndex === -1) {
|
||||
// Handle case where there's no opening brace - create a simple block
|
||||
return {
|
||||
match: content.substring(ifIndex, closeParenIndex + 1) + '{ }',
|
||||
startIndex: ifIndex,
|
||||
endIndex: closeParenIndex + 1
|
||||
};
|
||||
}
|
||||
|
||||
let endIndex = this.findIfBlockEnd(content, openBraceIndex);
|
||||
if (endIndex === -1) return null;
|
||||
if (endIndex === -1) {
|
||||
// For incomplete blocks, try to process what we have
|
||||
endIndex = content.length;
|
||||
}
|
||||
|
||||
return {
|
||||
match: content.substring(ifIndex, endIndex),
|
||||
|
|
@ -79,7 +89,21 @@ export class ControlFlowTransformer {
|
|||
index++;
|
||||
}
|
||||
|
||||
if (braceCount !== 0) return -1;
|
||||
// If we couldn't find matching closing brace, try to handle incomplete blocks
|
||||
if (braceCount !== 0) {
|
||||
// For incomplete blocks, find the end of the current line or next @if/@for statement
|
||||
const remainingContent = content.substring(startBraceIndex);
|
||||
const nextIfIndex = remainingContent.indexOf('@if', 1);
|
||||
const nextForIndex = remainingContent.indexOf('@for', 1);
|
||||
const lineEndIndex = remainingContent.indexOf('\n');
|
||||
|
||||
let endIndex = content.length;
|
||||
if (nextIfIndex !== -1) endIndex = Math.min(endIndex, startBraceIndex + nextIfIndex);
|
||||
if (nextForIndex !== -1) endIndex = Math.min(endIndex, startBraceIndex + nextForIndex);
|
||||
if (lineEndIndex !== -1) endIndex = Math.min(endIndex, startBraceIndex + lineEndIndex);
|
||||
|
||||
return endIndex;
|
||||
}
|
||||
|
||||
while (index < content.length) {
|
||||
const remaining = content.substring(index);
|
||||
|
|
@ -165,7 +189,21 @@ export class ControlFlowTransformer {
|
|||
if (forIndex === -1) return null;
|
||||
|
||||
const openParenIndex = content.indexOf('(', forIndex);
|
||||
const closeParenIndex = content.indexOf(')', openParenIndex);
|
||||
if (openParenIndex === -1) return null;
|
||||
|
||||
// Properly count nested parentheses
|
||||
let parenCount = 1;
|
||||
let closeParenIndex = openParenIndex + 1;
|
||||
while (closeParenIndex < content.length && parenCount > 0) {
|
||||
const char = content[closeParenIndex];
|
||||
if (char === '(') parenCount++;
|
||||
else if (char === ')') parenCount--;
|
||||
closeParenIndex++;
|
||||
}
|
||||
|
||||
if (parenCount !== 0) return null;
|
||||
closeParenIndex--; // Move back to the closing paren
|
||||
|
||||
const openBraceIndex = content.indexOf('{', closeParenIndex);
|
||||
|
||||
if (openBraceIndex === -1) return null;
|
||||
|
|
@ -194,7 +232,21 @@ export class ControlFlowTransformer {
|
|||
if (startIndex === -1) return null;
|
||||
|
||||
const openParenIndex = match.indexOf('(', startIndex);
|
||||
const closeParenIndex = match.indexOf(')', openParenIndex);
|
||||
if (openParenIndex === -1) return null;
|
||||
|
||||
// Properly count nested parentheses
|
||||
let parenCount = 1;
|
||||
let closeParenIndex = openParenIndex + 1;
|
||||
while (closeParenIndex < match.length && parenCount > 0) {
|
||||
const char = match[closeParenIndex];
|
||||
if (char === '(') parenCount++;
|
||||
else if (char === ')') parenCount--;
|
||||
closeParenIndex++;
|
||||
}
|
||||
|
||||
if (parenCount !== 0) return null;
|
||||
closeParenIndex--; // Move back to the closing paren
|
||||
|
||||
const openBraceIndex = match.indexOf('{', closeParenIndex);
|
||||
|
||||
if (openBraceIndex === -1) return null;
|
||||
|
|
@ -219,7 +271,8 @@ export class ControlFlowTransformer {
|
|||
const forPart = parts[0].trim();
|
||||
const trackPart = parts[1]?.trim();
|
||||
|
||||
const forMatch = forPart.match(/^\s*([^\s]+)\s+of\s+([^\s]+)\s*$/);
|
||||
// Match: variable of iterable (iterable can contain parentheses, dots, etc.)
|
||||
const forMatch = forPart.match(/^\s*(\w+)\s+of\s+(.+)\s*$/);
|
||||
if (!forMatch) return null;
|
||||
|
||||
const variable = forMatch[1].trim();
|
||||
|
|
@ -248,7 +301,10 @@ export class ControlFlowTransformer {
|
|||
ngForExpression += `; trackBy: ${forBlock.trackBy}`;
|
||||
}
|
||||
|
||||
return `<ng-container *ngFor="${ngForExpression}">${forBlock.content}</ng-container>`;
|
||||
// Recursively transform nested @if and @for blocks in content
|
||||
const transformedContent = this.transform(forBlock.content);
|
||||
|
||||
return `<ng-container *ngFor="${ngForExpression}">${transformedContent}</ng-container>`;
|
||||
}
|
||||
|
||||
private parseBlocks(match: string): ControlFlowBlock[] {
|
||||
|
|
@ -273,6 +329,12 @@ export class ControlFlowTransformer {
|
|||
const { condition, aliasVariable } = this.parseConditionWithAlias(conditionStr.trim());
|
||||
|
||||
const openBraceIndex = match.indexOf('{', closeParenIndex);
|
||||
if (openBraceIndex === -1) {
|
||||
// Incomplete @if block - no opening brace found
|
||||
blocks.push({ condition, content: '', aliasVariable });
|
||||
return blocks;
|
||||
}
|
||||
|
||||
let braceCount = 1;
|
||||
let closeBraceIndex = openBraceIndex + 1;
|
||||
|
||||
|
|
@ -282,11 +344,22 @@ export class ControlFlowTransformer {
|
|||
else if (char === '}') braceCount--;
|
||||
closeBraceIndex++;
|
||||
}
|
||||
closeBraceIndex--;
|
||||
|
||||
const content = match.substring(openBraceIndex + 1, closeBraceIndex);
|
||||
blocks.push({ condition, content, aliasVariable });
|
||||
let content = '';
|
||||
if (braceCount === 0) {
|
||||
// Complete block found
|
||||
closeBraceIndex--;
|
||||
content = match.substring(openBraceIndex + 1, closeBraceIndex);
|
||||
index = closeBraceIndex + 1;
|
||||
} else {
|
||||
// Incomplete block - take everything after opening brace
|
||||
content = match.substring(openBraceIndex + 1);
|
||||
index = match.length;
|
||||
}
|
||||
|
||||
// Trim leading whitespace from content
|
||||
content = content.trimStart();
|
||||
blocks.push({ condition, content, aliasVariable });
|
||||
}
|
||||
|
||||
while (index < match.length) {
|
||||
|
|
@ -311,6 +384,13 @@ export class ControlFlowTransformer {
|
|||
const { condition, aliasVariable } = this.parseConditionWithAlias(conditionStr.trim());
|
||||
|
||||
const openBraceIndex = match.indexOf('{', closeParenIndex);
|
||||
if (openBraceIndex === -1) {
|
||||
// Incomplete @else if block - no opening brace found
|
||||
blocks.push({ condition, content: '', aliasVariable });
|
||||
index = match.length;
|
||||
break;
|
||||
}
|
||||
|
||||
let braceCount = 1;
|
||||
let closeBraceIndex = openBraceIndex + 1;
|
||||
|
||||
|
|
@ -320,11 +400,22 @@ export class ControlFlowTransformer {
|
|||
else if (char === '}') braceCount--;
|
||||
closeBraceIndex++;
|
||||
}
|
||||
closeBraceIndex--;
|
||||
|
||||
const content = match.substring(openBraceIndex + 1, closeBraceIndex);
|
||||
blocks.push({ condition, content, aliasVariable });
|
||||
let content = '';
|
||||
if (braceCount === 0) {
|
||||
// Complete block found
|
||||
closeBraceIndex--;
|
||||
content = match.substring(openBraceIndex + 1, closeBraceIndex);
|
||||
index = closeBraceIndex + 1;
|
||||
} else {
|
||||
// Incomplete block - take everything after opening brace
|
||||
content = match.substring(openBraceIndex + 1);
|
||||
index = match.length;
|
||||
}
|
||||
|
||||
// Trim leading whitespace from content
|
||||
content = content.trimStart();
|
||||
blocks.push({ condition, content, aliasVariable });
|
||||
} else if (elseMatch) {
|
||||
const openBraceIndex = index + elseMatch[0].length - 1;
|
||||
let braceCount = 1;
|
||||
|
|
@ -336,11 +427,22 @@ export class ControlFlowTransformer {
|
|||
else if (char === '}') braceCount--;
|
||||
closeBraceIndex++;
|
||||
}
|
||||
closeBraceIndex--;
|
||||
|
||||
const content = match.substring(openBraceIndex + 1, closeBraceIndex);
|
||||
blocks.push({ condition: null, content });
|
||||
let content = '';
|
||||
if (braceCount === 0) {
|
||||
// Complete block found
|
||||
closeBraceIndex--;
|
||||
content = match.substring(openBraceIndex + 1, closeBraceIndex);
|
||||
index = closeBraceIndex + 1;
|
||||
} else {
|
||||
// Incomplete block - take everything after opening brace
|
||||
content = match.substring(openBraceIndex + 1);
|
||||
index = match.length;
|
||||
}
|
||||
|
||||
// Trim leading whitespace from content
|
||||
content = content.trimStart();
|
||||
blocks.push({ condition: null, content });
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -368,10 +470,13 @@ export class ControlFlowTransformer {
|
|||
const block = blocks[i];
|
||||
const condition = this.buildCondition(block.condition, negated);
|
||||
|
||||
// Recursively transform nested @if and @for blocks in content
|
||||
const transformedContent = this.transform(block.content);
|
||||
|
||||
if (block.aliasVariable) {
|
||||
result += `<ng-container *ngIf="${condition}; let ${block.aliasVariable}">${block.content}</ng-container>`;
|
||||
result += `<ng-container *ngIf="${condition}; let ${block.aliasVariable}">${transformedContent}</ng-container>`;
|
||||
} else {
|
||||
result += `<ng-container *ngIf="${condition}">${block.content}</ng-container>`;
|
||||
result += `<ng-container *ngIf="${condition}">${transformedContent}</ng-container>`;
|
||||
}
|
||||
|
||||
if (i < blocks.length - 1) {
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ class Server extends BaseBuilder {
|
|||
}
|
||||
|
||||
private proxyRequest(targetUrl: string, req: http.IncomingMessage, res: http.ServerResponse): void {
|
||||
console.log(`[Proxy] ${req.method} ${req.url} -> ${targetUrl}`);
|
||||
const parsedUrl = new URL(targetUrl);
|
||||
const protocol = parsedUrl.protocol === 'https:' ? https : http;
|
||||
|
||||
|
|
@ -173,13 +174,14 @@ class Server extends BaseBuilder {
|
|||
},
|
||||
},
|
||||
(proxyRes) => {
|
||||
console.log(`[Proxy] Response: ${proxyRes.statusCode} for ${req.url}`);
|
||||
res.writeHead(proxyRes.statusCode || 500, proxyRes.headers);
|
||||
proxyRes.pipe(res);
|
||||
},
|
||||
);
|
||||
|
||||
proxyReq.on('error', (err) => {
|
||||
console.error('Proxy error:', err.message);
|
||||
console.error(`[Proxy] Error for ${req.url}:`, err.message);
|
||||
res.writeHead(502);
|
||||
res.end('Bad Gateway');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -61,27 +61,11 @@ export class Injector {
|
|||
}
|
||||
|
||||
public createInstanceWithProviders<T>(classType: Type<T>, providers: Provider[]): T {
|
||||
console.log('[DI] createInstanceWithProviders START', {
|
||||
classType,
|
||||
typeofClassType: typeof classType,
|
||||
isFunction: typeof classType === 'function',
|
||||
hasName: classType?.name,
|
||||
originalName: (classType as any)?.__quarc_original_name__,
|
||||
providers: providers.map(p => ({
|
||||
provide: typeof p.provide === 'string' ? p.provide : p.provide?.name,
|
||||
type: 'useValue' in p ? 'useValue' : 'useClass' in p ? 'useClass' : 'useFactory' in p ? 'useFactory' : 'useExisting'
|
||||
}))
|
||||
});
|
||||
|
||||
if (!classType) {
|
||||
throw new Error(`[DI] createInstanceWithProviders called with undefined classType`);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log({
|
||||
className: (classType as any).__quarc_original_name__ || classType.name,
|
||||
classType,
|
||||
});
|
||||
const dependencies = this.resolveDependenciesWithProviders(classType, providers);
|
||||
/** /
|
||||
console.log({
|
||||
|
|
@ -127,11 +111,6 @@ export class Injector {
|
|||
return `${metadata.selector} (class)`;
|
||||
}
|
||||
|
||||
console.log({
|
||||
classType,
|
||||
metadata,
|
||||
});
|
||||
|
||||
return 'Unknown class';
|
||||
}
|
||||
|
||||
|
|
@ -187,44 +166,27 @@ export class Injector {
|
|||
}
|
||||
|
||||
private resolveDependency(token: any, providers: Provider[]): any {
|
||||
console.log('[DI] resolveDependency', {
|
||||
token,
|
||||
typeofToken: typeof token,
|
||||
tokenName: typeof token === 'string' ? token : (token as any).__quarc_original_name__ || token?.name,
|
||||
isFunction: typeof token === 'function',
|
||||
});
|
||||
|
||||
const tokenName = typeof token === 'string' ? token : (token as any).__quarc_original_name__ || token.name;
|
||||
|
||||
const provider = this.findProvider(token, providers);
|
||||
if (provider) {
|
||||
console.log('[DI] Found provider for token', tokenName);
|
||||
return this.resolveProviderValue(provider, providers);
|
||||
}
|
||||
|
||||
if (this.sharedInstances[tokenName]) {
|
||||
console.log('[DI] Found in sharedInstances', tokenName);
|
||||
return this.sharedInstances[tokenName];
|
||||
}
|
||||
|
||||
if (this.instanceCache[tokenName]) {
|
||||
console.log('[DI] Found in instanceCache', tokenName);
|
||||
return this.instanceCache[tokenName];
|
||||
}
|
||||
|
||||
console.log('[DI] Creating new instance for token', tokenName);
|
||||
return this.createInstanceWithProviders(token, providers);
|
||||
}
|
||||
|
||||
private getConstructorParameterTypes(classType: Type<any>): any[] {
|
||||
const className = classType?.name || 'Unknown';
|
||||
|
||||
console.log({
|
||||
className,
|
||||
classType,
|
||||
diParams: (classType as any).__di_params__,
|
||||
});
|
||||
|
||||
if (!classType) {
|
||||
throw new Error(`[DI] Cannot resolve dependencies: classType is undefined`);
|
||||
}
|
||||
|
|
@ -256,12 +218,10 @@ export class Injector {
|
|||
public register<T>(classType: Type<T>, instance: T | Type<T>): void {
|
||||
const key = (classType as any).__quarc_original_name__ || classType.name;
|
||||
this.instanceCache[key] = instance;
|
||||
console.log('injector register', classType, key, instance);
|
||||
}
|
||||
|
||||
public registerShared<T>(classType: Type<T>, instance: T | Type<T>): void {
|
||||
const key = (classType as any).__quarc_original_name__ || classType.name;
|
||||
console.log('injector registerShared', classType, key, instance);
|
||||
this.sharedInstances[key] = instance;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -235,7 +235,6 @@ export class TemplateFragment {
|
|||
const isForIn = !!forInMatch;
|
||||
|
||||
if (!match) {
|
||||
console.warn('Invalid ngFor expression:', ngForExpression);
|
||||
parent.insertBefore(endMarker, ngContainer);
|
||||
ngContainer.remove();
|
||||
return;
|
||||
|
|
@ -376,7 +375,6 @@ export class TemplateFragment {
|
|||
*/
|
||||
rerenderFragment(markerIndex: number): void {
|
||||
if (markerIndex < 0 || markerIndex >= this.ngContainerMarkers.length) {
|
||||
console.warn('Invalid marker index:', markerIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ export class WebComponentFactory {
|
|||
|
||||
const componentMeta = componentType._quarcComponent?.[0];
|
||||
if (!componentMeta) {
|
||||
console.warn(`Component ${componentType.name} has no _quarcComponent metadata`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +68,6 @@ export class WebComponentFactory {
|
|||
this.componentTypes.set(tagName, componentType);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.warn(`Failed to register component ${tagName}:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +106,6 @@ export class WebComponentFactory {
|
|||
}
|
||||
}
|
||||
|
||||
console.log({localProviders});
|
||||
return injector.createInstanceWithProviders<IComponent>(componentType, localProviders);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,11 +35,8 @@ async function tryLoadExternalScripts(urls: string | string[]): Promise<void> {
|
|||
await loadExternalScript(url);
|
||||
return;
|
||||
} catch {
|
||||
console.warn(`[External] Could not load from: ${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.info("[External] No external scripts loaded - app continues without enhancements");
|
||||
}
|
||||
|
||||
export async function bootstrapApplication(
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ export class RouterLink implements IDirective {
|
|||
public _nativeElement: HTMLElement,
|
||||
private activatedRoute?: ActivatedRoute,
|
||||
) {
|
||||
console.log({ routerLink: this.routerLink() });
|
||||
this._nativeElement.addEventListener('click', (event) => {
|
||||
this.onClick(event);
|
||||
});
|
||||
|
|
@ -44,7 +43,6 @@ export class RouterLink implements IDirective {
|
|||
|
||||
this.router.navigate(commands, extras).then(success => {
|
||||
}).catch(error => {
|
||||
console.error('RouterLink CLICK - Navigation failed:', error);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -261,6 +261,167 @@ test('ControlFlowTransformer: @if @else if oba z aliasem', () => {
|
|||
result.includes('*ngIf="!(primary()) && !(secondary())"');
|
||||
});
|
||||
|
||||
// Test 25: ControlFlowTransformer - niekompletny @if (bez zamknięcia)
|
||||
test('ControlFlowTransformer: niekompletny @if', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '@if (range.name) { content';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngIf="range.name">content</ng-container>');
|
||||
});
|
||||
|
||||
// Test 26: ControlFlowTransformer - niekompletny @if na końcu
|
||||
test('ControlFlowTransformer: niekompletny @if na końcu', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '} @if (prepared.sensor.loading) { ';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngIf="prepared.sensor.loading"></ng-container>');
|
||||
});
|
||||
|
||||
// Test 27: ControlFlowTransformer - niekompletny @if bez nawiasu klamrowego
|
||||
test('ControlFlowTransformer: niekompletny @if bez nawiasu klamrowego', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '@if (condition) ';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngIf="condition"></ng-container>');
|
||||
});
|
||||
|
||||
// Test 28: ControlFlowTransformer - zagnieżdżony @if wewnątrz @for
|
||||
test('ControlFlowTransformer: zagnieżdżony @if wewnątrz @for', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = `@for (item of items) {
|
||||
@if (item.active) {
|
||||
<span>{{ item.name }}</span>
|
||||
}
|
||||
}`;
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngFor="let item of items">') &&
|
||||
result.includes('<ng-container *ngIf="item.active">') &&
|
||||
!result.includes('@if') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 29: ControlFlowTransformer - zagnieżdżony @for wewnątrz @if
|
||||
test('ControlFlowTransformer: zagnieżdżony @for wewnątrz @if', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = `@if (hasItems) {
|
||||
@for (item of items; track item.id) {
|
||||
<div>{{ item }}</div>
|
||||
}
|
||||
}`;
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngIf="hasItems">') &&
|
||||
result.includes('<ng-container *ngFor="let item of items; trackBy: item.id">') &&
|
||||
!result.includes('@if') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 30: ControlFlowTransformer - wielokrotnie zagnieżdżone @if wewnątrz @for
|
||||
test('ControlFlowTransformer: wielokrotnie zagnieżdżone @if wewnątrz @for', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = `@for (range of ranges; track $index) {
|
||||
<div>
|
||||
@if (range.name) {
|
||||
<span>{{ range.name }}</span>
|
||||
}
|
||||
<span>{{ range.min }}</span>
|
||||
</div>
|
||||
}`;
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngFor="let range of ranges; trackBy: $index">') &&
|
||||
result.includes('<ng-container *ngIf="range.name">') &&
|
||||
!result.includes('@if') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 31: ControlFlowTransformer - kompleksowy przypadek z user template
|
||||
test('ControlFlowTransformer: kompleksowy przypadek użytkownika', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = `@if (prepared.sensor.ranges) {
|
||||
<span>
|
||||
@for (range of prepared.sensor.ranges; track $index) {
|
||||
<div>
|
||||
@if (range.name) {
|
||||
<span>{{ range.name }}</span>
|
||||
}
|
||||
<span>{{ range.min }}</span>
|
||||
<span>{{ range.max }}</span>
|
||||
</div>
|
||||
}
|
||||
</span>
|
||||
}`;
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngIf="prepared.sensor.ranges">') &&
|
||||
result.includes('<ng-container *ngFor="let range of prepared.sensor.ranges; trackBy: $index">') &&
|
||||
result.includes('<ng-container *ngIf="range.name">') &&
|
||||
!result.includes('@if') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 32: ControlFlowTransformer - głęboko zagnieżdżone @if/@for/@if
|
||||
test('ControlFlowTransformer: głęboko zagnieżdżone @if/@for/@if', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = `@if (level1) {
|
||||
@for (item of items; track item.id) {
|
||||
@if (item.visible) {
|
||||
<div>{{ item.name }}</div>
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngIf="level1">') &&
|
||||
result.includes('<ng-container *ngFor="let item of items; trackBy: item.id">') &&
|
||||
result.includes('<ng-container *ngIf="item.visible">') &&
|
||||
!result.includes('@if') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 33: ControlFlowTransformer - @for z funkcją w iterable
|
||||
test('ControlFlowTransformer: @for z funkcją w iterable', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '@for (item of getItems(); track item.id) { <div>{{ item }}</div> }';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngFor="let item of getItems(); trackBy: item.id">') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 34: ControlFlowTransformer - @for z zagnieżdżonymi nawiasami w funkcji
|
||||
test('ControlFlowTransformer: @for z zagnieżdżonymi nawiasami w funkcji', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '@for (prepared of preparedSensors(); track prepared.sensor.id) { <div>{{ prepared.sensor.name }}</div> }';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngFor="let prepared of preparedSensors(); trackBy: prepared.sensor.id">') &&
|
||||
result.includes('prepared.sensor.name') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 35: ControlFlowTransformer - @for z metodą obiektu w iterable
|
||||
test('ControlFlowTransformer: @for z metodą obiektu w iterable', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '@for (item of data.getItems(); track $index) { <span>{{ item }}</span> }';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngFor="let item of data.getItems(); trackBy: $index">') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 36: ControlFlowTransformer - @for z wieloma zagnieżdżonymi nawiasami
|
||||
test('ControlFlowTransformer: @for z wieloma zagnieżdżonymi nawiasami', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '@for (item of service.getData(filter(value())); track item.id) { <div>{{ item }}</div> }';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngFor="let item of service.getData(filter(value())); trackBy: item.id">') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
// Test 37: ControlFlowTransformer - @for z funkcją i złożonym trackBy
|
||||
test('ControlFlowTransformer: @for z funkcją i złożonym trackBy', () => {
|
||||
const transformer = new ControlFlowTransformer();
|
||||
const input = '@for (range of prepared.sensor.ranges; track $index) { <div>{{ range.name }}</div> }';
|
||||
const result = transformer.transform(input);
|
||||
return result.includes('<ng-container *ngFor="let range of prepared.sensor.ranges; trackBy: $index">') &&
|
||||
result.includes('range.name') &&
|
||||
!result.includes('@for');
|
||||
});
|
||||
|
||||
console.log('\n=== PODSUMOWANIE ===');
|
||||
console.log(`✅ Testy zaliczone: ${passedTests}`);
|
||||
console.log(`❌ Testy niezaliczone: ${failedTests}`);
|
||||
|
|
|
|||
Loading…
Reference in New Issue