From a50c3dea8cd3c55a3380e9855c24f17f3de1f8fd Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:24:14 +0000 Subject: [PATCH 1/4] Add Presenter VM Property Analyzer Script --- scripts/analyze_presenters.ts | 199 ++++++++++++++++++++++++++ scripts/examples/sample.presenter.tsx | 49 +++++++ scripts/package.json | 27 ++++ 3 files changed, 275 insertions(+) create mode 100644 scripts/analyze_presenters.ts create mode 100644 scripts/examples/sample.presenter.tsx create mode 100644 scripts/package.json diff --git a/scripts/analyze_presenters.ts b/scripts/analyze_presenters.ts new file mode 100644 index 0000000..aef6b25 --- /dev/null +++ b/scripts/analyze_presenters.ts @@ -0,0 +1,199 @@ +#!/usr/bin/env ts-node + +/** + * Presenter VM Property Analyzer + * + * This script analyzes presenter files (*.presenter.tsx or *.presenter.ts) to identify + * properties in the VM method that are simple repeats of other properties or props. + * + * Usage: + * npx ts-node scripts/analyze_presenters.ts [directory] + * + * If no directory is specified, it will search in the current directory. + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as ts from 'typescript'; +import * as glob from 'glob'; + +interface PropertyMapping { + name: string; + value: string; + location: { + file: string; + line: number; + column: number; + }; + isRepeat: boolean; + repeatedFrom?: string; +} + +function findPresenterFiles(directory: string): string[] { + return glob.sync(`${directory}/**/*.presenter.{ts,tsx}`); +} + +function analyzeVmMethod(sourceFile: ts.SourceFile, filePath: string): PropertyMapping[] { + const propertyMappings: PropertyMapping[] = []; + const propNames = new Set(); + + // First pass: collect all prop names + function collectProps(node: ts.Node) { + if (ts.isParameter(node) && node.name && ts.isObjectBindingPattern(node.name)) { + node.name.elements.forEach(element => { + if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) { + propNames.add(element.name.text); + } + }); + } + ts.forEachChild(node, collectProps); + } + + // Second pass: analyze VM method and find property mappings + function visit(node: ts.Node) { + if ( + ts.isMethodDeclaration(node) && + ts.isIdentifier(node.name) && + node.name.text === 'vm' + ) { + // Found VM method + if (node.body) { + ts.forEachChild(node.body, findReturnStatement); + } + } else { + ts.forEachChild(node, visit); + } + } + + function findReturnStatement(node: ts.Node) { + if (ts.isReturnStatement(node) && node.expression && ts.isObjectLiteralExpression(node.expression)) { + analyzeReturnedObject(node.expression); + } else { + ts.forEachChild(node, findReturnStatement); + } + } + + function analyzeReturnedObject(objectLiteral: ts.ObjectLiteralExpression) { + const properties = objectLiteral.properties; + const valueMap = new Map(); + + properties.forEach(prop => { + if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) { + const propName = prop.name.text; + const propValue = prop.initializer.getText(); + const { line, character } = sourceFile.getLineAndCharacterOfPosition(prop.getStart()); + + valueMap.set(propName, propValue); + + const mapping: PropertyMapping = { + name: propName, + value: propValue, + location: { + file: filePath, + line: line + 1, + column: character + 1, + }, + isRepeat: false + }; + + // Check if this property is a simple repeat of a prop + if (propNames.has(propValue)) { + mapping.isRepeat = true; + mapping.repeatedFrom = propValue; + } + + propertyMappings.push(mapping); + } + }); + + // Second pass to find properties that repeat other properties + propertyMappings.forEach(mapping => { + if (!mapping.isRepeat && valueMap.has(mapping.value)) { + mapping.isRepeat = true; + mapping.repeatedFrom = mapping.value; + } + }); + } + + // Start analysis + collectProps(sourceFile); + visit(sourceFile); + + return propertyMappings; +} + +function analyzeFile(filePath: string): PropertyMapping[] { + const fileContent = fs.readFileSync(filePath, 'utf-8'); + const sourceFile = ts.createSourceFile( + filePath, + fileContent, + ts.ScriptTarget.Latest, + true + ); + + return analyzeVmMethod(sourceFile, filePath); +} + +function formatResults(results: { file: string; properties: PropertyMapping[] }[]): string { + let output = ''; + + results.forEach(result => { + const repeatedProps = result.properties.filter(prop => prop.isRepeat); + + if (repeatedProps.length > 0) { + output += `\nFile: ${result.file}\n`; + output += '='.repeat(result.file.length + 6) + '\n'; + + repeatedProps.forEach(prop => { + output += ` - ${prop.name}: ${prop.value} (line ${prop.location.line})\n`; + output += ` Repeats: ${prop.repeatedFrom}\n`; + }); + } + }); + + if (output === '') { + output = 'No repeated properties found in any presenter files.'; + } + + return output; +} + +function main() { + const directory = process.argv[2] || '.'; + console.log(`Analyzing presenter files in: ${directory}`); + + const presenterFiles = findPresenterFiles(directory); + + if (presenterFiles.length === 0) { + console.log('No presenter files found.'); + return; + } + + console.log(`Found ${presenterFiles.length} presenter files.`); + + const results = presenterFiles.map(file => { + const properties = analyzeFile(file); + return { file, properties }; + }); + + const formattedResults = formatResults(results); + console.log('\nResults:'); + console.log(formattedResults); + + // Count statistics + const totalRepeatedProps = results.reduce( + (sum, result) => sum + result.properties.filter(prop => prop.isRepeat).length, + 0 + ); + + const filesWithRepeats = results.filter( + result => result.properties.some(prop => prop.isRepeat) + ).length; + + console.log('\nSummary:'); + console.log(`Total presenter files analyzed: ${presenterFiles.length}`); + console.log(`Files with repeated properties: ${filesWithRepeats}`); + console.log(`Total repeated properties found: ${totalRepeatedProps}`); +} + +main(); \ No newline at end of file diff --git a/scripts/examples/sample.presenter.tsx b/scripts/examples/sample.presenter.tsx new file mode 100644 index 0000000..3684439 --- /dev/null +++ b/scripts/examples/sample.presenter.tsx @@ -0,0 +1,49 @@ +import React from 'react'; + +interface SampleProps { + title: string; + description: string; + isActive: boolean; + onClick: () => void; + data: any; +} + +export class SamplePresenter { + constructor(private props: SampleProps) {} + + vm() { + const { title, description, isActive, onClick, data } = this.props; + + return { + // Simple repeats of props + heading: title, + content: description, + active: isActive, + + // Non-repeats (transformed props) + upperTitle: title.toUpperCase(), + + // Repeats of other properties + displayTitle: 'heading', + + // Function handlers + handleClick: onClick, + + // Complex properties + formattedData: JSON.stringify(data), + }; + } + + render() { + const vm = this.vm(); + + return ( +
+

{vm.heading}

+

{vm.content}

+ +
{vm.formattedData}
+
+ ); + } +} \ No newline at end of file diff --git a/scripts/package.json b/scripts/package.json new file mode 100644 index 0000000..837ae69 --- /dev/null +++ b/scripts/package.json @@ -0,0 +1,27 @@ +{ + "name": "presenter-vm-analyzer", + "version": "1.0.0", + "description": "Analyzes presenter files to identify redundant VM properties", + "main": "analyze_presenters.ts", + "scripts": { + "analyze": "ts-node analyze_presenters.ts", + "test": "ts-node analyze_presenters.ts ./examples" + }, + "keywords": [ + "typescript", + "presenter", + "analysis", + "react" + ], + "author": "Codegen", + "license": "MIT", + "dependencies": { + "glob": "^8.0.3", + "typescript": "^4.9.5" + }, + "devDependencies": { + "@types/glob": "^8.0.0", + "@types/node": "^18.11.18", + "ts-node": "^10.9.1" + } +} \ No newline at end of file From 384059cb877efcef4aaa594b9c337420beee1d87 Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:25:05 +0000 Subject: [PATCH 2/4] Automated pre-commit update --- scripts/analyze_presenters.ts | 358 ++++++++++++++------------ scripts/examples/sample.presenter.tsx | 88 +++---- scripts/package.json | 47 ++-- 3 files changed, 252 insertions(+), 241 deletions(-) diff --git a/scripts/analyze_presenters.ts b/scripts/analyze_presenters.ts index aef6b25..1faf042 100644 --- a/scripts/analyze_presenters.ts +++ b/scripts/analyze_presenters.ts @@ -2,198 +2,214 @@ /** * Presenter VM Property Analyzer - * + * * This script analyzes presenter files (*.presenter.tsx or *.presenter.ts) to identify * properties in the VM method that are simple repeats of other properties or props. - * + * * Usage: * npx ts-node scripts/analyze_presenters.ts [directory] - * + * * If no directory is specified, it will search in the current directory. */ -import * as fs from 'fs'; -import * as path from 'path'; -import * as ts from 'typescript'; -import * as glob from 'glob'; +import * as fs from "fs"; +import * as path from "path"; +import * as glob from "glob"; +import * as ts from "typescript"; interface PropertyMapping { - name: string; - value: string; - location: { - file: string; - line: number; - column: number; - }; - isRepeat: boolean; - repeatedFrom?: string; + name: string; + value: string; + location: { + file: string; + line: number; + column: number; + }; + isRepeat: boolean; + repeatedFrom?: string; } function findPresenterFiles(directory: string): string[] { - return glob.sync(`${directory}/**/*.presenter.{ts,tsx}`); + return glob.sync(`${directory}/**/*.presenter.{ts,tsx}`); } -function analyzeVmMethod(sourceFile: ts.SourceFile, filePath: string): PropertyMapping[] { - const propertyMappings: PropertyMapping[] = []; - const propNames = new Set(); - - // First pass: collect all prop names - function collectProps(node: ts.Node) { - if (ts.isParameter(node) && node.name && ts.isObjectBindingPattern(node.name)) { - node.name.elements.forEach(element => { - if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) { - propNames.add(element.name.text); - } - }); - } - ts.forEachChild(node, collectProps); - } - - // Second pass: analyze VM method and find property mappings - function visit(node: ts.Node) { - if ( - ts.isMethodDeclaration(node) && - ts.isIdentifier(node.name) && - node.name.text === 'vm' - ) { - // Found VM method - if (node.body) { - ts.forEachChild(node.body, findReturnStatement); - } - } else { - ts.forEachChild(node, visit); - } - } - - function findReturnStatement(node: ts.Node) { - if (ts.isReturnStatement(node) && node.expression && ts.isObjectLiteralExpression(node.expression)) { - analyzeReturnedObject(node.expression); - } else { - ts.forEachChild(node, findReturnStatement); - } - } - - function analyzeReturnedObject(objectLiteral: ts.ObjectLiteralExpression) { - const properties = objectLiteral.properties; - const valueMap = new Map(); - - properties.forEach(prop => { - if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) { - const propName = prop.name.text; - const propValue = prop.initializer.getText(); - const { line, character } = sourceFile.getLineAndCharacterOfPosition(prop.getStart()); - - valueMap.set(propName, propValue); - - const mapping: PropertyMapping = { - name: propName, - value: propValue, - location: { - file: filePath, - line: line + 1, - column: character + 1, - }, - isRepeat: false - }; - - // Check if this property is a simple repeat of a prop - if (propNames.has(propValue)) { - mapping.isRepeat = true; - mapping.repeatedFrom = propValue; - } - - propertyMappings.push(mapping); - } - }); - - // Second pass to find properties that repeat other properties - propertyMappings.forEach(mapping => { - if (!mapping.isRepeat && valueMap.has(mapping.value)) { - mapping.isRepeat = true; - mapping.repeatedFrom = mapping.value; - } - }); - } - - // Start analysis - collectProps(sourceFile); - visit(sourceFile); - - return propertyMappings; +function analyzeVmMethod( + sourceFile: ts.SourceFile, + filePath: string, +): PropertyMapping[] { + const propertyMappings: PropertyMapping[] = []; + const propNames = new Set(); + + // First pass: collect all prop names + function collectProps(node: ts.Node) { + if ( + ts.isParameter(node) && + node.name && + ts.isObjectBindingPattern(node.name) + ) { + node.name.elements.forEach((element) => { + if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) { + propNames.add(element.name.text); + } + }); + } + ts.forEachChild(node, collectProps); + } + + // Second pass: analyze VM method and find property mappings + function visit(node: ts.Node) { + if ( + ts.isMethodDeclaration(node) && + ts.isIdentifier(node.name) && + node.name.text === "vm" + ) { + // Found VM method + if (node.body) { + ts.forEachChild(node.body, findReturnStatement); + } + } else { + ts.forEachChild(node, visit); + } + } + + function findReturnStatement(node: ts.Node) { + if ( + ts.isReturnStatement(node) && + node.expression && + ts.isObjectLiteralExpression(node.expression) + ) { + analyzeReturnedObject(node.expression); + } else { + ts.forEachChild(node, findReturnStatement); + } + } + + function analyzeReturnedObject(objectLiteral: ts.ObjectLiteralExpression) { + const properties = objectLiteral.properties; + const valueMap = new Map(); + + properties.forEach((prop) => { + if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) { + const propName = prop.name.text; + const propValue = prop.initializer.getText(); + const { line, character } = sourceFile.getLineAndCharacterOfPosition( + prop.getStart(), + ); + + valueMap.set(propName, propValue); + + const mapping: PropertyMapping = { + name: propName, + value: propValue, + location: { + file: filePath, + line: line + 1, + column: character + 1, + }, + isRepeat: false, + }; + + // Check if this property is a simple repeat of a prop + if (propNames.has(propValue)) { + mapping.isRepeat = true; + mapping.repeatedFrom = propValue; + } + + propertyMappings.push(mapping); + } + }); + + // Second pass to find properties that repeat other properties + propertyMappings.forEach((mapping) => { + if (!mapping.isRepeat && valueMap.has(mapping.value)) { + mapping.isRepeat = true; + mapping.repeatedFrom = mapping.value; + } + }); + } + + // Start analysis + collectProps(sourceFile); + visit(sourceFile); + + return propertyMappings; } function analyzeFile(filePath: string): PropertyMapping[] { - const fileContent = fs.readFileSync(filePath, 'utf-8'); - const sourceFile = ts.createSourceFile( - filePath, - fileContent, - ts.ScriptTarget.Latest, - true - ); - - return analyzeVmMethod(sourceFile, filePath); + const fileContent = fs.readFileSync(filePath, "utf-8"); + const sourceFile = ts.createSourceFile( + filePath, + fileContent, + ts.ScriptTarget.Latest, + true, + ); + + return analyzeVmMethod(sourceFile, filePath); } -function formatResults(results: { file: string; properties: PropertyMapping[] }[]): string { - let output = ''; - - results.forEach(result => { - const repeatedProps = result.properties.filter(prop => prop.isRepeat); - - if (repeatedProps.length > 0) { - output += `\nFile: ${result.file}\n`; - output += '='.repeat(result.file.length + 6) + '\n'; - - repeatedProps.forEach(prop => { - output += ` - ${prop.name}: ${prop.value} (line ${prop.location.line})\n`; - output += ` Repeats: ${prop.repeatedFrom}\n`; - }); - } - }); - - if (output === '') { - output = 'No repeated properties found in any presenter files.'; - } - - return output; +function formatResults( + results: { file: string; properties: PropertyMapping[] }[], +): string { + let output = ""; + + results.forEach((result) => { + const repeatedProps = result.properties.filter((prop) => prop.isRepeat); + + if (repeatedProps.length > 0) { + output += `\nFile: ${result.file}\n`; + output += "=".repeat(result.file.length + 6) + "\n"; + + repeatedProps.forEach((prop) => { + output += ` - ${prop.name}: ${prop.value} (line ${prop.location.line})\n`; + output += ` Repeats: ${prop.repeatedFrom}\n`; + }); + } + }); + + if (output === "") { + output = "No repeated properties found in any presenter files."; + } + + return output; } function main() { - const directory = process.argv[2] || '.'; - console.log(`Analyzing presenter files in: ${directory}`); - - const presenterFiles = findPresenterFiles(directory); - - if (presenterFiles.length === 0) { - console.log('No presenter files found.'); - return; - } - - console.log(`Found ${presenterFiles.length} presenter files.`); - - const results = presenterFiles.map(file => { - const properties = analyzeFile(file); - return { file, properties }; - }); - - const formattedResults = formatResults(results); - console.log('\nResults:'); - console.log(formattedResults); - - // Count statistics - const totalRepeatedProps = results.reduce( - (sum, result) => sum + result.properties.filter(prop => prop.isRepeat).length, - 0 - ); - - const filesWithRepeats = results.filter( - result => result.properties.some(prop => prop.isRepeat) - ).length; - - console.log('\nSummary:'); - console.log(`Total presenter files analyzed: ${presenterFiles.length}`); - console.log(`Files with repeated properties: ${filesWithRepeats}`); - console.log(`Total repeated properties found: ${totalRepeatedProps}`); + const directory = process.argv[2] || "."; + console.log(`Analyzing presenter files in: ${directory}`); + + const presenterFiles = findPresenterFiles(directory); + + if (presenterFiles.length === 0) { + console.log("No presenter files found."); + return; + } + + console.log(`Found ${presenterFiles.length} presenter files.`); + + const results = presenterFiles.map((file) => { + const properties = analyzeFile(file); + return { file, properties }; + }); + + const formattedResults = formatResults(results); + console.log("\nResults:"); + console.log(formattedResults); + + // Count statistics + const totalRepeatedProps = results.reduce( + (sum, result) => + sum + result.properties.filter((prop) => prop.isRepeat).length, + 0, + ); + + const filesWithRepeats = results.filter((result) => + result.properties.some((prop) => prop.isRepeat), + ).length; + + console.log("\nSummary:"); + console.log(`Total presenter files analyzed: ${presenterFiles.length}`); + console.log(`Files with repeated properties: ${filesWithRepeats}`); + console.log(`Total repeated properties found: ${totalRepeatedProps}`); } -main(); \ No newline at end of file +main(); diff --git a/scripts/examples/sample.presenter.tsx b/scripts/examples/sample.presenter.tsx index 3684439..84677d6 100644 --- a/scripts/examples/sample.presenter.tsx +++ b/scripts/examples/sample.presenter.tsx @@ -1,49 +1,49 @@ -import React from 'react'; +import React from "react"; interface SampleProps { - title: string; - description: string; - isActive: boolean; - onClick: () => void; - data: any; + title: string; + description: string; + isActive: boolean; + onClick: () => void; + data: any; } export class SamplePresenter { - constructor(private props: SampleProps) {} - - vm() { - const { title, description, isActive, onClick, data } = this.props; - - return { - // Simple repeats of props - heading: title, - content: description, - active: isActive, - - // Non-repeats (transformed props) - upperTitle: title.toUpperCase(), - - // Repeats of other properties - displayTitle: 'heading', - - // Function handlers - handleClick: onClick, - - // Complex properties - formattedData: JSON.stringify(data), - }; - } - - render() { - const vm = this.vm(); - - return ( -
-

{vm.heading}

-

{vm.content}

- -
{vm.formattedData}
-
- ); - } -} \ No newline at end of file + constructor(private props: SampleProps) {} + + vm() { + const { title, description, isActive, onClick, data } = this.props; + + return { + // Simple repeats of props + heading: title, + content: description, + active: isActive, + + // Non-repeats (transformed props) + upperTitle: title.toUpperCase(), + + // Repeats of other properties + displayTitle: "heading", + + // Function handlers + handleClick: onClick, + + // Complex properties + formattedData: JSON.stringify(data), + }; + } + + render() { + const vm = this.vm(); + + return ( +
+

{vm.heading}

+

{vm.content}

+ +
{vm.formattedData}
+
+ ); + } +} diff --git a/scripts/package.json b/scripts/package.json index 837ae69..43c84b2 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -1,27 +1,22 @@ { - "name": "presenter-vm-analyzer", - "version": "1.0.0", - "description": "Analyzes presenter files to identify redundant VM properties", - "main": "analyze_presenters.ts", - "scripts": { - "analyze": "ts-node analyze_presenters.ts", - "test": "ts-node analyze_presenters.ts ./examples" - }, - "keywords": [ - "typescript", - "presenter", - "analysis", - "react" - ], - "author": "Codegen", - "license": "MIT", - "dependencies": { - "glob": "^8.0.3", - "typescript": "^4.9.5" - }, - "devDependencies": { - "@types/glob": "^8.0.0", - "@types/node": "^18.11.18", - "ts-node": "^10.9.1" - } -} \ No newline at end of file + "name": "presenter-vm-analyzer", + "version": "1.0.0", + "description": "Analyzes presenter files to identify redundant VM properties", + "main": "analyze_presenters.ts", + "scripts": { + "analyze": "ts-node analyze_presenters.ts", + "test": "ts-node analyze_presenters.ts ./examples" + }, + "keywords": ["typescript", "presenter", "analysis", "react"], + "author": "Codegen", + "license": "MIT", + "dependencies": { + "glob": "^8.0.3", + "typescript": "^4.9.5" + }, + "devDependencies": { + "@types/glob": "^8.0.0", + "@types/node": "^18.11.18", + "ts-node": "^10.9.1" + } +} From 84e8d360c3041e3f7793cc520a55fdc835686a8a Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:53:46 +0000 Subject: [PATCH 3/4] Optimize Presenter VM Property Analyzer Script for Better Performance --- scripts/analyze_presenters.ts | 73 +++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/scripts/analyze_presenters.ts b/scripts/analyze_presenters.ts index 1faf042..ed3191c 100644 --- a/scripts/analyze_presenters.ts +++ b/scripts/analyze_presenters.ts @@ -29,8 +29,18 @@ interface PropertyMapping { repeatedFrom?: string; } +// Use a more efficient glob pattern with ignore patterns function findPresenterFiles(directory: string): string[] { - return glob.sync(`${directory}/**/*.presenter.{ts,tsx}`); + // Add common directories to ignore + const ignorePatterns = [ + "**/node_modules/**", + "**/dist/**", + "**/build/**", + "**/coverage/**", + "**/.git/**", + ]; + + return glob.sync(`${directory}/**/*.presenter.{ts,tsx}`, { ignore: ignorePatterns }); } function analyzeVmMethod( @@ -40,8 +50,9 @@ function analyzeVmMethod( const propertyMappings: PropertyMapping[] = []; const propNames = new Set(); - // First pass: collect all prop names - function collectProps(node: ts.Node) { + // Optimize by combining the two passes into a single traversal + function visit(node: ts.Node) { + // Collect props from parameters if ( ts.isParameter(node) && node.name && @@ -53,23 +64,22 @@ function analyzeVmMethod( } }); } - ts.forEachChild(node, collectProps); - } - - // Second pass: analyze VM method and find property mappings - function visit(node: ts.Node) { + + // Find VM method and analyze if ( ts.isMethodDeclaration(node) && ts.isIdentifier(node.name) && - node.name.text === "vm" + node.name.text === "vm" && + node.body ) { - // Found VM method - if (node.body) { - ts.forEachChild(node.body, findReturnStatement); - } - } else { - ts.forEachChild(node, visit); + // Process the VM method body + ts.forEachChild(node.body, findReturnStatement); + // Skip further traversal for this branch + return; } + + // Continue traversal + ts.forEachChild(node, visit); } function findReturnStatement(node: ts.Node) { @@ -88,7 +98,8 @@ function analyzeVmMethod( const properties = objectLiteral.properties; const valueMap = new Map(); - properties.forEach((prop) => { + // Process all properties in a single pass + for (const prop of properties) { if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) { const propName = prop.name.text; const propValue = prop.initializer.getText(); @@ -117,26 +128,29 @@ function analyzeVmMethod( propertyMappings.push(mapping); } - }); + } // Second pass to find properties that repeat other properties - propertyMappings.forEach((mapping) => { + // This can't be combined with the first pass because we need all properties first + for (const mapping of propertyMappings) { if (!mapping.isRepeat && valueMap.has(mapping.value)) { mapping.isRepeat = true; mapping.repeatedFrom = mapping.value; } - }); + } } - // Start analysis - collectProps(sourceFile); + // Start analysis with a single traversal visit(sourceFile); return propertyMappings; } function analyzeFile(filePath: string): PropertyMapping[] { + // Cache file content to avoid multiple reads const fileContent = fs.readFileSync(filePath, "utf-8"); + + // Use a more efficient parsing strategy const sourceFile = ts.createSourceFile( filePath, fileContent, @@ -177,6 +191,7 @@ function main() { const directory = process.argv[2] || "."; console.log(`Analyzing presenter files in: ${directory}`); + // Find presenter files const presenterFiles = findPresenterFiles(directory); if (presenterFiles.length === 0) { @@ -186,10 +201,18 @@ function main() { console.log(`Found ${presenterFiles.length} presenter files.`); - const results = presenterFiles.map((file) => { - const properties = analyzeFile(file); - return { file, properties }; - }); + // Process files in batches to avoid memory pressure + const batchSize = 50; + const results: { file: string; properties: PropertyMapping[] }[] = []; + + for (let i = 0; i < presenterFiles.length; i += batchSize) { + const batch = presenterFiles.slice(i, i + batchSize); + const batchResults = batch.map((file) => { + const properties = analyzeFile(file); + return { file, properties }; + }); + results.push(...batchResults); + } const formattedResults = formatResults(results); console.log("\nResults:"); From 7579f9c02cccd6a6247fc363028e657ad6f0855e Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:54:32 +0000 Subject: [PATCH 4/4] Automated pre-commit update --- scripts/analyze_presenters.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/analyze_presenters.ts b/scripts/analyze_presenters.ts index ed3191c..fcf9cce 100644 --- a/scripts/analyze_presenters.ts +++ b/scripts/analyze_presenters.ts @@ -39,8 +39,10 @@ function findPresenterFiles(directory: string): string[] { "**/coverage/**", "**/.git/**", ]; - - return glob.sync(`${directory}/**/*.presenter.{ts,tsx}`, { ignore: ignorePatterns }); + + return glob.sync(`${directory}/**/*.presenter.{ts,tsx}`, { + ignore: ignorePatterns, + }); } function analyzeVmMethod( @@ -64,7 +66,7 @@ function analyzeVmMethod( } }); } - + // Find VM method and analyze if ( ts.isMethodDeclaration(node) && @@ -77,7 +79,7 @@ function analyzeVmMethod( // Skip further traversal for this branch return; } - + // Continue traversal ts.forEachChild(node, visit); } @@ -149,7 +151,7 @@ function analyzeVmMethod( function analyzeFile(filePath: string): PropertyMapping[] { // Cache file content to avoid multiple reads const fileContent = fs.readFileSync(filePath, "utf-8"); - + // Use a more efficient parsing strategy const sourceFile = ts.createSourceFile( filePath, @@ -204,7 +206,7 @@ function main() { // Process files in batches to avoid memory pressure const batchSize = 50; const results: { file: string; properties: PropertyMapping[] }[] = []; - + for (let i = 0; i < presenterFiles.length; i += batchSize) { const batch = presenterFiles.slice(i, i + batchSize); const batchResults = batch.map((file) => {