UNPKG

ts-alias

Version:

Parse module aliases from tsconfig ; Apply / remove them from pathnames ; Generate config for webpack & module-alias.

422 lines (421 loc) 19.6 kB
"use strict"; /*---------------------------------- - DEPENDANCES ----------------------------------*/ var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); // Node var fs_1 = __importDefault(require("fs")); var path_1 = __importDefault(require("path")); // Npm var json5_1 = __importDefault(require("json5")); // Because tsconfig.json is closer to json5 rather than json /*---------------------------------- - CONFIG ----------------------------------*/ var LogPrefix = '[ts-alias]'; /*---------------------------------- - MODULE ----------------------------------*/ var TsAlias = /** @class */ (function () { function TsAlias(options) { var _a; if (options === void 0) { options = {}; } this.options = options; this.options.debug && console.log(LogPrefix, "Instanciate with the following options:", options); var tsFile; var tsDir; // Aliases list already provided // No need to search and read the tsconfig file if ('aliases' in options) { this.list = options.aliases.map(function (alias) { return (__assign(__assign({}, alias), { pathnames: alias.pathnames.map(function (pathname) { return path_1.default.join(process.cwd(), pathname); }) })); }); this.options.debug && console.log(LogPrefix, "Loaded aliases from object", options.aliases, '=>', this.list); return; } // Use the CWD by default if (options.rootDir === undefined) options.rootDir = process.cwd(); else { // Ensure the path is absolute if (!path_1.default.isAbsolute(options.rootDir)) options.rootDir = path_1.default.join(process.cwd(), options.rootDir); // And it exists if (!fs_1.default.existsSync(options.rootDir)) throw new Error("The provided rootDir \"" + options.rootDir + "\" doesn't exists."); } // options.rootDir = config file if (fs_1.default.lstatSync(options.rootDir).isFile()) { tsDir = path_1.default.dirname(options.rootDir); tsFile = path_1.default.basename(options.rootDir); // options.rootDir = Project dir } else { tsDir = options.rootDir; tsFile = 'tsconfig.json'; } // Module resolution directories // Default = rootDir if (options.modulesDir === undefined) options.modulesDir = [path_1.default.join(options.rootDir, 'node_modules')]; options.debug && console.log(LogPrefix, "Using the following dirs for module resolution:", options.modulesDir); // Parse the tsconfig.json file var tsBaseDir; (_a = this.readTsConfig(tsDir, tsFile), this.typescript = _a.paths, tsBaseDir = _a.baseUrl); // Build the list of aliases this.list = this.processTsAliases(this.typescript, tsBaseDir); } /*---------------------------------- - PARSING ----------------------------------*/ TsAlias.prototype.readTsConfig = function (dir, file) { // TODO: prise en compte de extends si baseurl ou paths manquant if (file === void 0) { file = 'tsconfig.json'; } var fullpath = dir + '/' + file; this.options.debug && console.log(LogPrefix, "Reading config " + fullpath); var raw = fs_1.default.readFileSync(fullpath, 'utf-8'); var tsconfig = json5_1.default.parse(raw); var _a = tsconfig.compilerOptions, paths = _a.paths, baseUrl = _a.baseUrl; // baseUrl is specified if (baseUrl !== undefined) { baseUrl = path_1.default.resolve(dir, baseUrl); // if not, try to het it from the extended config file } else if (tsconfig.extends) { // If no extended file, use config file directory as base url } else baseUrl = dir; if (paths === undefined) paths = {}; this.options.debug && console.log(LogPrefix, "Processed config: " + fullpath, paths, { baseUrl: baseUrl }); return { paths: paths, baseUrl: baseUrl }; }; TsAlias.prototype.processTsAliases = function (tsAliases, tsBaseDir) { var e_1, _a; var list = []; for (var alias in tsAliases) { var destinations = tsAliases[alias]; // Détermine if it must be exact alias var exact = !alias.endsWith('/*'); if (!exact) alias = alias.substring(0, alias.length - 2); // Process each destination path var pathnames = []; var _loop_1 = function (destination) { // Remove wildcard if (destination.endsWith('*')) destination = destination.substring(0, destination.length - 1); // Remove trailing slash if (destination.endsWith('/')) destination = destination.substring(0, destination.length - 1); // If the destination is a node module, prefix with options.modulesDir var isNpmModule = destination[0] !== '.' && destination[0] !== '/'; if (isNpmModule) pathnames.push.apply(pathnames, __spreadArray([], __read(this_1.options.modulesDir.map(function (dir) { return path_1.default.join(dir, destination); })), false)); // Otherwise, concat the path with the base dir (the one given in the tsconfig) else if (destination) pathnames.push(path_1.default.join(tsBaseDir, destination)); else pathnames.push(tsBaseDir); }; var this_1 = this; try { for (var destinations_1 = (e_1 = void 0, __values(destinations)), destinations_1_1 = destinations_1.next(); !destinations_1_1.done; destinations_1_1 = destinations_1.next()) { var destination = destinations_1_1.value; _loop_1(destination); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (destinations_1_1 && !destinations_1_1.done && (_a = destinations_1.return)) _a.call(destinations_1); } finally { if (e_1) throw e_1.error; } } list.push({ alias: alias, exact: exact, pathnames: pathnames }); } this.options.debug && console.log(LogPrefix, "Processed aliases:", list, { tsBaseDir: tsBaseDir }); return list; }; TsAlias.prototype.apply = function (realpath, strict) { var e_2, _a; for (var alias in this.list) { var _b = this.list[alias], exact = _b.exact, pathnames = _b.pathnames; try { for (var pathnames_1 = (e_2 = void 0, __values(pathnames)), pathnames_1_1 = pathnames_1.next(); !pathnames_1_1.done; pathnames_1_1 = pathnames_1.next()) { var pathname = pathnames_1_1.value; if (exact) { if (realpath === pathname) return alias; } else if (realpath.startsWith(pathname + '/')) { return alias + realpath.substring(pathname.length); } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (pathnames_1_1 && !pathnames_1_1.done && (_a = pathnames_1.return)) _a.call(pathnames_1); } finally { if (e_2) throw e_2.error; } } } // No matching alias return strict ? null : realpath; }; /** * Check if the provided path can be shorten with aliases * @param filename The path to check * @returns If filename can be shorten an alias */ TsAlias.prototype.isAliased = function (filename) { return this.apply(filename, true) !== null; }; TsAlias.prototype.realpath = function (request, strict) { var e_3, _a, e_4, _b; try { for (var _c = __values(this.list), _d = _c.next(); !_d.done; _d = _c.next()) { var _e = _d.value, alias = _e.alias, exact = _e.exact, pathnames = _e.pathnames; try { for (var pathnames_2 = (e_4 = void 0, __values(pathnames)), pathnames_2_1 = pathnames_2.next(); !pathnames_2_1.done; pathnames_2_1 = pathnames_2.next()) { var pathname = pathnames_2_1.value; if (exact) { if (request === alias) return pathname; } else if (request.startsWith(alias + '/')) { return pathname + request.substring(alias.length); } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (pathnames_2_1 && !pathnames_2_1.done && (_b = pathnames_2.return)) _b.call(pathnames_2); } finally { if (e_4) throw e_4.error; } } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_3) throw e_3.error; } } // No matching alias return strict ? null : request; }; /** * If the provided path contains an alias * @param filename The path to check * @returns If filename contains an alias */ TsAlias.prototype.containsAlias = function (filename) { return this.realpath(filename, true) !== null; }; /*---------------------------------- - TRANSFORM LIST ----------------------------------*/ // https://webpack.js.org/configuration/resolve/#resolvealias TsAlias.prototype.forWebpack = function (_a) { var e_5, _b, e_6, _c; var _this = this; var modulesPath = _a.modulesPath, shortenPaths = _a.shortenPaths, nodeExternals = _a.nodeExternals; this.options.debug && console.log(LogPrefix, "Generating webpack aliases ..."); var aliases = {}; var externalsList = {}; try { aliasesIt: for (var _d = __values(this.list), _e = _d.next(); !_e.done; _e = _d.next()) { var _f = _e.value, alias = _f.alias, exact = _f.exact, pathnames = _f.pathnames; var curAliases = []; if (modulesPath === undefined) curAliases = pathnames; else try { for (var pathnames_3 = (e_6 = void 0, __values(pathnames)), pathnames_3_1 = pathnames_3.next(); !pathnames_3_1.done; pathnames_3_1 = pathnames_3.next()) { var pathname = pathnames_3_1.value; // Reference to node_modules if (shortenPaths && pathname.startsWith(modulesPath)) { // Transforms paths to node_module into module reference // Ex: "../node_modules/declarative-scraper" => "declarative-scraper" pathname = pathname.substring(modulesPath.length + 1); // Externals if (nodeExternals === true && pathnames.length === 1) { externalsList[alias] = { pathname: pathname, exact: exact }; continue aliasesIt; } } curAliases.push(pathname); } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (pathnames_3_1 && !pathnames_3_1.done && (_c = pathnames_3.return)) _c.call(pathnames_3); } finally { if (e_6) throw e_6.error; } } // From webpack doc: « A trailing $ can also be added to the given object's keys to signify an exact match: » if (exact) alias += '$'; aliases[alias] = curAliases; } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (_e && !_e.done && (_b = _d.return)) _b.call(_d); } finally { if (e_5) throw e_5.error; } } this.options.debug && console.log(LogPrefix, "Webpack aliases =", aliases, 'Webpakc externals =', externalsList); if (!nodeExternals) return { aliases: aliases }; // https://webpack.js.org/configuration/externals/#function var externals = function (_a, callback) { var request = _a.request; for (var alias in externalsList) { var _b = externalsList[alias], pathname = _b.pathname, exact = _b.exact; if (exact) { if (request === alias) { _this.options.debug && console.log(LogPrefix, request, '=>', pathname); return callback(null, pathname); } } else if (request.startsWith(alias)) { var destination = pathname + request.substring(alias.length); _this.options.debug && console.log(LogPrefix, request, '=>', destination); return callback(undefined, destination); } } callback(); }; this.options.debug && console.log(LogPrefix, "Webpack aliases:", aliases); return { aliases: aliases, externals: externals }; }; // https://github.com/ilearnio/module-alias#advanced-usage TsAlias.prototype.forModuleAlias = function (enableCache) { var e_7, _a; var _this = this; if (enableCache === void 0) { enableCache = true; } var moduleAlias = {}; var cache = {}; var _loop_2 = function (alias, exact, pathnames) { // Create a resolver moduleAlias[alias] = function (from, request, requestAlias) { var e_8, _a; // Exact alias if (exact && request !== alias) return requestAlias; _this.options.debug && console.log(LogPrefix, "Resolving " + request + " from " + from); // From cache var cacheId = from + '::' + request; if (enableCache && cache[cacheId] !== undefined) { _this.options.debug && console.log(LogPrefix, 'Found from cache:', cache[cacheId]); return cache[cacheId]; } // Chemin du module sans l'alias var modulePath = request.substring(requestAlias.length); try { // Recherche de la première destinaiton existante for (var pathnames_4 = (e_8 = void 0, __values(pathnames)), pathnames_4_1 = pathnames_4.next(); !pathnames_4_1.done; pathnames_4_1 = pathnames_4.next()) { var pathname = pathnames_4_1.value; try { var searchPath = pathname + modulePath; _this.options.debug && console.log(LogPrefix, '- Trying:', searchPath); // Si le chemin existe, il sera retourné if (require.resolve(searchPath)) { // Retourne un chemin relatif au fichier qui a importé le module var relative = path_1.default.relative(path_1.default.dirname(from), pathname); _this.options.debug && console.log(LogPrefix, 'Found:', relative); cache[cacheId] = relative; return relative; } } catch (e) { _this.options.debug && console.log(LogPrefix, 'Unable to resolve', e); } } } catch (e_8_1) { e_8 = { error: e_8_1 }; } finally { try { if (pathnames_4_1 && !pathnames_4_1.done && (_a = pathnames_4.return)) _a.call(pathnames_4); } finally { if (e_8) throw e_8.error; } } _this.options.debug && console.warn("Unable to resolve alias for " + request + " from " + from); return requestAlias; }; }; try { // For each registered alias for (var _b = __values(this.list), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = _c.value, alias = _d.alias, exact = _d.exact, pathnames = _d.pathnames; _loop_2(alias, exact, pathnames); } } catch (e_7_1) { e_7 = { error: e_7_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_7) throw e_7.error; } } this.options.debug && console.log(LogPrefix, "Module AliasDefinition:", moduleAlias); return moduleAlias; }; return TsAlias; }()); exports.default = TsAlias;