Skip to content

Commit b2bab54

Browse files
authored
Feature/incremental update (#64)
* Add model initialization, Implement listening for the file changes * Add an example of the classes layout for adding the incremental update feature * Add tests for the incremental update feature * Implement incremental update feature: Use proxy to track entities by file, Add methods to remove obsolete entities and relations * Change the ts2famix creating file and class code, leave comments regarding this * Remove unused files * Add testPathIgnorePatterns into the Jest configuration * Fix the failing smoke test * Refactor code for the Famix Class creation (#8) * Refactor code for the Famic Class creation * Connect vscode extension with ts2famix changes * Add neverthrow library, Throw the error when the tsconfig file is not found * Add better error handling for commands, Add response type for commands * Add the test cases list * Rename 'createOrGetFamixClass' method to 'ensureFamixClass' method * Inheritance incremental update (#20) * Add the source anchor deletion implementation * Refactor inheritance and interface creation * Add a FullyQualifiedNameEntity interface * Add catching the error for the extension incremental update * Update README.md * Split SourcedEntity class into 2 classes: SourcedEntity and EntityWithSourceAnchor * Properties incremental update (#59) * Add tests and incremental update for property * Import clause incremental update new (#58) * Add the source anchor deletion implementation * Refactor inheritance and interface creation * Add a FullyQualifiedNameEntity interface * Split SourcedEntity class into 2 classes: SourcedEntity and EntityWithSourceAnchor * Add tests for import clause * Implement ImportClause for named imports. Add incremental update for the imported entities (Inheritance and ImportClause). ---------------------------- Still need to resolve the issue with: - re-export - the cases when we choose to create the module over a file - finish file and module Famix elements creation, add tests - implement ImportClause for other types of imports * Add reexport tests * Add namespace import tests * Add implementation for the Import Clause for - named import/export; - namespace import/export; - reexport. Encapsulate ImportClause creation logic in a separate file * Add test with exporting interfaces for the inheritance * Remove the old ImportClause test * Fix getFamixEntityByFullyQualifiedName to work with all the entities that have fullyQualifiedName field * Fix getModuleSpecifierFromDeclaration to work with import without ts. We still need to verify how does it work with node_modules and import aliases * Add excluding files specified in tsconfig from watching * Add tests for incremental update of adding types * Incremental update cleanup (#63) * Review and fix tests
1 parent 76aad70 commit b2bab54

101 files changed

Lines changed: 6331 additions & 1365 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

jest.config.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
"^.+\\.tsx?$": ["ts-jest", { }]
88
},
99
"testEnvironment": "jest-environment-node",
10-
"verbose": true
10+
"verbose": true,
11+
"testPathIgnorePatterns": [
12+
"/node_modules/",
13+
"/vscode-extension/"
14+
]
1115
}

src/analyze.ts

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
import { Project } from "ts-morph";
1+
import { Project, SourceFile } from "ts-morph";
22
import * as fs from 'fs';
33
import { FamixRepository } from "./lib/famix/famix_repository";
44
import { Logger } from "tslog";
55
import { EntityDictionary, EntityDictionaryConfig } from "./famix_functions/EntityDictionary";
66
import path from "path";
77
import { TypeScriptToFamixProcessor } from "./analyze_functions/process_functions";
8+
import { getFamixIndexFileAnchorFileName } from "./helpers";
9+
import { isSourceFileAModule } from "./famix_functions/helpersTsMorphElementsProcessing";
10+
import { FamixBaseElement } from "./lib/famix/famix_base_element";
11+
import { getDirectDependentAssociations, getSourceFilesToUpdate, removeDependentAssociations } from "./helpers";
12+
import { getTransientDependentEntities } from "./helpers/transientDependencyResolverHelper";
813

914
export const logger = new Logger({ name: "ts2famix", minLevel: 2 });
1015

16+
export enum SourceFileChangeType {
17+
Create = 0,
18+
Update = 1,
19+
Delete = 2,
20+
}
21+
1122
/**
1223
* This class is used to build a Famix model from a TypeScript source code
1324
*/
@@ -59,20 +70,16 @@ export class Importer {
5970
private processEntities(project: Project): void {
6071
const onlyTypeScriptFiles = project.getSourceFiles().filter(f => f.getFilePath().endsWith('.ts'));
6172
this.processFunctions.processFiles(onlyTypeScriptFiles);
62-
const accesses = this.processFunctions.accessMap;
63-
const methodsAndFunctionsWithId = this.processFunctions.methodsAndFunctionsWithId;
64-
const classes = this.processFunctions.classes;
65-
const interfaces = this.processFunctions.interfaces;
66-
const modules = this.processFunctions.modules;
67-
const exports = this.processFunctions.listOfExportMaps;
68-
69-
this.processFunctions.processImportClausesForImportEqualsDeclarations(project.getSourceFiles(), exports);
70-
this.processFunctions.processImportClausesForModules(modules, exports);
71-
this.processFunctions.processAccesses(accesses);
72-
this.processFunctions.processInvocations(methodsAndFunctionsWithId);
73-
this.processFunctions.processInheritances(classes, interfaces);
74-
this.processFunctions.processConcretisations(classes, interfaces, methodsAndFunctionsWithId);
73+
74+
this.processReferences(onlyTypeScriptFiles, onlyTypeScriptFiles);
75+
}
7576

77+
private processReferences(sourceFiles: SourceFile[], allExistingSourceFiles: SourceFile[]): void {
78+
// TODO: process Access, Invocations, Concretisations
79+
this.processFunctions.processImportClausesForImportEqualsDeclarations(allExistingSourceFiles);
80+
81+
const modules = sourceFiles.filter(f => isSourceFileAModule(f));
82+
this.processFunctions.processImportClausesForModules(modules);
7683
}
7784

7885
/**
@@ -103,13 +110,47 @@ export class Importer {
103110

104111
//const famixRep = this.famixRepFromPaths(sourceFileNames);
105112

113+
this.project = project;
106114
this.initFamixRep(project);
107115

108116
this.processEntities(project);
109117

110118
return this.entityDictionary.famixRep;
111119
}
112120

121+
public updateFamixModelIncrementally(sourceFileChangeMap: Map<SourceFileChangeType, SourceFile[]>): void {
122+
const allChangedSourceFiles = Array.from(sourceFileChangeMap.values()).flat();
123+
124+
const removedEntities: FamixBaseElement[] = [];
125+
allChangedSourceFiles.forEach(
126+
file => {
127+
const filePath = getFamixIndexFileAnchorFileName(file.getFilePath(), this.entityDictionary.getAbsolutePath());
128+
const removed = this.entityDictionary.famixRep.removeEntitiesBySourceFile(filePath);
129+
removedEntities.push(...removed);
130+
}
131+
);
132+
133+
const allSourceFiles = this.project.getSourceFiles();
134+
const directDependentAssociations = getDirectDependentAssociations(removedEntities);
135+
const transientDependentAssociations = getTransientDependentEntities(this.entityDictionary, sourceFileChangeMap);
136+
137+
const associationsToRemove = [...directDependentAssociations, ...transientDependentAssociations];
138+
139+
removeDependentAssociations(this.entityDictionary.famixRep, associationsToRemove);
140+
141+
const sourceFilesToEnsure = getSourceFilesToUpdate(
142+
associationsToRemove, sourceFileChangeMap, allSourceFiles, this.entityDictionary.getAbsolutePath()
143+
);
144+
145+
this.processFunctions.processFiles(sourceFilesToEnsure);
146+
const sourceFilesToDelete = sourceFileChangeMap.get(SourceFileChangeType.Delete) || [];
147+
const existingSourceFiles = allSourceFiles.filter(
148+
file => !sourceFilesToDelete.includes(file)
149+
);
150+
this.processReferences(sourceFilesToEnsure, existingSourceFiles);
151+
152+
}
153+
113154
private initFamixRep(project: Project): void {
114155
// get compiler options
115156
const compilerOptions = project.getCompilerOptions();

0 commit comments

Comments
 (0)