Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tsLookup): path mapping #100

Merged
merged 4 commits into from
Apr 30, 2022
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
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