Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion blueprints/ember-cli-typescript/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module.exports = {
}

return {
includes: JSON.stringify(includes, null, 2).replace(/\n/g, '\n '),
includes: JSON.stringify(includes.map(include => `${include}/**/*`), null, 2).replace(/\n/g, '\n '),
pathsFor: dasherizedName => {
let appName = isAddon ? 'dummy' : dasherizedName;
let paths = {
Expand Down
67 changes: 48 additions & 19 deletions lib/utilities/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
const chokidar = require('chokidar');
const fs = require('fs-extra');
const escapeRegex = require('escape-string-regexp');
const debug = require('debug')('ember-cli-typescript:tsc:trace');
const path = require('path');
const glob = require('glob');

const trace = require('debug')('ember-cli-typescript:tsc:trace');
const debug = require('debug')('ember-cli-typescript:watcher');

module.exports = function compile(project, tsOptions, callbacks) {
// Ensure the output directory is created even if no files are generated
Expand All @@ -14,8 +18,8 @@ module.exports = function compile(project, tsOptions, callbacks) {
rootDir: project.root,
allowJs: false,
noEmit: false,
diagnostics: debug.enabled,
extendedDiagnostics: debug.enabled
diagnostics: trace.enabled,
extendedDiagnostics: trace.enabled
}, tsOptions);

let ts = project.require('typescript');
Expand All @@ -30,7 +34,7 @@ function createWatchCompilerHost(ts, options, project, callbacks) {
let host = ts.createWatchCompilerHost(
configPath,
options,
buildWatchHooks(project, ts.sys, callbacks),
buildWatchHooks(project, ts, callbacks),
createProgram,
diagnosticCallback(callbacks.reportDiagnostic),
diagnosticCallback(callbacks.reportWatchStatus)
Expand All @@ -46,8 +50,8 @@ function createWatchCompilerHost(ts, options, project, callbacks) {
}
};

if (debug.enabled) {
host.trace = str => debug(str.trim());
if (trace.enabled) {
host.trace = str => trace(str.trim());
}

return host;
Expand All @@ -64,28 +68,53 @@ function diagnosticCallback(callback) {
}
}

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

return Object.assign({}, sys, {
return Object.assign({}, ts.sys, {
watchFile: null,
watchDirectory(dir, callback) {
if (!fs.existsSync(dir)) return;

watchDirectory(rawDir, callback) {
if (!fs.existsSync(rawDir)) {
debug(`skipping watch for nonexistent directory %s`, rawDir);
return;
}

let dir = getCanonicalCapitalization(path.resolve(rawDir));
let ignored = buildIgnoreRegex(dir, ignorePatterns);
let watcher = chokidar.watch(dir, { ignored, ignoreInitial: true });
debug(`watching directory %s %o`, dir, { ignored });

watcher.on('all', (type, path) => {
callback(path);
watcher.on('all', (type, rawPath) => {
let resolvedPath = path.resolve(rawPath);

if (path.endsWith('.ts') && callbacks.watchedFileChanged) {
debug(`%s: %s (for directory watch on %s)`, type, resolvedPath, dir);
callback(resolvedPath);

if (resolvedPath.endsWith('.ts') && callbacks.watchedFileChanged) {
callbacks.watchedFileChanged();
}
});

return watcher;
return {
close() {
debug('closing watcher for %s', dir);
watcher.close();
}
};
}
});
}

function buildIgnoreRegex(rootDir, patterns) {
let base = escapeRegex(rootDir);
let sep = `[/\\\\]`;
return new RegExp(`^${base}${sep}(${patterns.join('|')})${sep}`, 'i');
}

// On case-insensitive file systems, tsc will normalize paths to be all lowercase,
// but chokidar expects the paths it's given to watch to exactly match what it's
// delivered in fs events.
function getCanonicalCapitalization(rawPath) {
let normalized = rawPath.replace(/\\/g, '/').replace(/^[a-z]:/i, '');
return glob.sync(normalized, { nocase: true })[0];
}
10 changes: 5 additions & 5 deletions node-tests/blueprints/ember-cli-typescript-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('Acceptance: ember-cli-typescript generator', function() {
expect(tsconfigJson.compilerOptions.inlineSourceMap).to.equal(true);
expect(tsconfigJson.compilerOptions.inlineSources).to.equal(true);

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

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

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

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

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

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

expect(json.include).to.deep.equal(['app', 'tests', 'types', 'mirage']);
expect(json.include).to.deep.equal(['app/**/*', 'tests/**/*', 'types/**/*', 'mirage/**/*']);
});
});

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

expect(json.include).to.deep.equal(['app', 'addon', 'tests', 'types']);
expect(json.include).to.deep.equal(['app/**/*', 'addon/**/*', 'tests/**/*', 'types/**/*']);
});
});

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"execa": "^0.9.0",
"exists-sync": "^0.0.4",
"fs-extra": "^5.0.0",
"glob": "^7.1.2",
"inflection": "^1.12.0",
"resolve": "^1.5.0",
"rimraf": "^2.6.2",
Expand Down