Skip to content

Commit ec96b70

Browse files
authored
feat: Add calculation of delta index (#2)
1 parent fae23f2 commit ec96b70

File tree

8 files changed

+1838
-16
lines changed

8 files changed

+1838
-16
lines changed

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,20 @@
3232
"homepage": "https://github.com/TypeScript-Heroes/node-typescript-parser#readme",
3333
"devDependencies": {
3434
"@types/jest": "^20.0.1",
35+
"@types/mock-fs": "^3.6.30",
3536
"@types/node": "^8.0.1",
3637
"del-cli": "^1.0.0",
3738
"jest": "^20.0.4",
39+
"mock-fs": "^4.4.1",
40+
"semantic-release": "^6.3.6",
3841
"ts-jest": "^20.0.6",
3942
"tslint": "^5.4.3",
4043
"tslint-config-airbnb": "^5.2.0",
4144
"tsutils": "^2.4.0",
42-
"typedoc": "^0.7.1",
43-
"semantic-release": "^6.3.6"
45+
"typedoc": "^0.7.1"
4446
},
4547
"dependencies": {
48+
"lodash": "^4.17.4",
4649
"tslib": "^1.7.1",
4750
"typescript": "^2.4.1"
4851
}

src/DeclarationIndex.ts

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { difference, differenceWith, intersection, isEqual } from 'lodash';
12
import { join, normalize, relative, resolve } from 'path';
23

34
import { DeclarationInfo } from './declarations/DeclarationInfo';
@@ -34,10 +35,16 @@ function getNodeLibraryName(path: string): string {
3435
*/
3536
type Resources = { [name: string]: Resource };
3637

37-
// export type DeltaIndex = {
38-
// deleted: string[];
39-
// updated: { [declaration: string]: DeclarationInfo[] };
40-
// };
38+
/**
39+
* IndexDelta type, is calculated by the declaration index to give an overview, what has changed in the index.
40+
* Returns a list of deleted declarations, newly added declarations (with the corresponding infos) and
41+
* which declarations have been updated (with all declarations under that name).
42+
*/
43+
export type IndexDelta = {
44+
added: { [declaration: string]: DeclarationInfo[] };
45+
updated: { [declaration: string]: DeclarationInfo[] };
46+
deleted: string[];
47+
};
4148

4249
/**
4350
* Interface for file changes. Contains lists of file uri's to the specific action.
@@ -119,6 +126,48 @@ export class DeclarationIndex {
119126

120127
constructor(private parser: TypescriptParser, private rootPath: string) { }
121128

129+
/**
130+
* Calculates the differences between two indices. Calculates removed, added and updated declarations.
131+
* The updated declarations are calculated and all declarations that the new index contains are inserted in the list.
132+
*
133+
* @static
134+
* @param {{ [declaration: string]: DeclarationInfo[] }} oldIndex
135+
* @param {{ [declaration: string]: DeclarationInfo[] }} newIndex
136+
* @returns {IndexDelta}
137+
* @memberof DeclarationIndex
138+
*/
139+
public static calculateIndexDelta(
140+
oldIndex: { [declaration: string]: DeclarationInfo[] },
141+
newIndex: { [declaration: string]: DeclarationInfo[] },
142+
): IndexDelta {
143+
const oldKeys = Object.keys(oldIndex);
144+
const newKeys = Object.keys(newIndex);
145+
146+
return {
147+
added: difference(newKeys, oldKeys).reduce(
148+
(obj, currentKey) => {
149+
obj[currentKey] = newIndex[currentKey];
150+
return obj;
151+
},
152+
{} as { [declaration: string]: DeclarationInfo[] },
153+
),
154+
updated: intersection(oldKeys, newKeys).reduce(
155+
(obj, currentKey) => {
156+
const old = oldIndex[currentKey];
157+
const neu = newIndex[currentKey];
158+
159+
if (differenceWith(neu, old, isEqual).length > 0 || differenceWith(old, neu, isEqual).length > 0) {
160+
obj[currentKey] = neu;
161+
}
162+
163+
return obj;
164+
},
165+
{} as { [declaration: string]: DeclarationInfo[] },
166+
),
167+
deleted: difference(oldKeys, newKeys),
168+
};
169+
}
170+
122171
/**
123172
* Resets the whole index. Does delete everything. Period.
124173
* Is useful for unit testing or similar things.
@@ -159,13 +208,14 @@ export class DeclarationIndex {
159208

160209
/**
161210
* Is called when file events happen. Does reindex for the changed files and creates a new index.
211+
* Returns the differences for the new index.
162212
*
163213
* @param {FileEvent[]} changes
164-
* @returns {Promise<void>}
214+
* @returns {Promise<IndexDelta>}
165215
*
166216
* @memberof DeclarationIndex
167217
*/
168-
public async reindexForChanges(changes: FileChanges): Promise<void> {
218+
public async reindexForChanges(changes: FileChanges): Promise<IndexDelta> {
169219
const rebuildResources: string[] = [];
170220
const removeResources: string[] = [];
171221
const rebuildFiles: string[] = [];
@@ -212,11 +262,10 @@ export class DeclarationIndex {
212262
for (const key of Object.keys(resources)) {
213263
this.parsedResources[key] = resources[key];
214264
}
265+
const old = this._index || {};
215266
this._index = await this.createIndex(this.parsedResources);
216-
// return {
217-
// deleted: removeResources,
218-
// updated: await this.createIndex(resources),
219-
// };
267+
268+
return DeclarationIndex.calculateIndexDelta(old, this._index);
220269
}
221270

222271
/**

test/TypescriptParser.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ describe('TypescriptParser', () => {
2828
parser = new TypescriptParser();
2929
});
3030

31+
describe('Source parsing', () => {
32+
33+
it('should parse a source code string correctly', async () => {
34+
const parsed = await parser.parseSource(`import {foo} from 'bar'; class Foobar {}; const bar = new Foobar();`);
35+
36+
expect(parsed).toMatchSnapshot();
37+
});
38+
39+
});
40+
3141
describe('Import parsing', () => {
3242

3343
const file = getWorkspaceFile('typescript-parser/importsOnly.ts');

test/__snapshots__/TypescriptParser.spec.ts.snap

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,3 +890,49 @@ StringImport {
890890
"start": 0,
891891
}
892892
`;
893+
894+
exports[`TypescriptParser Source parsing should parse a source code string correctly 1`] = `
895+
File {
896+
"declarations": Array [
897+
ClassDeclaration {
898+
"end": 40,
899+
"isExported": false,
900+
"methods": Array [],
901+
"name": "Foobar",
902+
"properties": Array [],
903+
"start": 25,
904+
},
905+
VariableDeclaration {
906+
"end": 67,
907+
"isConst": true,
908+
"isExported": false,
909+
"name": "bar",
910+
"start": 42,
911+
"type": undefined,
912+
},
913+
],
914+
"end": 67,
915+
"exports": Array [],
916+
"filePath": "inline.ts",
917+
"imports": Array [
918+
NamedImport {
919+
"end": 24,
920+
"libraryName": "bar",
921+
"specifiers": Array [
922+
SymbolSpecifier {
923+
"alias": undefined,
924+
"specifier": "foo",
925+
},
926+
],
927+
"start": 0,
928+
},
929+
],
930+
"resources": Array [],
931+
"rootPath": "/",
932+
"start": 0,
933+
"usages": Array [
934+
"bar",
935+
"Foobar",
936+
],
937+
}
938+
`;

test/code-generators/TypescriptCodeGenerator.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { TypescriptCodeGenerator } from '../../src/code-generators/TypescriptCodeGenerator';
22
import { TypescriptGenerationOptions } from '../../src/code-generators/TypescriptGenerationOptions';
3+
import { ClassDeclaration } from '../../src/declarations';
34
import { DeclarationVisibility } from '../../src/declarations/DeclarationVisibility';
45
import { MethodDeclaration } from '../../src/declarations/MethodDeclaration';
56
import { ParameterDeclaration } from '../../src/declarations/ParameterDeclaration';
67
import { PropertyDeclaration } from '../../src/declarations/PropertyDeclaration';
78
import { VariableDeclaration } from '../../src/declarations/VariableDeclaration';
9+
import { NotGeneratableYetError } from '../../src/errors/NotGeneratableYetError';
810
import { DefaultImport } from '../../src/imports/DefaultImport';
911
import { ExternalModuleImport } from '../../src/imports/ExternalModuleImport';
1012
import { NamedImport } from '../../src/imports/NamedImport';
@@ -81,4 +83,10 @@ describe('TypescriptCodeGenerator', () => {
8183
});
8284

8385
}
86+
87+
it('should throw on non generatable element', () => {
88+
const generator = new TypescriptCodeGenerator(defaultOptions);
89+
90+
expect(() => generator.generate(new ClassDeclaration('foo', true))).toThrow(NotGeneratableYetError);
91+
});
8492
});

0 commit comments

Comments
 (0)