smartui-migration-tool
Version:
Enterprise-grade CLI tool for migrating visual testing platforms to LambdaTest SmartUI
733 lines • 22.4 kB
JavaScript
"use strict";
/**
* Context Analysis Engine
* Phase 2: Advanced Pattern Matching & Context Analysis
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextAnalysisEngine = void 0;
class ContextAnalysisEngine {
constructor() {
this.nodeMap = new Map();
this.contextMap = new Map();
this.crossReferences = [];
}
analyze(ast) {
const startTime = Date.now();
const startMemory = process.memoryUsage().heapUsed;
// Build node map
this.buildNodeMap(ast);
// Analyze global context
const globalContext = this.analyzeGlobalContext(ast);
// Analyze function contexts
const functionContexts = this.analyzeFunctionContexts(ast);
// Analyze class contexts
const classContexts = this.analyzeClassContexts(ast);
// Analyze module contexts
const moduleContexts = this.analyzeModuleContexts(ast);
// Analyze test contexts
const testContexts = this.analyzeTestContexts(ast);
// Analyze visual test contexts
const visualTestContexts = this.analyzeVisualTestContexts(ast);
// Build cross references
this.buildCrossReferences(ast);
// Calculate complexity
const complexity = this.calculateComplexity(ast);
// Calculate maintainability
const maintainability = this.calculateMaintainability(ast);
// Calculate testability
const testability = this.calculateTestability(ast);
const endTime = Date.now();
const endMemory = process.memoryUsage().heapUsed;
return {
globalContext,
functionContexts,
classContexts,
moduleContexts,
testContexts,
visualTestContexts,
crossReferences: this.crossReferences,
complexity,
maintainability,
testability,
metadata: {
totalNodes: this.nodeMap.size,
totalFunctions: functionContexts.size,
totalClasses: classContexts.size,
totalVariables: this.countVariables(ast),
totalImports: this.countImports(ast),
totalExports: this.countExports(ast),
totalTests: testContexts.size,
totalVisualTests: visualTestContexts.size,
totalDependencies: this.countDependencies(ast),
processingTime: endTime - startTime,
memoryUsage: endMemory - startMemory,
confidence: this.calculateConfidence(ast)
}
};
}
buildNodeMap(ast) {
this.nodeMap.set(ast.id, ast);
if (ast.children) {
ast.children.forEach(child => this.buildNodeMap(child));
}
}
analyzeGlobalContext(ast) {
const variables = [];
const functions = [];
const imports = [];
const exports = [];
const dependencies = [];
this.traverseAST(ast, (node) => {
switch (node.type) {
case 'variable':
variables.push(this.analyzeVariable(node));
break;
case 'function':
case 'arrow-function':
case 'async-function':
case 'generator':
functions.push(this.analyzeFunction(node));
break;
case 'import':
imports.push(this.analyzeImport(node));
break;
case 'export':
exports.push(this.analyzeExport(node));
break;
}
});
return {
scope: 'global',
depth: 0,
parent: null,
siblings: [],
children: ast.children?.map(child => child.id) || [],
variables,
functions,
imports,
exports,
dependencies,
testContext: null,
visualTestContext: null
};
}
analyzeFunctionContexts(ast) {
const contexts = new Map();
this.traverseAST(ast, (node) => {
if (['function', 'arrow-function', 'async-function', 'generator'].includes(node.type)) {
const context = this.analyzeFunctionContext(node);
contexts.set(node.id, context);
}
});
return contexts;
}
analyzeClassContexts(ast) {
const contexts = new Map();
this.traverseAST(ast, (node) => {
if (node.type === 'class') {
const context = this.analyzeClassContext(node);
contexts.set(node.id, context);
}
});
return contexts;
}
analyzeModuleContexts(ast) {
const contexts = new Map();
this.traverseAST(ast, (node) => {
if (['module', 'namespace'].includes(node.type)) {
const context = this.analyzeModuleContext(node);
contexts.set(node.id, context);
}
});
return contexts;
}
analyzeTestContexts(ast) {
const contexts = new Map();
this.traverseAST(ast, (node) => {
if (this.isTestNode(node)) {
const context = this.analyzeTestContext(node);
contexts.set(node.id, context);
}
});
return contexts;
}
analyzeVisualTestContexts(ast) {
const contexts = new Map();
this.traverseAST(ast, (node) => {
if (this.isVisualTestNode(node)) {
const context = this.analyzeVisualTestContext(node);
contexts.set(node.id, context);
}
});
return contexts;
}
analyzeVariable(node) {
return {
name: this.extractVariableName(node),
type: this.extractVariableType(node),
scope: this.extractScope(node),
isUsed: this.isVariableUsed(node),
isModified: this.isVariableModified(node),
references: this.countVariableReferences(node),
declaration: node,
usage: this.findVariableUsage(node)
};
}
analyzeFunction(node) {
return {
name: this.extractFunctionName(node),
type: this.extractFunctionType(node),
scope: this.extractScope(node),
parameters: this.extractParameters(node),
returnType: this.extractReturnType(node),
isTest: this.isTestFunction(node),
isVisualTest: this.isVisualTestFunction(node),
complexity: this.calculateFunctionComplexity(node),
calls: this.extractFunctionCalls(node),
calledBy: this.findCallers(node),
declaration: node,
body: this.extractFunctionBody(node)
};
}
analyzeImport(node) {
return {
source: this.extractImportSource(node),
specifiers: this.extractImportSpecifiers(node),
isDefault: this.isDefaultImport(node),
isNamespace: this.isNamespaceImport(node),
isSideEffect: this.isSideEffectImport(node),
usage: this.findImportUsage(node),
declaration: node
};
}
analyzeExport(node) {
return {
name: this.extractExportName(node),
type: this.extractExportType(node),
source: this.extractExportSource(node),
isTypeOnly: this.isTypeOnlyExport(node),
usage: this.findExportUsage(node),
declaration: node
};
}
analyzeTestContext(node) {
return {
framework: this.detectTestFramework(node),
type: this.detectTestType(node),
describe: this.extractDescribe(node),
it: this.extractIt(node),
beforeEach: this.extractBeforeEach(node),
afterEach: this.extractAfterEach(node),
beforeAll: this.extractBeforeAll(node),
afterAll: this.extractAfterAll(node),
setup: this.extractTestSetup(node),
teardown: this.extractTestTeardown(node),
assertions: this.extractAssertions(node)
};
}
analyzeVisualTestContext(node) {
return {
platform: this.detectVisualTestPlatform(node),
type: this.detectVisualTestType(node),
name: this.extractVisualTestName(node),
selector: this.extractVisualTestSelector(node),
options: this.extractVisualTestOptions(node),
beforeHook: this.extractBeforeHook(node),
afterHook: this.extractAfterHook(node),
assertions: this.extractVisualTestAssertions(node),
dependencies: this.extractVisualTestDependencies(node)
};
}
buildCrossReferences(ast) {
this.crossReferences = [];
this.traverseAST(ast, (node) => {
this.findCrossReferences(node);
});
}
calculateComplexity(ast) {
let cyclomatic = 1;
let cognitive = 0;
let nesting = 0;
let parameters = 0;
let lines = 0;
let statements = 0;
let expressions = 0;
let branches = 0;
let loops = 0;
let conditionals = 0;
let tryCatch = 0;
let async = 0;
let generators = 0;
let decorators = 0;
let annotations = 0;
this.traverseAST(ast, (node) => {
switch (node.type) {
case 'conditional':
cyclomatic++;
cognitive += 2;
conditionals++;
break;
case 'loop':
cyclomatic++;
cognitive += 3;
loops++;
break;
case 'try-catch':
tryCatch++;
break;
case 'async-function':
async++;
break;
case 'generator':
generators++;
break;
case 'decorator':
decorators++;
break;
case 'annotation':
annotations++;
break;
case 'function':
case 'arrow-function':
parameters += this.countParameters(node);
break;
}
lines += this.countLines(node.raw);
statements += this.countStatements(node);
expressions += this.countExpressions(node);
nesting = Math.max(nesting, this.calculateNestingDepth(node));
});
const overall = this.calculateOverallComplexity(cyclomatic, cognitive, nesting);
return {
cyclomatic,
cognitive,
nesting,
parameters,
lines,
statements,
expressions,
branches: conditionals,
loops,
conditionals,
tryCatch,
async,
generators,
decorators,
annotations,
overall
};
}
calculateMaintainability(ast) {
const cohesion = this.calculateCohesion(ast);
const coupling = this.calculateCoupling(ast);
const abstraction = this.calculateAbstraction(ast);
const encapsulation = this.calculateEncapsulation(ast);
const polymorphism = this.calculatePolymorphism(ast);
const inheritance = this.calculateInheritance(ast);
const composition = this.calculateComposition(ast);
const modularity = this.calculateModularity(ast);
const reusability = this.calculateReusability(ast);
const readability = this.calculateReadability(ast);
const overall = this.calculateOverallMaintainability(cohesion, coupling, abstraction, encapsulation, polymorphism, inheritance, composition, modularity, reusability, readability);
return {
cohesion,
coupling,
abstraction,
encapsulation,
polymorphism,
inheritance,
composition,
modularity,
reusability,
readability,
overall
};
}
calculateTestability(ast) {
const coverage = this.calculateTestCoverage(ast);
const isolation = this.calculateTestIsolation(ast);
const mocking = this.calculateMocking(ast);
const assertions = this.calculateAssertions(ast);
const setup = this.calculateTestSetup(ast);
const teardown = this.calculateTestTeardown(ast);
const data = this.calculateTestData(ast);
const edgeCases = this.calculateEdgeCases(ast);
const errorHandling = this.calculateErrorHandling(ast);
const performance = this.calculatePerformance(ast);
const overall = this.calculateOverallTestability(coverage, isolation, mocking, assertions, setup, teardown, data, edgeCases, errorHandling, performance);
return {
coverage,
isolation,
mocking,
assertions,
setup,
teardown,
data,
edgeCases,
errorHandling,
performance,
overall
};
}
// Helper methods
traverseAST(ast, callback) {
callback(ast);
if (ast.children) {
ast.children.forEach(child => this.traverseAST(child, callback));
}
}
isTestNode(node) {
const testPatterns = [
/test/i, /spec/i, /describe/i, /it\(/i, /expect\(/i
];
return testPatterns.some(pattern => pattern.test(node.raw));
}
isVisualTestNode(node) {
const visualTestPatterns = [
/percy/i, /applitools/i, /eyes/i, /sauce/i, /visual/i, /screenshot/i, /snapshot/i
];
return visualTestPatterns.some(pattern => pattern.test(node.raw));
}
isTestFunction(node) {
return this.isTestNode(node) && ['function', 'arrow-function', 'async-function'].includes(node.type);
}
isVisualTestFunction(node) {
return this.isVisualTestNode(node) && ['function', 'arrow-function', 'async-function'].includes(node.type);
}
// Placeholder implementations for complex analysis methods
extractVariableName(node) {
// Implementation for extracting variable name
return 'variable';
}
extractVariableType(node) {
return 'const';
}
extractScope(node) {
return 'global';
}
isVariableUsed(node) {
return true;
}
isVariableModified(node) {
return false;
}
countVariableReferences(node) {
return 1;
}
findVariableUsage(node) {
return [];
}
extractFunctionName(node) {
return 'function';
}
extractFunctionType(node) {
return 'function';
}
extractParameters(node) {
return [];
}
extractReturnType(node) {
return null;
}
calculateFunctionComplexity(node) {
return 1;
}
extractFunctionCalls(node) {
return [];
}
findCallers(node) {
return [];
}
extractFunctionBody(node) {
return node.children || [];
}
extractImportSource(node) {
return 'module';
}
extractImportSpecifiers(node) {
return [];
}
isDefaultImport(node) {
return false;
}
isNamespaceImport(node) {
return false;
}
isSideEffectImport(node) {
return false;
}
findImportUsage(node) {
return [];
}
extractExportName(node) {
return 'export';
}
extractExportType(node) {
return 'named';
}
extractExportSource(node) {
return null;
}
isTypeOnlyExport(node) {
return false;
}
findExportUsage(node) {
return [];
}
detectTestFramework(node) {
return 'jest';
}
detectTestType(node) {
return 'unit';
}
extractDescribe(node) {
return null;
}
extractIt(node) {
return null;
}
extractBeforeEach(node) {
return [];
}
extractAfterEach(node) {
return [];
}
extractBeforeAll(node) {
return [];
}
extractAfterAll(node) {
return [];
}
extractTestSetup(node) {
return [];
}
extractTestTeardown(node) {
return [];
}
extractAssertions(node) {
return [];
}
detectVisualTestPlatform(node) {
return 'percy';
}
detectVisualTestType(node) {
return 'snapshot';
}
extractVisualTestName(node) {
return 'visual-test';
}
extractVisualTestSelector(node) {
return null;
}
extractVisualTestOptions(node) {
return {};
}
extractBeforeHook(node) {
return null;
}
extractAfterHook(node) {
return null;
}
extractVisualTestAssertions(node) {
return [];
}
extractVisualTestDependencies(node) {
return [];
}
findCrossReferences(node) {
// Implementation for finding cross references
}
countParameters(node) {
return 0;
}
countLines(code) {
return code.split('\n').length;
}
countStatements(node) {
return 1;
}
countExpressions(node) {
return 1;
}
calculateNestingDepth(node) {
return 1;
}
calculateOverallComplexity(cyclomatic, cognitive, nesting) {
const score = cyclomatic + cognitive + nesting;
if (score < 10)
return 'low';
if (score < 20)
return 'medium';
if (score < 30)
return 'high';
return 'very-high';
}
calculateCohesion(ast) {
return 0.8;
}
calculateCoupling(ast) {
return 0.3;
}
calculateAbstraction(ast) {
return 0.7;
}
calculateEncapsulation(ast) {
return 0.6;
}
calculatePolymorphism(ast) {
return 0.4;
}
calculateInheritance(ast) {
return 0.3;
}
calculateComposition(ast) {
return 0.5;
}
calculateModularity(ast) {
return 0.7;
}
calculateReusability(ast) {
return 0.6;
}
calculateReadability(ast) {
return 0.8;
}
calculateOverallMaintainability(cohesion, coupling, abstraction, encapsulation, polymorphism, inheritance, composition, modularity, reusability, readability) {
const score = (cohesion + (1 - coupling) + abstraction + encapsulation +
polymorphism + inheritance + composition + modularity +
reusability + readability) / 10;
if (score >= 0.8)
return 'excellent';
if (score >= 0.6)
return 'good';
if (score >= 0.4)
return 'fair';
return 'poor';
}
calculateTestCoverage(ast) {
return 0.7;
}
calculateTestIsolation(ast) {
return 0.8;
}
calculateMocking(ast) {
return 0.6;
}
calculateAssertions(ast) {
return 0.7;
}
calculateTestSetup(ast) {
return 0.8;
}
calculateTestTeardown(ast) {
return 0.7;
}
calculateTestData(ast) {
return 0.6;
}
calculateEdgeCases(ast) {
return 0.5;
}
calculateErrorHandling(ast) {
return 0.7;
}
calculatePerformance(ast) {
return 0.8;
}
calculateOverallTestability(coverage, isolation, mocking, assertions, setup, teardown, data, edgeCases, errorHandling, performance) {
const score = (coverage + isolation + mocking + assertions + setup +
teardown + data + edgeCases + errorHandling + performance) / 10;
if (score >= 0.8)
return 'excellent';
if (score >= 0.6)
return 'good';
if (score >= 0.4)
return 'fair';
return 'poor';
}
countVariables(ast) {
let count = 0;
this.traverseAST(ast, (node) => {
if (node.type === 'variable')
count++;
});
return count;
}
countImports(ast) {
let count = 0;
this.traverseAST(ast, (node) => {
if (node.type === 'import')
count++;
});
return count;
}
countExports(ast) {
let count = 0;
this.traverseAST(ast, (node) => {
if (node.type === 'export')
count++;
});
return count;
}
countDependencies(ast) {
let count = 0;
this.traverseAST(ast, (node) => {
if (node.type === 'import')
count++;
});
return count;
}
calculateConfidence(ast) {
return 0.9;
}
analyzeFunctionContext(node) {
return {
scope: 'function',
depth: 1,
parent: node.parent?.id || null,
siblings: [],
children: node.children?.map(child => child.id) || [],
variables: [],
functions: [],
imports: [],
exports: [],
dependencies: [],
testContext: null,
visualTestContext: null
};
}
analyzeClassContext(node) {
return {
scope: 'class',
depth: 1,
parent: node.parent?.id || null,
siblings: [],
children: node.children?.map(child => child.id) || [],
variables: [],
functions: [],
imports: [],
exports: [],
dependencies: [],
testContext: null,
visualTestContext: null
};
}
analyzeModuleContext(node) {
return {
scope: 'module',
depth: 1,
parent: node.parent?.id || null,
siblings: [],
children: node.children?.map(child => child.id) || [],
variables: [],
functions: [],
imports: [],
exports: [],
dependencies: [],
testContext: null,
visualTestContext: null
};
}
}
exports.ContextAnalysisEngine = ContextAnalysisEngine;
//# sourceMappingURL=ContextAnalysisEngine.js.map