diff --git a/index.js b/index.js index 54b16b2..77db6f9 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ const fs = require('fs'); const cabinet = require('filing-cabinet'); const debug = require('debug')('tree'); const Config = require('./lib/Config'); +const { createMatchPath } = require('tsconfig-paths') /** * Recursively find all dependencies (avoiding circular) traversing the entire dependency tree @@ -25,7 +26,7 @@ const Config = require('./lib/Config'); * @param {Boolean} [options.noTypeDefinitions] For TypeScript imports, whether to resolve to `*.js` instead of `*.d.ts`. * @return {Object} */ -module.exports = function(options) { +module.exports = function (options) { const config = new Config(options); if (!fs.existsSync(config.filename)) { @@ -67,7 +68,7 @@ module.exports = function(options) { * * Params are those of module.exports */ -module.exports.toList = function(options) { +module.exports.toList = function (options) { options.isListForm = true; return module.exports(options); @@ -81,7 +82,7 @@ module.exports.toList = function(options) { * @param {Config} config * @return {Array} */ -module.exports._getDependencies = function(config) { +module.exports._getDependencies = function (config) { let dependencies; const precinctOptions = config.detectiveConfig; precinctOptions.includeCore = false; @@ -97,12 +98,22 @@ module.exports._getDependencies = function(config) { return []; } + + const tsMatchPath = (() => { + if (config.tsConfig) { + const absoluteBaseUrl = path.join(path.dirname(config.tsConfigPath), config.tsConfig.compilerOptions.baseUrl) + // REF: https://github.com/dividab/tsconfig-paths#creatematchpath + return createMatchPath(absoluteBaseUrl, config.tsConfig.compilerOptions.paths) + } + return (alias) => undefined; + })() + const resolvedDependencies = []; for (let i = 0, l = dependencies.length; i < l; i++) { const dep = dependencies[i]; - const result = cabinet({ + let result = cabinet({ partial: dep, filename: config.filename, directory: config.directory, @@ -114,6 +125,46 @@ module.exports._getDependencies = function(config) { noTypeDefinitions: config.noTypeDefinitions }); + // Check if the dep is ts path mapping alias, and if so, update the result. + if (!result) { + result = (() => { + // REF: https://github.com/dividab/tsconfig-paths#creatematchpath + const resolvedTsAliasPath = tsMatchPath(dep) // Get absolute path by ts path mapping. `undefined` if non-existent + if (resolvedTsAliasPath) { + const stat = (() => { + try { + // fs.statSync throws an error if path is non-existent + return fs.statSync(resolvedTsAliasPath) + } catch (error) { + return undefined + } + })() + if (stat) { + if (stat.isDirectory()) { + // When directory is imported, index file is resolved + for (const indexFile of ['index.ts', 'index.tsx', 'index.js', 'index.jsx']) { + const filename = path.join(resolvedTsAliasPath, indexFile) + if (fs.existsSync(filename)) { + return filename + } + } + } + // if the path is complete filename + return resolvedTsAliasPath + } else { + // For cases a file extension is omitted when being imported + for (const ext of ['.ts', '.tsx', '.js', '.jsx']) { + const filename = resolvedTsAliasPath + ext + if (fs.existsSync(filename)) { + return filename + } + } + } + } + return undefined + })() + } + if (!result) { debug('skipping an empty filepath resolution for partial: ' + dep); config.nonExistent.push(dep); @@ -123,6 +174,7 @@ module.exports._getDependencies = function(config) { const exists = fs.existsSync(result); if (!exists) { + config.nonExistent.push(dep); debug('skipping non-empty but non-existent resolution: ' + result + ' for partial: ' + dep); continue; @@ -158,7 +210,7 @@ function traverse(config) { if (config.filter) { debug('using filter function to filter out dependencies'); debug('unfiltered number of dependencies: ' + dependencies.length); - dependencies = dependencies.filter(function(filePath) { + dependencies = dependencies.filter(function (filePath) { return config.filter(filePath, config.filename); }); debug('filtered number of dependencies: ' + dependencies.length); diff --git a/lib/Config.js b/lib/Config.js index 4be5d58..5575ca9 100644 --- a/lib/Config.js +++ b/lib/Config.js @@ -23,11 +23,14 @@ class Config { if (!this.directory) { throw new Error('directory not given'); } if (this.filter && typeof this.filter !== 'function') { throw new Error('filter must be a function'); } + // tsConfigPath is needed to calculate absolute baseUrl, which the function `createMatchPath` of the package `tsconfig-paths` requires + this.tsConfigPath = options.tsConfigPath if ('string' === typeof this.tsConfig) { debug('preparsing the ts config into an object for performance'); const ts = require('typescript'); const tsParsedConfig = ts.readJsonConfigFile(this.tsConfig, ts.sys.readFile); const obj = ts.parseJsonSourceFileConfigFileContent(tsParsedConfig, ts.sys, path.dirname(this.tsConfig)); + this.tsConfigPath = this.tsConfig this.tsConfig = obj.raw; } @@ -39,7 +42,7 @@ class Config { debug('visited: ', this.visited); } - clone () { + clone() { return new Config(this); } } diff --git a/package-lock.json b/package-lock.json index 7496135..5ac2f1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1844,6 +1844,14 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, "jsonlint": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", @@ -2971,6 +2979,23 @@ "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz", "integrity": "sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=" }, + "tsconfig-paths": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", + "integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", + "requires": { + "json5": "^2.2.0", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + } + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", diff --git a/package.json b/package.json index db9e38a..a13507e 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "debug": "^4.3.1", "filing-cabinet": "^3.0.0", "precinct": "^8.0.0", + "tsconfig-paths": "^3.10.1", "typescript": "^3.9.7" }, "devDependencies": {