diff --git a/src/cache.ts b/src/cache.ts index b34928e..e2b9030 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -2,6 +2,7 @@ import * as ts from "typescript"; import * as graph from "graphlib"; import * as hash from "object-hash"; import * as fs from "fs"; +import * as _ from "lodash"; interface ICode { @@ -40,6 +41,7 @@ export class Cache public setDependency(importee: string, importer: string): void { + // importer -> importee this.dependencyTree.setEdge(importer, importee); } @@ -48,61 +50,65 @@ export class Cache this.treeComplete = true; } - public markAsDirty(fileName: string, _snapshot: ts.IScriptSnapshot) + public markAsDirty(id: string, _snapshot: ts.IScriptSnapshot) { - this.dependencyTree.setNode(fileName, { dirty: true }); + this.dependencyTree.setNode(id, { dirty: true }); } - public isDirty(fileName: string, _snapshot: ts.IScriptSnapshot): boolean + // returns true if node or any of its imports changed + public isDirty(id: string, _snapshot: ts.IScriptSnapshot, checkImports: boolean): boolean { - let label = this.dependencyTree.node(fileName) as INodeLabel; + let label = this.dependencyTree.node(id) as INodeLabel; - // TODO: also if any dependencies are dirty + if (checkImports || label.dirty) + return label.dirty; - return label.dirty; + let dependencies = graph.alg.dijkstra(this.dependencyTree, id); + + return _.some(_.keys(dependencies), (dependencyId: string) => (this.dependencyTree.node(dependencyId) as INodeLabel).dirty); } - public getCompiled(fileName: string, snapshot: ts.IScriptSnapshot, transform: () => ICode | undefined): ICode | undefined + public getCompiled(id: string, snapshot: ts.IScriptSnapshot, transform: () => ICode | undefined): ICode | undefined { - let path = this.makePath(fileName, snapshot); + let path = this.makePath(id, snapshot); - if (!fs.existsSync(path) || this.isDirty(fileName, snapshot)) + if (!fs.existsSync(path) || this.isDirty(id, snapshot, false)) { let data = transform(); - this.setCache(path, fileName, snapshot, data); + this.setCache(path, id, snapshot, data); return data; } return JSON.parse(fs.readFileSync(path, "utf8")) as ICode; } - public getDiagnostics(fileName: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): ts.Diagnostic[] + public getDiagnostics(id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): ts.Diagnostic[] { - let path = `${this.makePath(fileName, snapshot)}.diagnostics`; + let path = `${this.makePath(id, snapshot)}.diagnostics`; - if (!fs.existsSync(path) || this.isDirty(fileName, snapshot)) + if (!fs.existsSync(path) || this.isDirty(id, snapshot, true)) { let data = check(); - this.setCache(path, fileName, snapshot, data); + this.setCache(path, id, snapshot, data); return data; } return JSON.parse(fs.readFileSync(path, "utf8")) as ts.Diagnostic[]; } - private setCache(path: string, fileName: string, snapshot: ts.IScriptSnapshot, data: ts.Diagnostic[] | ICode | undefined): void + private setCache(path: string, id: string, snapshot: ts.IScriptSnapshot, data: ts.Diagnostic[] | ICode | undefined): void { if (data === undefined) return; fs.writeFileSync(path, JSON.stringify(data)); - this.markAsDirty(fileName, snapshot); + this.markAsDirty(id, snapshot); } - private makePath(fileName: string, snapshot: ts.IScriptSnapshot): string + private makePath(id: string, snapshot: ts.IScriptSnapshot): string { let data = snapshot.getText(0, snapshot.getLength()); - return `${this.cacheRoot}/${hash.sha1({ data, fileName })}`; + return `${this.cacheRoot}/${hash.sha1({ data, id })}`; } }