Skip to content

Commit e8c71c0

Browse files
committed
Merge remote-tracking branch 'upstream/master'
* upstream/master: add new npm deps with improved gulp for dev (#328)
2 parents 029e055 + 58d4f4d commit e8c71c0

File tree

6 files changed

+6163
-104
lines changed

6 files changed

+6163
-104
lines changed

.vscode/tasks.json

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
// Available variables which can be used inside of strings.
2-
// ${workspaceRoot}: the root folder of the team
3-
// ${file}: the current opened file
4-
// ${fileBasename}: the current opened file's basename
5-
// ${fileDirname}: the current opened file's dirname
6-
// ${fileExtname}: the current opened file's extension
7-
// ${cwd}: the current working directory of the spawned process
8-
// A task runner that calls a custom npm script that compiles the extension.
91
{
102
"version": "2.0.0",
113
"presentation": {
@@ -16,48 +8,49 @@
168
},
179
"tasks": [
1810
{
19-
"label": "compile",
11+
"label": "Compile",
2012
"type": "npm",
2113
"script": "compile",
22-
"group": "build",
2314
"isBackground": true,
2415
"problemMatcher": [
2516
"$tsc",
2617
{
2718
"base": "$tslint5",
2819
"fileLocation": "relative"
2920
}
30-
]
31-
},
32-
{
33-
"type": "npm",
34-
"script": "lint",
35-
"problemMatcher": {
36-
"base": "$tslint5",
37-
"fileLocation": "relative"
21+
],
22+
"group": {
23+
"kind": "build",
24+
"isDefault": true
3825
}
3926
},
4027
{
41-
"type": "npm",
42-
"script": "watch",
43-
"isBackground": true,
44-
"problemMatcher": "$tsc-watch"
45-
},
46-
{
28+
"label": "Hygiene",
4729
"type": "gulp",
48-
"task": "hygiene",
30+
"task": "hygiene-watch",
31+
"isBackground": true,
32+
"presentation": {
33+
"echo": true,
34+
"reveal": "always",
35+
"focus": false,
36+
"panel": "shared"
37+
},
4938
"problemMatcher": [
5039
"$tsc",
5140
{
5241
"base": "$tslint5",
5342
"fileLocation": "relative"
5443
}
55-
]
44+
],
45+
"group": {
46+
"kind": "build",
47+
"isDefault": true
48+
}
5649
},
5750
{
58-
"label": "lint-staged",
59-
"type": "npm",
60-
"script": "lint-staged",
51+
"label": "Hygiene (staged)",
52+
"type": "gulp",
53+
"task": "hygiene-staged",
6154
"problemMatcher": [
6255
"$tsc",
6356
{
@@ -67,15 +60,9 @@
6760
]
6861
},
6962
{
63+
"label": "Hygiene (all)",
7064
"type": "gulp",
71-
"task": "hygiene-watch",
72-
"isBackground": true,
73-
"presentation": {
74-
"echo": true,
75-
"reveal": "always",
76-
"focus": false,
77-
"panel": "shared"
78-
},
65+
"task": "hygiene",
7966
"problemMatcher": [
8067
"$tsc",
8168
{

gulpfile.js

Lines changed: 158 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const tsfmt = require('typescript-formatter');
1212
const tslint = require('tslint');
1313
const relative = require('relative');
1414
const ts = require('gulp-typescript');
15-
const watch = require('gulp-watch');
15+
const watch = require('gulp-debounced-watch');
1616
const cp = require('child_process');
1717
const colors = require('colors/safe');
1818

@@ -42,7 +42,7 @@ const eolFilter = [
4242
'!.vscodeignore',
4343
'!LICENSE',
4444
'!**/node_modules/**',
45-
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,txt,md,json,yml}',
45+
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,txt,md,json,yml,pyc}',
4646
'!out/**/*',
4747
'!images/**/*',
4848
'!.vscode/**/*',
@@ -84,7 +84,21 @@ function reportFailures(failures) {
8484
});
8585
}
8686

87-
const hygiene = exports.hygiene = (some, options) => {
87+
88+
/**
89+
* @typedef {Object} hygieneOptions - creates a new type named 'SpecialType'
90+
* @property {boolean=} skipEOL - skipEOL check.
91+
* @property {boolean=} skipIndentationCheck - Skip indentation checks.
92+
* @property {boolean=} skipFormatCheck - Skip format checks.
93+
*/
94+
95+
/**
96+
*
97+
* @param {string[]} some
98+
* @param {hygieneOptions} options
99+
* @returns {NodeJS.EventEmitter}
100+
*/
101+
const hygiene = (some, options) => {
88102
options = options || {};
89103
let errorCount = 0;
90104
const eol = es.through(function (file) {
@@ -185,19 +199,29 @@ const hygiene = exports.hygiene = (some, options) => {
185199
return tsProject(reporter);
186200
}
187201

188-
const result = gulp.src(some || all, {
202+
// Misc file checks.
203+
let result = gulp.src(some || all, {
189204
base: '.'
190205
})
191206
.pipe(filter(f => !f.stat.isDirectory()))
192207
.pipe(filter(eolFilter))
193208
.pipe(options.skipEOL ? es.through() : eol)
194-
.pipe(filter(indentationFilter))
195-
.pipe(indentation);
209+
.pipe(filter(indentationFilter));
210+
211+
if (!options.skipIndentationCheck) {
212+
result = result
213+
.pipe(indentation);
214+
}
215+
216+
// Type script checks.
217+
let typescript = result
218+
.pipe(filter(tslintFilter));
196219

197-
const typescript = result
198-
.pipe(filter(tslintFilter))
199-
.pipe(formatting)
200-
.pipe(tsl)
220+
if (!options.skipFormatCheck) {
221+
typescript = typescript
222+
.pipe(formatting);
223+
}
224+
typescript = typescript.pipe(tsl)
201225
.pipe(tscFilesTracker)
202226
.pipe(tsc());
203227

@@ -211,68 +235,142 @@ const hygiene = exports.hygiene = (some, options) => {
211235
}));
212236
};
213237

214-
gulp.task('hygiene', () => hygiene());
238+
exports.hygiene = hygiene;
239+
240+
gulp.task('hygiene', () => run({ mode: 'all', skipFormatCheck: true, skipIndentationCheck: true }));
241+
242+
gulp.task('hygiene-staged', () => run({ mode: 'changes' }));
243+
244+
gulp.task('hygiene-watch', ['hygiene-staged', 'hygiene-watch-runner']);
215245

216-
gulp.task('hygiene-watch', function () {
217-
return watch(all, function () {
218-
console.clear();
219-
console.log('Checking hygiene...');
220-
run(true, true);
246+
gulp.task('hygiene-watch-runner', function () {
247+
return watch(all, { events: ['add', 'change'] }, function (event) {
248+
const start = new Date();
249+
console.log(`[${start.toLocaleTimeString()}] Starting '${colors.cyan('hygiene-watch-runner')}'...`);
250+
// Skip indentation and formatting checks to speed up linting.
251+
return run({ mode: 'watch', skipFormatCheck: true, skipIndentationCheck: true })
252+
.then(() => {
253+
const end = new Date();
254+
const time = (end.getTime() - start.getTime()) / 1000;
255+
console.log(`[${end.toLocaleTimeString()}] Finished '${colors.cyan('hygiene-watch-runner')}' after ${time} seconds`);
256+
});
221257
});
222258
});
223259

224-
function run(lintOnlyModifiedFiles, doNotExit) {
225-
function exitProcessOnError(ex) {
226-
console.error();
260+
/**
261+
* @typedef {Object} runOptions
262+
* @property {boolean=} exitOnError - Exit on error.
263+
* @property {'watch'|'changes'|'staged'|'all'} [mode=] - Mode.
264+
* @property {string[]=} files - Optional list of files to be modified.
265+
* @property {boolean=} skipIndentationCheck - Skip indentation checks.
266+
* @property {boolean=} skipFormatCheck - Skip format checks.
267+
*/
268+
269+
/**
270+
* Run the linters.
271+
* @param {runOptions} options
272+
* @param {Error} ex
273+
*/
274+
function exitHandler(options, ex) {
275+
console.error();
276+
if (ex) {
277+
console.error(ex);
227278
console.error(colors.red(ex));
228-
if (!doNotExit) {
229-
process.exit(1);
230-
}
231-
if (lintOnlyModifiedFiles && doNotExit) {
232-
console.log('Watching for changes...');
233-
}
234279
}
235-
process.on('unhandledRejection', (reason, p) => {
280+
if (options.exitOnError) {
281+
process.exit(1);
282+
}
283+
if (options.mode === 'watch') {
284+
console.log('Watching for changes...');
285+
}
286+
}
287+
288+
/**
289+
* Run the linters.
290+
* @param {runOptions} options
291+
* @return {Promise<void>}
292+
*/
293+
function run(options) {
294+
options = options ? options : {};
295+
process.once('unhandledRejection', (reason, p) => {
236296
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
237-
exitProcessOnError();
297+
exitHandler(options);
238298
});
239299

240-
cp.exec('git config core.autocrlf', (err, out) => {
241-
const skipEOL = out.trim() === 'true';
242-
if (!lintOnlyModifiedFiles && process.argv.length > 2) {
243-
return hygiene(process.argv.slice(2), {
244-
skipEOL: skipEOL
245-
}).on('error', exitProcessOnError);
246-
}
300+
return getGitSkipEOL()
301+
.then(skipEOL => {
302+
if (typeof options.mode !== 'string' && process.argv.length > 2) {
303+
return new Promise((resolve, reject) => {
304+
return hygiene(process.argv.slice(2), {
305+
skipEOL: skipEOL
306+
})
307+
.once('error', reject)
308+
.once('end', resolve);
309+
});
310+
}
247311

248-
let filesPromise;
249-
if (lintOnlyModifiedFiles) {
250-
filesPromise = Promise.all([getCachedFiles(), getModifiedFiles()]).then(filesList => {
251-
const files1 = filesList[0];
252-
const files2 = filesList[1];
253-
files2.forEach(file => {
254-
if (files1.indexOf(file) === -1) {
255-
files1.push(file);
256-
}
312+
return getFilesToProcess(options)
313+
.then(files => {
314+
return new Promise((resolve, reject) => {
315+
hygiene(files, {
316+
skipEOL: skipEOL,
317+
skipFormatCheck: options.skipFormatCheck,
318+
skipIndentationCheck: options.skipIndentationCheck
319+
})
320+
.once('end', () => {
321+
if (options.mode === 'watch') {
322+
console.log(colors.green('Hygiene passed with 0 errors 👍.'));
323+
console.log('Watching for changes...');
324+
}
325+
resolve();
326+
})
327+
.once('error', reject);
328+
});
257329
});
258-
return files1;
259-
});
260-
} else {
261-
filesPromise = getCachedFiles();
330+
})
331+
.catch(exitHandler.bind(options));
332+
}
333+
function getGitSkipEOL() {
334+
return new Promise(resolve => {
335+
cp.exec('git config core.autocrlf', (err, out) => {
336+
const skipEOL = out.trim() === 'true';
337+
resolve(skipEOL);
338+
});
339+
});
340+
}
341+
/**
342+
* Gets a list of files to be processed.
343+
* @param {runOptions} options
344+
* @return {Promise<string[]>}
345+
*/
346+
function getFilesToProcess(options) {
347+
switch (options.mode) {
348+
case 'all': {
349+
return Promise.resolve(all);
350+
}
351+
case 'watch':
352+
case 'changes': {
353+
return Promise.all([getCachedFiles(), getModifiedFiles()])
354+
.then(filesList => mergeFiles(filesList[0], filesList[1]));
355+
}
356+
default: {
357+
return getCachedFiles();
358+
}
359+
}
360+
}
361+
/**
362+
* Merges a list of files.
363+
* @param {string[]} files1
364+
* @param {string[]} files2
365+
*/
366+
function mergeFiles(files1, files2) {
367+
const files = files2.slice();
368+
files.forEach(file => {
369+
if (files.indexOf(file) === -1) {
370+
files.push(file);
262371
}
263-
filesPromise.then(files => {
264-
hygiene(files, {
265-
skipEOL: skipEOL
266-
})
267-
.on('end', () => {
268-
if (lintOnlyModifiedFiles && doNotExit) {
269-
console.log(colors.green('Hygiene passed with 0 errors 👍.'));
270-
console.log('Watching for changes...');
271-
}
272-
})
273-
.on('error', exitProcessOnError);
274-
}).catch(exitProcessOnError);
275372
});
373+
return files;
276374
}
277375
function getCachedFiles() {
278376
return new Promise(resolve => {
@@ -306,5 +404,5 @@ function getModifiedFiles() {
306404
}
307405
// this allows us to run hygiene as a git pre-commit hook.
308406
if (require.main === module) {
309-
run();
407+
run({ exitOnError: true, mode: 'staged' });
310408
}

0 commit comments

Comments
 (0)