@ordojs/core
Version:
Core compiler and runtime for OrdoJS framework
877 lines (795 loc) • 30.3 kB
text/typescript
/**
* @fileoverview Dead Code Eliminator Tests
*/
import { beforeEach, describe, expect, it } from 'vitest';
import {
ExpressionType,
StatementType,
type ClientBlockNode,
type ComponentAST,
type FunctionNode,
type MarkupBlockNode,
type ReactiveVariableNode,
type ServerBlockNode
} from '../types/index.js';
import { DeadCodeEliminator } from './dead-code-eliminator.js';
describe('DeadCodeEliminator', () => {
let eliminator: DeadCodeEliminator;
beforeEach(() => {
eliminator = new DeadCodeEliminator();
});
describe('constructor', () => {
it('should initialize with default options', () => {
expect(eliminator).toBeInstanceOf(DeadCodeEliminator);
});
it('should accept custom options', () => {
const customEliminator = new DeadCodeEliminator({
aggressiveTreeShaking: false,
inlineSmallFunctions: false,
maxInlineSize: 5
});
expect(customEliminator).toBeInstanceOf(DeadCodeEliminator);
});
});
describe('optimize', () => {
it('should return the same AST when no optimizations are possible', () => {
const ast = createSimpleAST();
const result = eliminator.optimize(ast);
expect(result).toBe(ast);
});
it('should remove unused reactive variables', () => {
const ast = createASTWithUnusedVariables();
const originalVariableCount = ast.component.clientBlock!.reactiveVariables.length;
const result = eliminator.optimize(ast);
expect(result.component.clientBlock!.reactiveVariables.length).toBeLessThan(originalVariableCount);
expect(result.component.clientBlock!.reactiveVariables.every(v => v.name === 'usedVariable')).toBe(true);
});
it('should remove unused functions', () => {
const ast = createASTWithUnusedFunctions();
const originalFunctionCount = ast.component.clientBlock!.functions.length;
const result = eliminator.optimize(ast);
expect(result.component.clientBlock!.functions.length).toBeLessThan(originalFunctionCount);
expect(result.component.clientBlock!.functions.every(f => f.name === 'usedFunction')).toBe(true);
});
it('should remove unused event handlers', () => {
const ast = createASTWithUnusedEventHandlers();
const originalHandlerCount = ast.component.clientBlock!.eventHandlers.length;
const result = eliminator.optimize(ast);
expect(result.component.clientBlock!.eventHandlers.length).toBeLessThan(originalHandlerCount);
expect(result.component.clientBlock!.eventHandlers.every(h => h.eventName === 'click')).toBe(true);
});
it('should remove unused server functions', () => {
const ast = createASTWithUnusedServerFunctions();
const originalFunctionCount = ast.component.serverBlock!.functions.length;
const result = eliminator.optimize(ast);
expect(result.component.serverBlock!.functions.length).toBeLessThan(originalFunctionCount);
expect(result.component.serverBlock!.functions.every(f => f.isPublic || f.name === 'usedFunction')).toBe(true);
});
it('should perform constant folding', () => {
const ast = createASTWithConstantExpressions();
const result = eliminator.optimize(ast);
// Check that constant expressions were folded
const warnings = eliminator.getWarnings();
expect(warnings.some(w => w.message.includes('constant folding'))).toBe(true);
});
it('should remove empty blocks', () => {
const ast = createASTWithEmptyBlocks();
const result = eliminator.optimize(ast);
const warnings = eliminator.getWarnings();
expect(warnings.some(w => w.message.includes('empty blocks'))).toBe(true);
});
it('should handle errors gracefully', () => {
const invalidAST = createInvalidAST();
expect(() => eliminator.optimize(invalidAST)).toThrow();
const errors = eliminator.getErrors();
expect(errors.length).toBeGreaterThan(0);
expect(errors[0]).toBeInstanceOf(Error);
});
it('should generate warnings for optimizations', () => {
const ast = createASTWithUnusedVariables();
eliminator.optimize(ast);
const warnings = eliminator.getWarnings();
expect(warnings.length).toBeGreaterThan(0);
expect(warnings.every(w => w instanceof Error)).toBe(true);
});
it('should preserve used variables and functions', () => {
const ast = createASTWithUsedAndUnused();
const result = eliminator.optimize(ast);
// Check that used variables are preserved
const usedVariables = result.component.clientBlock!.reactiveVariables.map(v => v.name);
expect(usedVariables).toContain('usedVariable');
expect(usedVariables).not.toContain('unusedVariable');
// Check that used functions are preserved
const usedFunctions = result.component.clientBlock!.functions.map(f => f.name);
expect(usedFunctions).toContain('usedFunction');
expect(usedFunctions).not.toContain('unusedFunction');
});
it('should handle complex nested expressions', () => {
const ast = createASTWithComplexExpressions();
const result = eliminator.optimize(ast);
expect(result).toBeDefined();
expect(result.component).toBeDefined();
});
it('should handle components without client or server blocks', () => {
const ast = createASTWithoutBlocks();
const result = eliminator.optimize(ast);
expect(result).toBe(ast);
});
});
describe('error handling', () => {
it('should handle null AST gracefully', () => {
expect(() => eliminator.optimize(null as any)).toThrow();
});
it('should handle undefined AST gracefully', () => {
expect(() => eliminator.optimize(undefined as any)).toThrow();
});
it('should handle malformed AST gracefully', () => {
const malformedAST = createMalformedAST();
expect(() => eliminator.optimize(malformedAST)).toThrow();
});
});
describe('options', () => {
it('should respect aggressiveTreeShaking option', () => {
const conservativeEliminator = new DeadCodeEliminator({
aggressiveTreeShaking: false
});
const ast = createASTWithUnusedVariables();
const result = conservativeEliminator.optimize(ast);
// Should be less aggressive in removal
expect(result.component.clientBlock!.reactiveVariables.length).toBeGreaterThanOrEqual(
ast.component.clientBlock!.reactiveVariables.length
);
});
it('should respect inlineSmallFunctions option', () => {
const noInlineEliminator = new DeadCodeEliminator({
inlineSmallFunctions: false
});
const ast = createASTWithSmallFunctions();
const result = noInlineEliminator.optimize(ast);
const warnings = noInlineEliminator.getWarnings();
expect(warnings.some(w => w.message.includes('inlining'))).toBe(false);
});
it('should respect maxInlineSize option', () => {
const smallInlineEliminator = new DeadCodeEliminator({
maxInlineSize: 2
});
const ast = createASTWithSmallFunctions();
const result = smallInlineEliminator.optimize(ast);
// Should inline fewer functions with smaller maxInlineSize
const warnings = smallInlineEliminator.getWarnings();
const inliningWarnings = warnings.filter(w => w.message.includes('inlining'));
expect(inliningWarnings.length).toBeLessThanOrEqual(2);
});
});
});
// Helper functions to create test ASTs
function createSimpleAST(): ComponentAST {
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithUnusedVariables(): ComponentAST {
const usedVariable: ReactiveVariableNode = {
type: 'ReactiveVariable',
name: 'usedVariable',
initialValue: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 42, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
dataType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] },
isConst: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const unusedVariable: ReactiveVariableNode = {
type: 'ReactiveVariable',
name: 'unusedVariable',
initialValue: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 100, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
dataType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] },
isConst: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [usedVariable, unusedVariable],
eventHandlers: [],
functions: [],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const markupBlock: MarkupBlockNode = {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [{
type: 'Interpolation',
expression: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'usedVariable', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithUnusedFunctions(): ComponentAST {
const usedFunction: FunctionNode = {
type: 'Function',
name: 'usedFunction',
parameters: [],
body: [],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const unusedFunction: FunctionNode = {
type: 'Function',
name: 'unusedFunction',
parameters: [],
body: [],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [],
eventHandlers: [],
functions: [usedFunction, unusedFunction],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const markupBlock: MarkupBlockNode = {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [{
type: 'Interpolation',
expression: { type: 'Expression', expressionType: ExpressionType.CALL, callee: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'usedFunction', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } }, arguments: [], range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithUnusedEventHandlers(): ComponentAST {
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [],
eventHandlers: [
{
type: 'EventHandler',
eventName: 'click',
handler: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 'handleClick', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
modifiers: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
{
type: 'EventHandler',
eventName: 'unused',
handler: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 'handleUnused', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
modifiers: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}
],
functions: [],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const markupBlock: MarkupBlockNode = {
type: 'MarkupBlock',
elements: [{
type: 'HTMLElement',
tagName: 'button',
attributes: [{ type: 'Attribute', name: 'onclick', value: 'click', isDirective: false, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } }],
children: [],
isSelfClosing: false,
isVoidElement: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithUnusedServerFunctions(): ComponentAST {
const serverBlock: ServerBlockNode = {
type: 'ServerBlock',
functions: [
{
type: 'ServerFunction',
name: 'usedFunction',
parameters: [],
body: [],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
isPublic: false,
middleware: [],
permissions: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
{
type: 'ServerFunction',
name: 'unusedFunction',
parameters: [],
body: [],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
isPublic: false,
middleware: [],
permissions: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}
],
middleware: [],
dataFetchers: [],
imports: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
serverBlock,
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [{
type: 'Interpolation',
expression: { type: 'Expression', expressionType: ExpressionType.CALL, callee: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'usedFunction', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } }, arguments: [], range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithConstantExpressions(): ComponentAST {
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [],
eventHandlers: [],
functions: [{
type: 'Function',
name: 'testFunction',
parameters: [],
body: [{
type: 'Statement',
statementType: StatementType.EXPRESSION,
expression: {
type: 'Expression',
expressionType: ExpressionType.BINARY,
operator: '+',
left: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 2, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
right: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 3, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
returnType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithEmptyBlocks(): ComponentAST {
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [],
eventHandlers: [],
functions: [{
type: 'Function',
name: 'testFunction',
parameters: [],
body: [{
type: 'Statement',
statementType: StatementType.BLOCK,
body: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithUsedAndUnused(): ComponentAST {
const usedVariable: ReactiveVariableNode = {
type: 'ReactiveVariable',
name: 'usedVariable',
initialValue: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 42, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
dataType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] },
isConst: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const unusedVariable: ReactiveVariableNode = {
type: 'ReactiveVariable',
name: 'unusedVariable',
initialValue: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 100, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
dataType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] },
isConst: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const usedFunction: FunctionNode = {
type: 'Function',
name: 'usedFunction',
parameters: [],
body: [],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const unusedFunction: FunctionNode = {
type: 'Function',
name: 'unusedFunction',
parameters: [],
body: [],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [usedVariable, unusedVariable],
eventHandlers: [],
functions: [usedFunction, unusedFunction],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
const markupBlock: MarkupBlockNode = {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [
{
type: 'Interpolation',
expression: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'usedVariable', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
{
type: 'Interpolation',
expression: { type: 'Expression', expressionType: ExpressionType.CALL, callee: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'usedFunction', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } }, arguments: [], range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}
],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithComplexExpressions(): ComponentAST {
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [],
eventHandlers: [],
functions: [{
type: 'Function',
name: 'complexFunction',
parameters: [],
body: [{
type: 'Statement',
statementType: StatementType.EXPRESSION,
expression: {
type: 'Expression',
expressionType: ExpressionType.CALL,
callee: {
type: 'Expression',
expressionType: ExpressionType.MEMBER,
object: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'console', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
property: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'log', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
arguments: [
{
type: 'Expression',
expressionType: ExpressionType.BINARY,
operator: '+',
left: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 'Hello', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
right: { type: 'Expression', expressionType: ExpressionType.IDENTIFIER, identifier: 'name', range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}
],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithoutBlocks(): ComponentAST {
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createASTWithSmallFunctions(): ComponentAST {
const clientBlock: ClientBlockNode = {
type: 'ClientBlock',
reactiveVariables: [],
eventHandlers: [],
functions: [{
type: 'Function',
name: 'smallFunction',
parameters: [],
body: [{
type: 'Statement',
statementType: StatementType.EXPRESSION,
expression: { type: 'Expression', expressionType: ExpressionType.LITERAL, value: 42, range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } } },
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
returnType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
}],
lifecycle: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
};
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
clientBlock,
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createInvalidAST(): ComponentAST {
return {
component: {
type: 'Component',
name: 'TestComponent',
props: [],
markupBlock: {
type: 'MarkupBlock',
elements: [],
textNodes: [],
interpolations: [],
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
},
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
} as any, // Force invalid AST
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}
function createMalformedAST(): ComponentAST {
return {
component: null as any,
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
}