build(brocolli): move filename filtering into DiffingPluginWrapper
Closes #1719
This commit is contained in:
parent
6bba289a3c
commit
aaf3edd131
|
@ -30,6 +30,8 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
private tsServiceHost: ts.LanguageServiceHost;
|
private tsServiceHost: ts.LanguageServiceHost;
|
||||||
private tsService: ts.LanguageService;
|
private tsService: ts.LanguageService;
|
||||||
|
|
||||||
|
static includeExtensions = ['.ts'];
|
||||||
|
static excludeExtensions = ['.d.ts'];
|
||||||
|
|
||||||
constructor(public inputPath: string, public cachePath: string, public options) {
|
constructor(public inputPath: string, public cachePath: string, public options) {
|
||||||
this.tsOpts = Object.create(options);
|
this.tsOpts = Object.create(options);
|
||||||
|
@ -46,8 +48,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
let pathsToEmit = [];
|
let pathsToEmit = [];
|
||||||
let pathsWithErrors = [];
|
let pathsWithErrors = [];
|
||||||
|
|
||||||
treeDiff.changedPaths.filter((changedPath) =>
|
treeDiff.changedPaths
|
||||||
changedPath.match(/\.ts/) && !changedPath.match(/\.d\.ts/))
|
|
||||||
.forEach((tsFilePath) => {
|
.forEach((tsFilePath) => {
|
||||||
if (!this.fileRegistry[tsFilePath]) {
|
if (!this.fileRegistry[tsFilePath]) {
|
||||||
this.fileRegistry[tsFilePath] = {version: 0};
|
this.fileRegistry[tsFilePath] = {version: 0};
|
||||||
|
@ -59,8 +60,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
pathsToEmit.push(tsFilePath);
|
pathsToEmit.push(tsFilePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
treeDiff.removedPaths.filter((changedPath) =>
|
treeDiff.removedPaths
|
||||||
changedPath.match(/\.ts/) && !changedPath.match(/\.d\.ts/))
|
|
||||||
.forEach((tsFilePath) => {
|
.forEach((tsFilePath) => {
|
||||||
console.log('removing outputs for', tsFilePath);
|
console.log('removing outputs for', tsFilePath);
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ class DiffingPluginWrapper implements BroccoliTree {
|
||||||
cachePath = null;
|
cachePath = null;
|
||||||
outputPath = null;
|
outputPath = null;
|
||||||
|
|
||||||
|
|
||||||
constructor(private pluginClass, private wrappedPluginArguments) {
|
constructor(private pluginClass, private wrappedPluginArguments) {
|
||||||
if (Array.isArray(wrappedPluginArguments[0])) {
|
if (Array.isArray(wrappedPluginArguments[0])) {
|
||||||
this.inputTrees = wrappedPluginArguments[0];
|
this.inputTrees = wrappedPluginArguments[0];
|
||||||
|
@ -92,8 +91,10 @@ class DiffingPluginWrapper implements BroccoliTree {
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
if (!this.initialized) {
|
if (!this.initialized) {
|
||||||
|
let includeExtensions = this.pluginClass.includeExtensions || [];
|
||||||
|
let excludeExtensions = this.pluginClass.excludeExtensions || [];
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
this.treeDiffer = new TreeDiffer(this.inputPath);
|
this.treeDiffer = new TreeDiffer(this.inputPath, includeExtensions, excludeExtensions);
|
||||||
this.wrappedPlugin =
|
this.wrappedPlugin =
|
||||||
new this.pluginClass(this.inputPath, this.cachePath, this.wrappedPluginArguments[1]);
|
new this.pluginClass(this.inputPath, this.cachePath, this.wrappedPluginArguments[1]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,43 +13,37 @@ let xtend = require('xtend');
|
||||||
class DiffingTraceurCompiler implements DiffingBroccoliPlugin {
|
class DiffingTraceurCompiler implements DiffingBroccoliPlugin {
|
||||||
constructor(public inputPath: string, public cachePath: string, public options) {}
|
constructor(public inputPath: string, public cachePath: string, public options) {}
|
||||||
|
|
||||||
|
static includeExtensions = ['.js', '.es6', '.cjs'];
|
||||||
|
|
||||||
rebuild(treeDiff: DiffResult) {
|
rebuild(treeDiff: DiffResult) {
|
||||||
treeDiff.changedPaths.forEach((changedFilePath) => {
|
treeDiff.changedPaths.forEach((changedFilePath) => {
|
||||||
var extension = path.extname(changedFilePath).toLowerCase();
|
var traceurOpts = xtend({filename: changedFilePath}, this.options.traceurOptions);
|
||||||
if (extension === '.js' || extension === '.es6' || extension === '.cjs') {
|
|
||||||
var traceurOpts = xtend({filename: changedFilePath}, this.options.traceurOptions);
|
|
||||||
|
|
||||||
var fsOpts = {encoding: 'utf-8'};
|
var fsOpts = {encoding: 'utf-8'};
|
||||||
var absoluteInputFilePath = path.join(this.inputPath, changedFilePath);
|
var absoluteInputFilePath = path.join(this.inputPath, changedFilePath);
|
||||||
var sourcecode = fs.readFileSync(absoluteInputFilePath, fsOpts);
|
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
|
// TODO: we should fix the sourceMappingURL written by Traceur instead of overriding
|
||||||
// (but we might switch to typescript first)
|
// (but we might switch to typescript first)
|
||||||
var mapFilepath =
|
var mapFilepath = changedFilePath.replace(/\.\w+$/, '') + this.options.destSourceMapExtension;
|
||||||
changedFilePath.replace(/\.\w+$/, '') + this.options.destSourceMapExtension;
|
result.js = result.js + '\n//# sourceMappingURL=./' + path.basename(mapFilepath);
|
||||||
result.js = result.js + '\n//# sourceMappingURL=./' + path.basename(mapFilepath);
|
|
||||||
|
|
||||||
var destFilepath = changedFilePath.replace(/\.\w+$/, this.options.destExtension);
|
var destFilepath = changedFilePath.replace(/\.\w+$/, this.options.destExtension);
|
||||||
var destFile = path.join(this.cachePath, destFilepath);
|
var destFile = path.join(this.cachePath, destFilepath);
|
||||||
fse.mkdirsSync(path.dirname(destFile));
|
fse.mkdirsSync(path.dirname(destFile));
|
||||||
fs.writeFileSync(destFile, result.js, fsOpts);
|
fs.writeFileSync(destFile, result.js, fsOpts);
|
||||||
|
|
||||||
var destMap = path.join(this.cachePath, mapFilepath);
|
var destMap = path.join(this.cachePath, mapFilepath);
|
||||||
result.sourceMap.file = destFilepath;
|
result.sourceMap.file = destFilepath;
|
||||||
fs.writeFileSync(destMap, JSON.stringify(result.sourceMap), fsOpts);
|
fs.writeFileSync(destMap, JSON.stringify(result.sourceMap), fsOpts);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
treeDiff.removedPaths.forEach((removedFilePath) => {
|
treeDiff.removedPaths.forEach((removedFilePath) => {
|
||||||
var extension = path.extname(removedFilePath).toLowerCase();
|
var destFilepath = removedFilePath.replace(/\.\w+$/, this.options.destExtension);
|
||||||
if (extension === '.js' || extension === '.es6' || extension === '.cjs') {
|
var absoluteOuputFilePath = path.join(this.cachePath, destFilepath);
|
||||||
var destFilepath = removedFilePath.replace(/\.\w+$/, this.options.destExtension);
|
fs.unlinkSync(absoluteOuputFilePath);
|
||||||
var absoluteOuputFilePath = path.join(this.cachePath, destFilepath);
|
|
||||||
fs.unlinkSync(absoluteOuputFilePath);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,95 @@ describe('TreeDiffer', () => {
|
||||||
diffResult = differ.diffTree();
|
diffResult = differ.diffTree();
|
||||||
expect(diffResult.changedPaths).toEqual(['file-1.txt']);
|
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', () => {
|
describe('diff of new files', () => {
|
||||||
|
|
|
@ -8,8 +8,24 @@ export class TreeDiffer {
|
||||||
private fingerprints: {[key: string]: string} = Object.create(null);
|
private fingerprints: {[key: string]: string} = Object.create(null);
|
||||||
private nextFingerprints: {[key: string]: string} = Object.create(null);
|
private nextFingerprints: {[key: string]: string} = Object.create(null);
|
||||||
private rootDirName: string;
|
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 {
|
public diffTree(): DiffResult {
|
||||||
|
@ -30,9 +46,12 @@ export class TreeDiffer {
|
||||||
result.directoriesChecked++;
|
result.directoriesChecked++;
|
||||||
this.dirtyCheckPath(absolutePath, result);
|
this.dirtyCheckPath(absolutePath, result);
|
||||||
} else {
|
} else {
|
||||||
result.filesChecked++;
|
if (!(this.include && !absolutePath.match(this.include)) &&
|
||||||
if (this.isFileDirty(absolutePath, pathStat)) {
|
!(this.exclude && absolutePath.match(this.exclude))) {
|
||||||
result.changedPaths.push(path.relative(this.rootPath, absolutePath));
|
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) {
|
private detectDeletionsAndUpdateFingerprints(result: DiffResult) {
|
||||||
for (let absolutePath in this.fingerprints) {
|
for (let absolutePath in this.fingerprints) {
|
||||||
if (this.fingerprints[absolutePath] !== null) {
|
if (!(this.include && !absolutePath.match(this.include)) &&
|
||||||
let relativePath = path.relative(this.rootPath, absolutePath);
|
!(this.exclude && absolutePath.match(this.exclude))) {
|
||||||
result.removedPaths.push(relativePath);
|
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) {}
|
constructor(public name: string) {}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return `${pad(this.name, 40)}, ` +
|
return `${pad(this.name, 40)}, duration: ${pad(this.endTime - this.startTime, 5)}ms, ` +
|
||||||
`duration: ${pad(this.endTime - this.startTime, 5)}ms, ` +
|
|
||||||
`${pad(this.changedPaths.length + this.removedPaths.length, 5)} changes detected ` +
|
`${pad(this.changedPaths.length + this.removedPaths.length, 5)} changes detected ` +
|
||||||
`(files: ${pad(this.filesChecked, 5)}, directories: ${pad(this.directoriesChecked, 4)})`;
|
`(files: ${pad(this.filesChecked, 5)}, directories: ${pad(this.directoriesChecked, 4)})`;
|
||||||
}
|
}
|
||||||
|
@ -102,8 +123,9 @@ class DirtyCheckingDiffResult {
|
||||||
log(verbose) {
|
log(verbose) {
|
||||||
let prefixedPaths =
|
let prefixedPaths =
|
||||||
this.changedPaths.map((p) => `* ${p}`).concat(this.removedPaths.map((p) => `- ${p}`));
|
this.changedPaths.map((p) => `* ${p}`).concat(this.removedPaths.map((p) => `- ${p}`));
|
||||||
console.log(`Tree diff: ${this}` +
|
console.log(`Tree diff: ${this}` + ((verbose && prefixedPaths.length) ?
|
||||||
((verbose && prefixedPaths.length) ? ` [\n ${prefixedPaths.join('\n ')}\n]` : ''));
|
` [\n ${prefixedPaths.join('\n ')}\n]` :
|
||||||
|
''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue