Skip to content

Commit

Permalink
Merge pull request #100 from jjangga0214/feat/tsLookup/path-mapping
Browse files Browse the repository at this point in the history
feat(tsLookup): path mapping
  • Loading branch information
mrjoelkemp authored Apr 30, 2022
2 parents 56031e9 + bc9913f commit 05b02b9
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 76 deletions.
60 changes: 55 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

const path = require('path');
const debug = require('debug')('cabinet');

const {createMatchPath} = require('tsconfig-paths');
const fs = require('fs');
/*
* most js resolver are lazy-loaded (only required when needed)
* e.g. dont load requirejs when we only have commonjs modules to resolve
Expand Down Expand Up @@ -44,7 +45,8 @@ const defaultLookups = {
* @param {String} [options.nodeModulesConfig.entry] The new value for "main" in package json
* @param {String} [options.webpackConfig] Path to the webpack config
* @param {Object} [options.ast] A preparsed AST for the file identified by filename.
* @param {Object} [options.tsConfig] Path to a typescript config file
* @param {String|Object} [options.tsConfig] Path to a typescript configuration or an object representing a pre-parsed typescript config.
* @param {String} [options.tsConfigPath] A (virtual) Path to typescript config file when options.tsConfig is given as an object. Needed to calculate [Path Mapping](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping). If not given when options.tsConfig is an object, Path Mapping is not considered.
* @param {Boolean} [options.noTypeDefinitions] Whether to return '.d.ts' files or '.js' files for a dependency
*/
module.exports = function cabinet(options) {
Expand Down Expand Up @@ -147,7 +149,6 @@ function getCompilerOptionsFromTsConfig(tsConfig) {

if (!tsConfig) {
debug('no tsconfig given, defaulting');

} else if (typeof tsConfig === 'string') {
debug('string tsconfig given, parsing');

Expand Down Expand Up @@ -183,7 +184,7 @@ function getCompilerOptionsFromTsConfig(tsConfig) {
* @return {String}
*/
function jsLookup(options) {
const {dependency, filename, directory, config, webpackConfig, configPath, ast} = options;
const {dependency, filename, directory, config, webpackConfig, configPath, nodeModulesConfig, ast, tsConfig} = options;
const type = module.exports._getJSType({
config: config,
webpackConfig: webpackConfig,
Expand Down Expand Up @@ -222,9 +223,13 @@ function jsLookup(options) {
}
}

function tsLookup({dependency, filename, tsConfig, noTypeDefinitions}) {
function tsLookup({dependency, filename, tsConfig, tsConfigPath, noTypeDefinitions}) {
debug('performing a typescript lookup');

if (typeof tsConfig === 'string') {
tsConfigPath = tsConfigPath || path.dirname(tsConfig);
}

let compilerOptions = getCompilerOptionsFromTsConfig(tsConfig);

// Preserve for backcompat. Consider removing this as a breaking change.
Expand All @@ -233,6 +238,7 @@ function tsLookup({dependency, filename, tsConfig, noTypeDefinitions}) {
}

const host = ts.createCompilerHost({});

debug('with options: ', compilerOptions);

const namedModule = ts.resolveModuleName(dependency, filename, compilerOptions, host);
Expand All @@ -252,13 +258,57 @@ function tsLookup({dependency, filename, tsConfig, noTypeDefinitions}) {
result = lookUpLocations.find(ts.sys.fileExists) || '';
}

if (!result && tsConfigPath && compilerOptions.baseUrl && compilerOptions.paths) {
const absoluteBaseUrl = path.join(path.dirname(tsConfigPath), compilerOptions.baseUrl);
// REF: https://github.com/dividab/tsconfig-paths#creatematchpath
const tsMatchPath = createMatchPath(absoluteBaseUrl, compilerOptions.paths);
const extensions = ['.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json', '.node'];
// REF: https://github.com/dividab/tsconfig-paths#creatematchpath
const resolvedTsAliasPath = tsMatchPath(dependency, undefined, undefined, extensions); // 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 ext of extensions) {
const filename = path.join(resolvedTsAliasPath, 'index' + ext);
if (fs.existsSync(filename)) {
result = filename;
break;
}
}
} else {
// if the path is complete filename
result = resolvedTsAliasPath;
}
} else {
// For cases a file extension is omitted when being imported
for (const ext of extensions) {
const filenameWithExt = resolvedTsAliasPath + ext;
if (fs.existsSync(filenameWithExt)) {
result = filenameWithExt;
break;
}
}
}
}
}

debug('result: ' + result);
return result ? path.resolve(result) : '';
}

function commonJSLookup(options) {
const {filename, directory, nodeModulesConfig, tsConfig} = options;
let {dependency} = options;

if (!resolve) {
resolve = require('resolve');
}
Expand Down
121 changes: 73 additions & 48 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"resolve-dependency-path": "^2.0.0",
"sass-lookup": "^3.0.0",
"stylus-lookup": "^3.0.1",
"tsconfig-paths": "^3.10.1",
"typescript": "^3.9.7"
}
}
Loading

0 comments on commit 05b02b9

Please sign in to comment.