Skip to content

Commit f3ab41a

Browse files
authored
Merge pull request #222 from typed-ember/de-simplify-watcher
De-simplify watcher
2 parents 8972428 + bc21503 commit f3ab41a

File tree

4 files changed

+55
-25
lines changed

4 files changed

+55
-25
lines changed

blueprints/ember-cli-typescript/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ module.exports = {
4040
}
4141

4242
return {
43-
includes: JSON.stringify(includes, null, 2).replace(/\n/g, '\n '),
43+
includes: JSON.stringify(includes.map(include => `${include}/**/*`), null, 2).replace(/\n/g, '\n '),
4444
pathsFor: dasherizedName => {
4545
let appName = isAddon ? 'dummy' : dasherizedName;
4646
let paths = {

lib/utilities/compile.js

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
const chokidar = require('chokidar');
55
const fs = require('fs-extra');
66
const escapeRegex = require('escape-string-regexp');
7-
const debug = require('debug')('ember-cli-typescript:tsc:trace');
7+
const path = require('path');
8+
const glob = require('glob');
9+
10+
const trace = require('debug')('ember-cli-typescript:tsc:trace');
11+
const debug = require('debug')('ember-cli-typescript:watcher');
812

913
module.exports = function compile(project, tsOptions, callbacks) {
1014
// Ensure the output directory is created even if no files are generated
@@ -14,8 +18,8 @@ module.exports = function compile(project, tsOptions, callbacks) {
1418
rootDir: project.root,
1519
allowJs: false,
1620
noEmit: false,
17-
diagnostics: debug.enabled,
18-
extendedDiagnostics: debug.enabled
21+
diagnostics: trace.enabled,
22+
extendedDiagnostics: trace.enabled
1923
}, tsOptions);
2024

2125
let ts = project.require('typescript');
@@ -30,7 +34,7 @@ function createWatchCompilerHost(ts, options, project, callbacks) {
3034
let host = ts.createWatchCompilerHost(
3135
configPath,
3236
options,
33-
buildWatchHooks(project, ts.sys, callbacks),
37+
buildWatchHooks(project, ts, callbacks),
3438
createProgram,
3539
diagnosticCallback(callbacks.reportDiagnostic),
3640
diagnosticCallback(callbacks.reportWatchStatus)
@@ -46,8 +50,8 @@ function createWatchCompilerHost(ts, options, project, callbacks) {
4650
}
4751
};
4852

49-
if (debug.enabled) {
50-
host.trace = str => debug(str.trim());
53+
if (trace.enabled) {
54+
host.trace = str => trace(str.trim());
5155
}
5256

5357
return host;
@@ -64,28 +68,53 @@ function diagnosticCallback(callback) {
6468
}
6569
}
6670

67-
function buildWatchHooks(project, sys, callbacks) {
68-
let root = escapeRegex(project.root);
69-
let sep = `[/\\\\]`;
70-
let patterns = ['\\..*?', 'dist', 'node_modules', 'tmp'];
71-
let ignored = new RegExp(`^${root}${sep}(${patterns.join('|')})${sep}`);
71+
function buildWatchHooks(project, ts, callbacks) {
72+
let ignorePatterns = ['\\..*?', 'dist', 'tmp', 'node_modules'];
7273

73-
return Object.assign({}, sys, {
74+
return Object.assign({}, ts.sys, {
7475
watchFile: null,
75-
watchDirectory(dir, callback) {
76-
if (!fs.existsSync(dir)) return;
77-
76+
watchDirectory(rawDir, callback) {
77+
if (!fs.existsSync(rawDir)) {
78+
debug(`skipping watch for nonexistent directory %s`, rawDir);
79+
return;
80+
}
81+
82+
let dir = getCanonicalCapitalization(path.resolve(rawDir));
83+
let ignored = buildIgnoreRegex(dir, ignorePatterns);
7884
let watcher = chokidar.watch(dir, { ignored, ignoreInitial: true });
85+
debug(`watching directory %s %o`, dir, { ignored });
7986

80-
watcher.on('all', (type, path) => {
81-
callback(path);
87+
watcher.on('all', (type, rawPath) => {
88+
let resolvedPath = path.resolve(rawPath);
8289

83-
if (path.endsWith('.ts') && callbacks.watchedFileChanged) {
90+
debug(`%s: %s (for directory watch on %s)`, type, resolvedPath, dir);
91+
callback(resolvedPath);
92+
93+
if (resolvedPath.endsWith('.ts') && callbacks.watchedFileChanged) {
8494
callbacks.watchedFileChanged();
8595
}
8696
});
8797

88-
return watcher;
98+
return {
99+
close() {
100+
debug('closing watcher for %s', dir);
101+
watcher.close();
102+
}
103+
};
89104
}
90105
});
91106
}
107+
108+
function buildIgnoreRegex(rootDir, patterns) {
109+
let base = escapeRegex(rootDir);
110+
let sep = `[/\\\\]`;
111+
return new RegExp(`^${base}${sep}(${patterns.join('|')})${sep}`, 'i');
112+
}
113+
114+
// On case-insensitive file systems, tsc will normalize paths to be all lowercase,
115+
// but chokidar expects the paths it's given to watch to exactly match what it's
116+
// delivered in fs events.
117+
function getCanonicalCapitalization(rawPath) {
118+
let normalized = rawPath.replace(/\\/g, '/').replace(/^[a-z]:/i, '');
119+
return glob.sync(normalized, { nocase: true })[0];
120+
}

node-tests/blueprints/ember-cli-typescript-test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ describe('Acceptance: ember-cli-typescript generator', function() {
7171
expect(tsconfigJson.compilerOptions.inlineSourceMap).to.equal(true);
7272
expect(tsconfigJson.compilerOptions.inlineSources).to.equal(true);
7373

74-
expect(tsconfigJson.include).to.deep.equal(['app', 'tests', 'types']);
74+
expect(tsconfigJson.include).to.deep.equal(['app/**/*', 'tests/**/*', 'types/**/*']);
7575

7676
const projectTypes = file('types/my-app/index.d.ts');
7777
expect(projectTypes).to.exist;
@@ -116,7 +116,7 @@ describe('Acceptance: ember-cli-typescript generator', function() {
116116
'*': ['types/*'],
117117
});
118118

119-
expect(tsconfigJson.include).to.deep.equal(['app', 'addon', 'tests', 'types']);
119+
expect(tsconfigJson.include).to.deep.equal(['app/**/*', 'addon/**/*', 'tests/**/*', 'types/**/*']);
120120

121121
const projectTypes = file('types/dummy/index.d.ts');
122122
expect(projectTypes).to.exist;
@@ -159,7 +159,7 @@ describe('Acceptance: ember-cli-typescript generator', function() {
159159
'*': ['types/*'],
160160
});
161161

162-
expect(json.include).to.deep.equal(['app', 'tests', 'types', 'lib/my-addon-1', 'lib/my-addon-2']);
162+
expect(json.include).to.deep.equal(['app/**/*', 'tests/**/*', 'types/**/*', 'lib/my-addon-1/**/*', 'lib/my-addon-2/**/*']);
163163

164164
const projectTypes = file('types/my-app/index.d.ts');
165165
expect(projectTypes).to.exist;
@@ -194,7 +194,7 @@ describe('Acceptance: ember-cli-typescript generator', function() {
194194
'*': ['types/*'],
195195
});
196196

197-
expect(json.include).to.deep.equal(['app', 'tests', 'types', 'mirage']);
197+
expect(json.include).to.deep.equal(['app/**/*', 'tests/**/*', 'types/**/*', 'mirage/**/*']);
198198
});
199199
});
200200

@@ -224,7 +224,7 @@ describe('Acceptance: ember-cli-typescript generator', function() {
224224
'*': ['types/*'],
225225
});
226226

227-
expect(json.include).to.deep.equal(['app', 'addon', 'tests', 'types']);
227+
expect(json.include).to.deep.equal(['app/**/*', 'addon/**/*', 'tests/**/*', 'types/**/*']);
228228
});
229229
});
230230

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"execa": "^0.9.0",
5454
"exists-sync": "^0.0.4",
5555
"fs-extra": "^5.0.0",
56+
"glob": "^7.1.2",
5657
"inflection": "^1.12.0",
5758
"resolve": "^1.5.0",
5859
"rimraf": "^2.6.2",

0 commit comments

Comments
 (0)