UNPKG

smartui-migration-tool

Version:

Enterprise-grade CLI tool for migrating visual testing platforms to LambdaTest SmartUI

874 lines 28.3 kB
"use strict"; /** * Multi-Language AST Parser Framework * Phase 1: Advanced AST Parser Infrastructure */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiLanguageASTParser = void 0; const fs_1 = require("fs"); const babel = __importStar(require("@babel/parser")); const babelTraverse = __importStar(require("@babel/traverse")); class MultiLanguageASTParser { constructor() { this.parsers = new Map(); this.initializeParsers(); } initializeParsers() { // JavaScript/TypeScript Parser (Babel) this.parsers.set('javascript', new BabelASTParser('javascript')); this.parsers.set('typescript', new BabelASTParser('typescript')); // Python Parser (Custom implementation) this.parsers.set('python', new PythonASTParser()); // Java Parser (Custom implementation) this.parsers.set('java', new JavaASTParser()); // C# Parser (Custom implementation) this.parsers.set('csharp', new CSharpASTParser()); } async parseFile(filePath, config) { try { const code = await fs_1.promises.readFile(filePath, 'utf-8'); return this.parse(code, config); } catch (error) { return { success: false, errors: [{ message: `Failed to read file: ${error instanceof Error ? error.message : 'Unknown error'}`, code: 'FILE_READ_ERROR', position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }, severity: 'error' }], warnings: [], metadata: { language: config.language, framework: config.framework, platform: config.platform, complexity: 0, nodeCount: 0, importCount: 0, functionCount: 0, classCount: 0, testCount: 0, visualTestCount: 0, parseTime: 0, memoryUsage: 0 } }; } } parse(code, config) { const startTime = Date.now(); const startMemory = process.memoryUsage().heapUsed; try { const parser = this.parsers.get(config.language); if (!parser) { throw new Error(`Unsupported language: ${config.language}`); } const result = parser.parse(code, config); const endTime = Date.now(); const endMemory = process.memoryUsage().heapUsed; result.metadata.parseTime = endTime - startTime; result.metadata.memoryUsage = endMemory - startMemory; return result; } catch (error) { const endTime = Date.now(); return { success: false, errors: [{ message: `Parse error: ${error instanceof Error ? error.message : 'Unknown error'}`, code: 'PARSE_ERROR', position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }, severity: 'error' }], warnings: [], metadata: { language: config.language, framework: config.framework, platform: config.platform, complexity: 0, nodeCount: 0, importCount: 0, functionCount: 0, classCount: 0, testCount: 0, visualTestCount: 0, parseTime: endTime - startTime, memoryUsage: 0 } }; } } analyze(ast) { const parser = this.parsers.get(ast.language); if (!parser) { throw new Error(`Unsupported language: ${ast.language}`); } return parser.analyze(ast); } transform(ast, transformations) { const parser = this.parsers.get(ast.language); if (!parser) { throw new Error(`Unsupported language: ${ast.language}`); } return parser.transform(ast, transformations); } generate(ast) { const parser = this.parsers.get(ast.language); if (!parser) { throw new Error(`Unsupported language: ${ast.language}`); } return parser.generate(ast); } } exports.MultiLanguageASTParser = MultiLanguageASTParser; /** * Babel-based AST Parser for JavaScript/TypeScript */ class BabelASTParser { constructor(language) { this.language = language; } parse(code, config) { try { const babelConfig = { sourceType: config.sourceType || 'module', allowImportExportEverywhere: true, allowReturnOutsideFunction: true, allowSuperOutsideMethod: true, allowUndeclaredExports: true, plugins: this.getBabelPlugins(config), tokens: true, ranges: true, createParenthesizedExpressions: true, errorRecovery: true, strictMode: config.strictMode || false, attachComment: config.includeComments || false }; const ast = babel.parse(code, babelConfig); const universalAST = this.convertBabelToUniversal(ast, code, config); return { success: true, ast: universalAST, errors: [], warnings: [], metadata: this.calculateMetadata(universalAST, config) }; } catch (error) { return { success: false, errors: [{ message: `Babel parse error: ${error instanceof Error ? error.message : 'Unknown error'}`, code: 'BABEL_PARSE_ERROR', position: this.extractErrorPosition(error), severity: 'error' }], warnings: [], metadata: this.getEmptyMetadata(config) }; } } getBabelPlugins(config) { const plugins = [ 'jsx', 'decorators-legacy', 'classProperties', 'objectRestSpread', 'functionBind', 'exportDefaultFrom', 'exportNamespaceFrom', 'dynamicImport', 'nullishCoalescingOperator', 'optionalChaining', 'asyncGenerators', 'functionSent', 'throwExpressions', 'topLevelAwait' ]; if (config.language === 'typescript') { plugins.push('typescript'); } if (config.experimentalFeatures) { plugins.push('pipelineOperator', 'doExpressions', 'partialApplication'); } return plugins; } convertBabelToUniversal(babelAST, code, config) { const universalAST = { id: 'root', type: 'program', language: this.language, framework: config.framework, platform: config.platform, position: this.extractPosition(babelAST.loc), metadata: this.createMetadata(babelAST, config), children: [], raw: code }; this.traverseBabelAST(babelAST, universalAST, code); return universalAST; } traverseBabelAST(babelNode, universalNode, code) { if (!babelNode || typeof babelNode !== 'object') return; babelTraverse.default(babelNode, { enter: (path) => { const node = path.node; const universalChild = this.convertBabelNode(node, code, universalNode); if (universalChild) { universalNode.children?.push(universalChild); } } }); } convertBabelNode(babelNode, code, parent) { const nodeType = this.mapBabelNodeType(babelNode.type); if (!nodeType) return null; return { id: this.generateNodeId(babelNode), type: nodeType, language: this.language, position: this.extractPosition(babelNode.loc), metadata: this.createNodeMetadata(babelNode), parent, raw: this.extractRawCode(babelNode, code), children: [] }; } mapBabelNodeType(babelType) { const typeMap = { 'ImportDeclaration': 'import', 'ExportNamedDeclaration': 'export', 'ExportDefaultDeclaration': 'export', 'ExportAllDeclaration': 'export', 'ClassDeclaration': 'class', 'FunctionDeclaration': 'function', 'ArrowFunctionExpression': 'arrow-function', 'MethodDefinition': 'method', 'VariableDeclaration': 'variable', 'VariableDeclarator': 'variable', 'Decorator': 'decorator', 'TSInterfaceDeclaration': 'interface', 'TSTypeAliasDeclaration': 'type', 'TSEnumDeclaration': 'enum', 'TSModuleDeclaration': 'namespace', 'ExpressionStatement': 'statement', 'CallExpression': 'call', 'MemberExpression': 'member', 'AssignmentExpression': 'assignment', 'ConditionalExpression': 'conditional', 'ForStatement': 'loop', 'WhileStatement': 'loop', 'DoWhileStatement': 'loop', 'ForInStatement': 'loop', 'ForOfStatement': 'loop', 'TryStatement': 'try-catch', 'JSXElement': 'jsx-element', 'TemplateLiteral': 'template', 'StringLiteral': 'string', 'NumericLiteral': 'number', 'BooleanLiteral': 'boolean', 'ArrayExpression': 'array', 'ObjectExpression': 'object', 'AsyncFunctionExpression': 'async-function', 'GeneratorFunction': 'generator', 'ObjectPattern': 'destructuring', 'ArrayPattern': 'destructuring', 'SpreadElement': 'spread', 'RestElement': 'rest', 'OptionalMemberExpression': 'optional', 'NullishCoalescingExpression': 'nullish-coalescing', 'LogicalExpression': 'logical', 'BinaryExpression': 'binary', 'UnaryExpression': 'unary', 'UpdateExpression': 'update', 'NewExpression': 'new', 'ThisExpression': 'this', 'Super': 'super', 'YieldExpression': 'yield', 'AwaitExpression': 'await', 'ReturnStatement': 'return', 'ThrowStatement': 'throw', 'BreakStatement': 'break', 'ContinueStatement': 'continue', 'DebuggerStatement': 'debugger', 'WithStatement': 'with', 'SwitchStatement': 'switch', 'SwitchCase': 'case', 'LabeledStatement': 'label', 'BlockStatement': 'block', 'Program': 'program', 'File': 'file', 'Identifier': 'identifier', 'Literal': 'literal' }; return typeMap[babelType] || 'unknown'; } extractPosition(loc) { if (!loc) { return { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }; } return { start: { line: loc.start.line, column: loc.start.column, offset: loc.start.index || 0 }, end: { line: loc.end.line, column: loc.end.column, offset: loc.end.index || 0 } }; } createMetadata(node, config) { return { confidence: 1.0, context: [], dependencies: [], frameworkHints: config.framework ? [config.framework] : [], platformHints: config.platform ? [config.platform] : [], complexity: 'low', transformationPriority: 1 }; } createNodeMetadata(node) { return { confidence: 0.9, context: [], dependencies: [], frameworkHints: [], platformHints: [], complexity: 'low', transformationPriority: 1 }; } generateNodeId(node) { return `${node.type}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } extractRawCode(node, code) { if (node.start !== undefined && node.end !== undefined) { return code.slice(node.start, node.end); } return ''; } extractErrorPosition(error) { if (error.loc) { return this.extractPosition(error.loc); } return { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }; } calculateMetadata(ast, config) { const analysis = this.analyze(ast); return { language: config.language, framework: config.framework, platform: config.platform, complexity: analysis.complexity, nodeCount: analysis.nodes.length, importCount: analysis.imports.length, functionCount: analysis.functions.length, classCount: analysis.classes.length, testCount: analysis.testFiles.length, visualTestCount: analysis.visualTests.length, parseTime: 0, memoryUsage: 0 }; } getEmptyMetadata(config) { return { language: config.language, framework: config.framework, platform: config.platform, complexity: 0, nodeCount: 0, importCount: 0, functionCount: 0, classCount: 0, testCount: 0, visualTestCount: 0, parseTime: 0, memoryUsage: 0 }; } analyze(ast) { const nodes = []; const imports = []; const exports = []; const functions = []; const classes = []; const variables = []; const decorators = []; const annotations = []; const visualTests = []; const testFiles = []; const dependencies = []; const frameworks = []; const platforms = []; this.traverseUniversalAST(ast, (node) => { nodes.push(node); switch (node.type) { case 'import': imports.push(node); break; case 'export': exports.push(node); break; case 'function': case 'arrow-function': case 'async-function': case 'generator': functions.push(node); break; case 'class': classes.push(node); break; case 'variable': variables.push(node); break; case 'decorator': decorators.push(node); break; case 'annotation': annotations.push(node); break; } // Detect visual testing patterns if (this.isVisualTestNode(node)) { visualTests.push(node); } // Detect test files if (this.isTestFile(node)) { testFiles.push(node); } }); return { nodes, imports, exports, functions, classes, variables, decorators, annotations, visualTests, testFiles, dependencies, frameworks, platforms, complexity: this.calculateComplexity(nodes), maintainability: this.calculateMaintainability(nodes), testability: this.calculateTestability(nodes) }; } traverseUniversalAST(ast, callback) { callback(ast); if (ast.children) { ast.children.forEach(child => this.traverseUniversalAST(child, callback)); } } 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)); } isTestFile(node) { const testPatterns = [ /test/i, /spec/i, /\.test\./i, /\.spec\./i, /describe/i, /it\(/i, /expect\(/i ]; return testPatterns.some(pattern => pattern.test(node.raw)); } calculateComplexity(nodes) { let complexity = 0; nodes.forEach(node => { switch (node.type) { case 'loop': case 'conditional': case 'try-catch': case 'switch': complexity += 2; break; case 'function': case 'class': complexity += 1; break; } }); return complexity; } calculateMaintainability(nodes) { const totalNodes = nodes.length; const complexNodes = nodes.filter(node => ['loop', 'conditional', 'try-catch', 'switch'].includes(node.type)).length; return Math.max(0, 100 - (complexNodes / totalNodes) * 100); } calculateTestability(nodes) { const functions = nodes.filter(node => ['function', 'arrow-function', 'async-function', 'generator'].includes(node.type)).length; const testFiles = nodes.filter(node => this.isTestFile(node)).length; return Math.min(100, (testFiles / Math.max(1, functions)) * 100); } transform(ast, transformations) { // Implementation for AST transformations return ast; } generate(ast) { // Implementation for code generation return ast.raw; } validate(code) { try { const babelConfig = { sourceType: 'module', allowImportExportEverywhere: true, allowReturnOutsideFunction: true, allowSuperOutsideMethod: true, allowUndeclaredExports: true, plugins: this.getBabelPlugins({ language: this.language, includeComments: true, includeWhitespace: false, strictMode: false, experimentalFeatures: true, sourceType: 'module' }), errorRecovery: false }; babel.parse(code, babelConfig); return true; } catch (error) { return false; } } } /** * Python AST Parser (Custom Implementation) */ class PythonASTParser { constructor() { this.language = 'python'; } parse(code, config) { // Python AST parsing implementation return { success: true, ast: this.createUniversalAST(code, config), errors: [], warnings: [], metadata: this.getEmptyMetadata(config) }; } analyze(ast) { return this.getEmptyAnalysis(); } transform(ast, transformations) { return ast; } generate(ast) { return ast.raw; } validate(code) { // Simple validation for Python code try { // Basic Python syntax validation return code.trim().length > 0 && !code.includes('SyntaxError'); } catch (error) { return false; } } createUniversalAST(code, config) { return { id: 'python_root', type: 'program', language: 'python', framework: config.framework, platform: config.platform, position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }, metadata: { confidence: 1.0, context: [], dependencies: [], frameworkHints: [], platformHints: [], complexity: 'low', transformationPriority: 1 }, raw: code }; } getEmptyMetadata(config) { return { language: config.language, framework: config.framework, platform: config.platform, complexity: 0, nodeCount: 0, importCount: 0, functionCount: 0, classCount: 0, testCount: 0, visualTestCount: 0, parseTime: 0, memoryUsage: 0 }; } getEmptyAnalysis() { return { nodes: [], imports: [], exports: [], functions: [], classes: [], variables: [], decorators: [], annotations: [], visualTests: [], testFiles: [], dependencies: [], frameworks: [], platforms: [], complexity: 0, maintainability: 0, testability: 0 }; } } /** * Java AST Parser (Custom Implementation) */ class JavaASTParser { constructor() { this.language = 'java'; } parse(code, config) { // Java AST parsing implementation return { success: true, ast: this.createUniversalAST(code, config), errors: [], warnings: [], metadata: this.getEmptyMetadata(config) }; } analyze(ast) { return this.getEmptyAnalysis(); } transform(ast, transformations) { return ast; } generate(ast) { return ast.raw; } validate(code) { // Simple validation for Java code try { return code.trim().length > 0 && code.includes('class') && !code.includes('SyntaxError'); } catch (error) { return false; } } createUniversalAST(code, config) { return { id: 'java_root', type: 'program', language: 'java', framework: config.framework, platform: config.platform, position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }, metadata: { confidence: 1.0, context: [], dependencies: [], frameworkHints: [], platformHints: [], complexity: 'low', transformationPriority: 1 }, raw: code }; } getEmptyMetadata(config) { return { language: config.language, framework: config.framework, platform: config.platform, complexity: 0, nodeCount: 0, importCount: 0, functionCount: 0, classCount: 0, testCount: 0, visualTestCount: 0, parseTime: 0, memoryUsage: 0 }; } getEmptyAnalysis() { return { nodes: [], imports: [], exports: [], functions: [], classes: [], variables: [], decorators: [], annotations: [], visualTests: [], testFiles: [], dependencies: [], frameworks: [], platforms: [], complexity: 0, maintainability: 0, testability: 0 }; } } /** * C# AST Parser (Custom Implementation) */ class CSharpASTParser { constructor() { this.language = 'csharp'; } parse(code, config) { // C# AST parsing implementation return { success: true, ast: this.createUniversalAST(code, config), errors: [], warnings: [], metadata: this.getEmptyMetadata(config) }; } analyze(ast) { return this.getEmptyAnalysis(); } transform(ast, transformations) { return ast; } generate(ast) { return ast.raw; } validate(code) { // Simple validation for C# code try { return code.trim().length > 0 && code.includes('using') && !code.includes('SyntaxError'); } catch (error) { return false; } } createUniversalAST(code, config) { return { id: 'csharp_root', type: 'program', language: 'csharp', framework: config.framework, platform: config.platform, position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }, metadata: { confidence: 1.0, context: [], dependencies: [], frameworkHints: [], platformHints: [], complexity: 'low', transformationPriority: 1 }, raw: code }; } getEmptyMetadata(config) { return { language: config.language, framework: config.framework, platform: config.platform, complexity: 0, nodeCount: 0, importCount: 0, functionCount: 0, classCount: 0, testCount: 0, visualTestCount: 0, parseTime: 0, memoryUsage: 0 }; } getEmptyAnalysis() { return { nodes: [], imports: [], exports: [], functions: [], classes: [], variables: [], decorators: [], annotations: [], visualTests: [], testFiles: [], dependencies: [], frameworks: [], platforms: [], complexity: 0, maintainability: 0, testability: 0 }; } } //# sourceMappingURL=ASTParser.js.map