build(brocolli): move filename filtering into DiffingPluginWrapper

Closes #1719
This commit is contained in:
Caitlin Potter 2015-05-06 19:24:10 -04:00
parent 6bba289a3c
commit aaf3edd131
5 changed files with 149 additions and 43 deletions

View File

@ -30,6 +30,8 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
private tsServiceHost: ts.LanguageServiceHost;
private tsService: ts.LanguageService;
static includeExtensions = ['.ts'];
static excludeExtensions = ['.d.ts'];
constructor(public inputPath: string, public cachePath: string, public options) {
this.tsOpts = Object.create(options);
@ -46,8 +48,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
let pathsToEmit = [];
let pathsWithErrors = [];
treeDiff.changedPaths.filter((changedPath) =>
changedPath.match(/\.ts/) && !changedPath.match(/\.d\.ts/))
treeDiff.changedPaths
.forEach((tsFilePath) => {
if (!this.fileRegistry[tsFilePath]) {
this.fileRegistry[tsFilePath] = {version: 0};
@ -59,8 +60,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
pathsToEmit.push(tsFilePath);
});
treeDiff.removedPaths.filter((changedPath) =>
changedPath.match(/\.ts/) && !changedPath.match(/\.d\.ts/))
treeDiff.removedPaths
.forEach((tsFilePath) => {
console.log('removing outputs for', tsFilePath);

View File

@ -49,7 +49,6 @@ class DiffingPluginWrapper implements BroccoliTree {
cachePath = null;
outputPath = null;
constructor(private pluginClass, private wrappedPluginArguments) {
if (Array.isArray(wrappedPluginArguments[0])) {
this.inputTrees = wrappedPluginArguments[0];
@ -92,8 +91,10 @@ class DiffingPluginWrapper implements BroccoliTree {
private init() {
if (!this.initialized) {
let includeExtensions = this.pluginClass.includeExtensions || [];
let excludeExtensions = this.pluginClass.excludeExtensions || [];
this.initialized = true;
this.treeDiffer = new TreeDiffer(this.inputPath);
this.treeDiffer = new TreeDiffer(this.inputPath, includeExtensions, excludeExtensions);
this.wrappedPlugin =
new this.pluginClass(this.inputPath, this.cachePath, this.wrappedPluginArguments[1]);
}

View File

@ -13,43 +13,37 @@ let xtend = require('xtend');
class DiffingTraceurCompiler implements DiffingBroccoliPlugin {
constructor(public inputPath: string, public cachePath: string, public options) {}
static includeExtensions = ['.js', '.es6', '.cjs'];
rebuild(treeDiff: DiffResult) {
treeDiff.changedPaths.forEach((changedFilePath) => {
var extension = path.extname(changedFilePath).toLowerCase();
if (extension === '.js' || extension === '.es6' || extension === '.cjs') {
var traceurOpts = xtend({filename: changedFilePath}, this.options.traceurOptions);
var traceurOpts = xtend({filename: changedFilePath}, this.options.traceurOptions);
var fsOpts = {encoding: 'utf-8'};
var absoluteInputFilePath = path.join(this.inputPath, changedFilePath);
var sourcecode = fs.readFileSync(absoluteInputFilePath, fsOpts);
var fsOpts = {encoding: 'utf-8'};
var absoluteInputFilePath = path.join(this.inputPath, changedFilePath);
var sourcecode = fs.readFileSync(absoluteInputFilePath, fsOpts);
var result = traceur.compile(traceurOpts, changedFilePath, sourcecode);
var result = traceur.compile(traceurOpts, changedFilePath, sourcecode);
// TODO: we should fix the sourceMappingURL written by Traceur instead of overriding
// (but we might switch to typescript first)
var mapFilepath =
changedFilePath.replace(/\.\w+$/, '') + this.options.destSourceMapExtension;
result.js = result.js + '\n//# sourceMappingURL=./' + path.basename(mapFilepath);
// TODO: we should fix the sourceMappingURL written by Traceur instead of overriding
// (but we might switch to typescript first)
var mapFilepath = changedFilePath.replace(/\.\w+$/, '') + this.options.destSourceMapExtension;
result.js = result.js + '\n//# sourceMappingURL=./' + path.basename(mapFilepath);
var destFilepath = changedFilePath.replace(/\.\w+$/, this.options.destExtension);
var destFile = path.join(this.cachePath, destFilepath);
fse.mkdirsSync(path.dirname(destFile));
fs.writeFileSync(destFile, result.js, fsOpts);
var destFilepath = changedFilePath.replace(/\.\w+$/, this.options.destExtension);
var destFile = path.join(this.cachePath, destFilepath);
fse.mkdirsSync(path.dirname(destFile));
fs.writeFileSync(destFile, result.js, fsOpts);
var destMap = path.join(this.cachePath, mapFilepath);
result.sourceMap.file = destFilepath;
fs.writeFileSync(destMap, JSON.stringify(result.sourceMap), fsOpts);
}
var destMap = path.join(this.cachePath, mapFilepath);
result.sourceMap.file = destFilepath;
fs.writeFileSync(destMap, JSON.stringify(result.sourceMap), fsOpts);
});
treeDiff.removedPaths.forEach((removedFilePath) => {
var extension = path.extname(removedFilePath).toLowerCase();
if (extension === '.js' || extension === '.es6' || extension === '.cjs') {
var destFilepath = removedFilePath.replace(/\.\w+$/, this.options.destExtension);
var absoluteOuputFilePath = path.join(this.cachePath, destFilepath);
fs.unlinkSync(absoluteOuputFilePath);
}
var destFilepath = removedFilePath.replace(/\.\w+$/, this.options.destExtension);
var absoluteOuputFilePath = path.join(this.cachePath, destFilepath);
fs.unlinkSync(absoluteOuputFilePath);
});
}
}

View File

@ -102,6 +102,95 @@ describe('TreeDiffer', () => {
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt']);
});
it('should ignore files with extensions not listed in includeExtensions', () => {
let testDir = {
'dir1': {
'file-1.js': mockfs.file({content: 'file-1.js content', mtime: new Date(1000)}),
'file-2.md': mockfs.file({content: 'file-2.md content', mtime: new Date(1000)}),
'file-3.coffee': mockfs.file({content: 'file-3.coffee content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.cc': mockfs.file({content: 'file-1.1.cc content', mtime: new Date(1000)})
}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1', ['.js', '.coffee']);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js', 'file-3.coffee']);
// change two files
testDir['dir1']['file-1.js'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-3.coffee'] =
mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['subdir-1']['file-1.1.cc'] =
mockfs.file({content: 'file-1.1.cc content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js', 'file-3.coffee']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['dir1']['file-1.js'] = mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js']);
});
it('should ignore files with extensions listed in excludeExtensions', () => {
let testDir = {
'dir1': {
'file-1.ts': mockfs.file({content: 'file-1.ts content', mtime: new Date(1000)}),
'file-1.cs': mockfs.file({content: 'file-1.cs content', mtime: new Date(1000)}),
'file-1.d.cs': mockfs.file({content: 'file-1.d.cs content', mtime: new Date(1000)}),
'file-2.md': mockfs.file({content: 'file-2.md content', mtime: new Date(1000)}),
'file-3.ts': mockfs.file({content: 'file-3.ts content', mtime: new Date(1000)}),
'file-4.d.ts': mockfs.file({content: 'file-4.d.ts content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.cc': mockfs.file({content: 'file-1.1.cc content', mtime: new Date(1000)})
}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1', ['.ts', '.cs'], ['.d.ts', '.d.cs']);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.cs', 'file-1.ts', 'file-3.ts']);
// change two files
testDir['dir1']['file-1.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-1.cs'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-1.d.cs'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-3.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-4.d.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['subdir-1']['file-1.1.cc'] =
mockfs.file({content: 'file-1.1.cc content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.cs', 'file-1.ts', 'file-3.ts']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['dir1']['file-4.d.ts'] = mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual([]);
});
});
describe('diff of new files', () => {

View File

@ -8,8 +8,24 @@ export class TreeDiffer {
private fingerprints: {[key: string]: string} = Object.create(null);
private nextFingerprints: {[key: string]: string} = Object.create(null);
private rootDirName: string;
private include: RegExp = null;
private exclude: RegExp = null;
constructor(private rootPath: string) { this.rootDirName = path.basename(rootPath); }
constructor(private rootPath: string, includeExtensions?: string[],
excludeExtensions?: string[]) {
this.rootDirName = path.basename(rootPath);
let buildRegexp = (arr) => new RegExp(`(${arr.reduce(combine, "")})$`, "i");
this.include = (includeExtensions || []).length ? buildRegexp(includeExtensions) : null;
this.exclude = (excludeExtensions || []).length ? buildRegexp(excludeExtensions) : null;
function combine(prev, curr) {
if (curr.charAt(0) !== ".") throw new TypeError("Extension must begin with '.'");
curr = '(' + curr + ')';
return prev ? (prev + '|' + curr) : curr;
}
}
public diffTree(): DiffResult {
@ -30,9 +46,12 @@ export class TreeDiffer {
result.directoriesChecked++;
this.dirtyCheckPath(absolutePath, result);
} else {
result.filesChecked++;
if (this.isFileDirty(absolutePath, pathStat)) {
result.changedPaths.push(path.relative(this.rootPath, absolutePath));
if (!(this.include && !absolutePath.match(this.include)) &&
!(this.exclude && absolutePath.match(this.exclude))) {
result.filesChecked++;
if (this.isFileDirty(absolutePath, pathStat)) {
result.changedPaths.push(path.relative(this.rootPath, absolutePath));
}
}
}
});
@ -62,9 +81,12 @@ export class TreeDiffer {
private detectDeletionsAndUpdateFingerprints(result: DiffResult) {
for (let absolutePath in this.fingerprints) {
if (this.fingerprints[absolutePath] !== null) {
let relativePath = path.relative(this.rootPath, absolutePath);
result.removedPaths.push(relativePath);
if (!(this.include && !absolutePath.match(this.include)) &&
!(this.exclude && absolutePath.match(this.exclude))) {
if (this.fingerprints[absolutePath] !== null) {
let relativePath = path.relative(this.rootPath, absolutePath);
result.removedPaths.push(relativePath);
}
}
}
@ -93,8 +115,7 @@ class DirtyCheckingDiffResult {
constructor(public name: string) {}
toString() {
return `${pad(this.name, 40)}, ` +
`duration: ${pad(this.endTime - this.startTime, 5)}ms, ` +
return `${pad(this.name, 40)}, duration: ${pad(this.endTime - this.startTime, 5)}ms, ` +
`${pad(this.changedPaths.length + this.removedPaths.length, 5)} changes detected ` +
`(files: ${pad(this.filesChecked, 5)}, directories: ${pad(this.directoriesChecked, 4)})`;
}
@ -102,8 +123,9 @@ class DirtyCheckingDiffResult {
log(verbose) {
let prefixedPaths =
this.changedPaths.map((p) => `* ${p}`).concat(this.removedPaths.map((p) => `- ${p}`));
console.log(`Tree diff: ${this}` +
((verbose && prefixedPaths.length) ? ` [\n ${prefixedPaths.join('\n ')}\n]` : ''));
console.log(`Tree diff: ${this}` + ((verbose && prefixedPaths.length) ?
` [\n ${prefixedPaths.join('\n ')}\n]` :
''));
}
}