UNPKG

typescript-cp

Version:
534 lines (533 loc) 23.1 kB
"use strict"; 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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.definitely_posix = exports.sleep = exports.copy_file_or_directory = exports.remove_file_or_directory = exports.get_file_stats = exports.validate_path = exports.color_log = exports.get_ignore_list = exports.get_ts_projects_paths = exports.get_ts_project_paths = exports.get_ts_config = exports.get_config = exports.console_colors = void 0; var path = __importStar(require("path")); var fs = __importStar(require("fs")); var commander_1 = require("commander"); var typescript_1 = __importDefault(require("typescript")); var fs_extra_1 = __importDefault(require("fs-extra")); var rimraf_1 = require("rimraf"); var cosmiconfig_1 = require("cosmiconfig"); // https://stackoverflow.com/a/41407246/3111787 // https://en.wikipedia.org/wiki/ANSI_escape_code#Colors var console_colors; (function (console_colors) { console_colors["Reset"] = "\u001B[0m"; console_colors["Bright"] = "\u001B[1m"; console_colors["Dim"] = "\u001B[2m"; console_colors["Underscore"] = "\u001B[4m"; console_colors["Blink"] = "\u001B[5m"; console_colors["Reverse"] = "\u001B[7m"; console_colors["Hidden"] = "\u001B[8m"; console_colors["FgBlack"] = "\u001B[30m"; console_colors["FgRed"] = "\u001B[31m"; console_colors["FgGreen"] = "\u001B[32m"; console_colors["FgYellow"] = "\u001B[33m"; console_colors["FgBlue"] = "\u001B[34m"; console_colors["FgMagenta"] = "\u001B[35m"; console_colors["FgCyan"] = "\u001B[36m"; console_colors["FgWhite"] = "\u001B[37m"; console_colors["BgBlack"] = "\u001B[40m"; console_colors["BgRed"] = "\u001B[41m"; console_colors["BgGreen"] = "\u001B[42m"; console_colors["BgYellow"] = "\u001B[43m"; console_colors["BgBlue"] = "\u001B[44m"; console_colors["BgMagenta"] = "\u001B[45m"; console_colors["BgCyan"] = "\u001B[46m"; console_colors["BgWhite"] = "\u001B[47m"; console_colors["FgBrightBlack"] = "\u001B[90m"; console_colors["FgBrightRed"] = "\u001B[91m"; console_colors["FgBrightGreen"] = "\u001B[92m"; console_colors["FgBrightYellow"] = "\u001B[93m"; console_colors["FgBrightBlue"] = "\u001B[94m"; console_colors["FgBrightMagenta"] = "\u001B[95m"; console_colors["FgBrightCyan"] = "\u001B[96m"; console_colors["FgBrightWhite"] = "\u001B[97m"; console_colors["BgBrightBlack"] = "\u001B[100m"; console_colors["BgBrightRed"] = "\u001B[101m"; console_colors["BgBrightGreen"] = "\u001B[102m"; console_colors["BgBrightYellow"] = "\u001B[103m"; console_colors["BgBrightBlue"] = "\u001B[104m"; console_colors["BgBrightMagenta"] = "\u001B[105m"; console_colors["BgBrightCyan"] = "\u001B[106m"; console_colors["BgBrightWhite"] = "\u001B[107m"; })(console_colors = exports.console_colors || (exports.console_colors = {})); var version = require('../package.json').version; var defaultProject = (function () { // process.argv = ['node_path', 'script_path', ...args] var lastArg = process.argv.slice(2).slice(-1)[0]; if (lastArg && !lastArg.startsWith('-')) { return lastArg; } return 'tsconfig.json'; })(); var program = new commander_1.Command(); program .option('-w, --watch', 'Watch input files.') .option('-b, --build', 'Build one or more projects and their dependencies, if out of date') .option('-p , --project <path>', 'FILE OR DIRECTORY Compile the project given the path to its configuration file, or to a folder with a \'tsconfig.json\'', defaultProject) .version(version, '-v, --version'); program.parse(process.argv); // @ts-ignore var options = program.opts(); /** * Returns the complete, resolved configuration object */ function get_config() { return __awaiter(this, void 0, void 0, function () { var cwd, ts_config, explorer, result, project_config, default_config, config; return __generator(this, function (_a) { switch (_a.label) { case 0: cwd = definitely_posix(process.cwd()); ts_config = get_ts_config(cwd, options.project); explorer = (0, cosmiconfig_1.cosmiconfig)('tscp'); return [4 /*yield*/, explorer.search(cwd)]; case 1: result = _a.sent(); project_config = (result || {}).config; default_config = { cwd: cwd, cli_options: options, ts_config: ts_config, use_ts_exclude: true, compiled_files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], ignored_files: ['node_modules'], rules: [], }; config = __assign(__assign({}, default_config), project_config); config.ignored_files = __spreadArray(__spreadArray([], __read(config.compiled_files), false), __read(config.ignored_files), false); return [2 /*return*/, config]; } }); }); } exports.get_config = get_config; /** * Finds the `project` config file in `currentDir` and parses it with Typescript's own parser * @param currentDir * @param project */ function get_ts_config(currentDir, project) { var configFile = typescript_1.default.findConfigFile(currentDir, typescript_1.default.sys.fileExists, project); if (!configFile) throw Error('tsconfig.json not found'); var config = typescript_1.default.readConfigFile(configFile, typescript_1.default.sys.readFile).config; return typescript_1.default.parseJsonConfigFileContent(config, typescript_1.default.sys, currentDir); } exports.get_ts_config = get_ts_config; /** * Creates an internal project descriptor for one Typescript project * @param cwd * @param project_path * @param ts_config */ function build_project_path(cwd, project_path, ts_config) { var currentDirName = path.basename(path.resolve()); var referenceName = path.relative(process.cwd(), cwd); var projectName = path.join(currentDirName, referenceName); var exclude = ts_config.raw.exclude; var _a = ts_config.options, rootDir = _a.rootDir, outDir = _a.outDir, noEmit = _a.noEmit; if (!rootDir) { throw new Error("No 'rootDir' configured in reference '".concat(referenceName, "'")); } if (!outDir) { throw new Error("No 'outDir' configured in reference '".concat(referenceName, "'")); } return { project_name: projectName, base_path: cwd, ts_config_path: project_path, root_dir: rootDir, out_dir: outDir, exclude: exclude || [], no_emit: noEmit !== null && noEmit !== void 0 ? noEmit : false, }; } /** * Returns the internal project descriptor of a TS project that doesn't have project references * @param options */ function get_ts_project_paths(options) { var cwd = options.cwd, cli_options = options.cli_options, ts_config = options.ts_config; var project = build_project_path(cwd, cli_options.project, ts_config); if (project.no_emit) { throw new Error('Project must have emitting enabled'); } return project; } exports.get_ts_project_paths = get_ts_project_paths; /** * Returns the internal project descriptor of a TS project that has project references * @param options */ function get_ts_projects_paths(options) { var ts_config = options.ts_config; if (!ts_config.projectReferences) { throw new Error('No project references configured'); } var projects = ts_config.projectReferences.map(function (reference) { if (!reference.path) { throw new Error('Could not find project reference path'); } if (!reference.originalPath) { throw new Error('Could not find project reference originalPath'); } var cwd = path.dirname(reference.path); var referenceConfig = get_ts_config(cwd, reference.originalPath); return build_project_path(cwd, reference.originalPath, referenceConfig); }); var projects_with_emit = projects.filter(function (project) { return !project.no_emit; }); if (projects_with_emit.length === 0) { throw new Error('At least one project must have emitting enabled'); } return projects_with_emit; } exports.get_ts_projects_paths = get_ts_projects_paths; /** * Combines the exclude pattern in the tsconfig file and the TSCP `config.ignored_files` * @param config * @param projects */ function get_ignore_list(config, projects) { var ignore_list = []; if (config.use_ts_exclude) { var safe_projects = !Array.isArray(projects) ? [projects] : projects; var ts_exclude_list = safe_projects.map(function (project) { return project.exclude.map(function (rule) { // Handle if the exclude pattern contains the name of the root directory var rootDirName = project.root_dir.replace(project.base_path + '/', '') + '/'; if (rule.startsWith(rootDirName)) { return rule.replace(rootDirName, ''); } return rule; }); }).flat(); ignore_list.push.apply(ignore_list, __spreadArray([], __read(ts_exclude_list), false)); } ignore_list.push.apply(ignore_list, __spreadArray([], __read(config.ignored_files), false)); return ignore_list; } exports.get_ignore_list = get_ignore_list; /** * Displays a colored log in the stdout * @param msg * @param color */ function color_log(msg, color) { return "".concat(color).concat(msg).concat(console_colors.Reset); } exports.color_log = color_log; /** * Makes sure that the given folder (or the parent folder of a file) exists - creates if not * @param p {string} */ function validate_path(p) { return __awaiter(this, void 0, void 0, function () { var dirname; return __generator(this, function (_a) { switch (_a.label) { case 0: dirname = path.dirname(p); return [4 /*yield*/, get_file_stats(dirname)]; case 1: if (!!(_a.sent())) return [3 /*break*/, 3]; return [4 /*yield*/, fs.promises.mkdir(dirname, { recursive: true })]; case 2: _a.sent(); _a.label = 3; case 3: return [2 /*return*/]; } }); }); } exports.validate_path = validate_path; /** * Error-safe `fs.lstat` - returns stats if the file exists, otherwise null * @param file_path */ function get_file_stats(file_path) { return __awaiter(this, void 0, void 0, function () { var e_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, fs_extra_1.default.lstat(file_path)]; case 1: return [2 /*return*/, _a.sent()]; case 2: e_1 = _a.sent(); return [2 /*return*/, Promise.resolve()]; case 3: return [2 /*return*/]; } }); }); } exports.get_file_stats = get_file_stats; /** * Deletes the `file_path` file. Doesn't throw error if the file doesn't exist. * @param file_path */ function remove_file_or_directory(file_path) { return __awaiter(this, void 0, void 0, function () { var stats; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, get_file_stats(file_path)]; case 1: stats = _a.sent(); if (!stats) { return [2 /*return*/, Promise.resolve(false)]; } // console.log('DELETE', file_path); return [2 /*return*/, (0, rimraf_1.rimraf)(file_path)]; } }); }); } exports.remove_file_or_directory = remove_file_or_directory; var files_without_loaders = []; /** * Reads the content of the `source_path` file, applies the loaders on its content, and writes the processed content to `destination_path` * @param source_path * @param destination_path * @param config */ function copy_file_or_directory(source_path, destination_path, config) { return __awaiter(this, void 0, void 0, function () { var stats, is_directory, raw_content, processed_content; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, get_file_stats(source_path)]; case 1: stats = _a.sent(); if (!stats) { return [2 /*return*/]; } is_directory = stats.isDirectory(); if (is_directory) { return [2 /*return*/, fs.promises.mkdir(destination_path)]; } return [4 /*yield*/, fs_extra_1.default.readFile(source_path)]; case 2: raw_content = _a.sent(); return [4 /*yield*/, apply_loaders(raw_content, source_path, destination_path, config)]; case 3: processed_content = _a.sent(); return [4 /*yield*/, validate_path(destination_path)]; case 4: _a.sent(); return [2 /*return*/, fs_extra_1.default.writeFile(destination_path, processed_content)]; } }); }); } exports.copy_file_or_directory = copy_file_or_directory; /** * Tests the given `source_path` against a given rule condition * @param source_path * @param rule_condition * @param config */ function test_rule_condition(source_path, rule_condition, config) { if (Array.isArray(rule_condition)) { return rule_condition.every(function (sub_condition) { return test_rule_condition(source_path, sub_condition, config); }); } // An exact absolute path string if (typeof rule_condition === 'string') { return rule_condition === source_path; } if (rule_condition instanceof RegExp) { return rule_condition.test(source_path); } if (typeof rule_condition === 'function') { return rule_condition(source_path); } return false; } /** * Tests the given `source_path` against every rule conditions * @param source_path * @param rule * @param config */ function apply_rule_condition(source_path, rule, config) { var isMatching = rule.test !== undefined ? test_rule_condition(source_path, rule.test, config) : null; var isIncluded = rule.include !== undefined ? test_rule_condition(source_path, rule.include, config) : null; var isExcluded = rule.exclude !== undefined ? test_rule_condition(source_path, rule.exclude, config) : null; if (isIncluded === true) { return true; } if (isExcluded === true) { return false; } if (isMatching === true) { return true; } return false; } /** * Passes the content of the source file to each loader in sequence and returns a Promise with the final content * @param raw_content * @param source_path * @param destination_path * @param config */ function apply_loaders(raw_content, source_path, destination_path, config) { return __awaiter(this, void 0, void 0, function () { var processed_content, should_process_file, used_rules, loaderMeta_1; return __generator(this, function (_a) { switch (_a.label) { case 0: processed_content = raw_content; should_process_file = files_without_loaders.indexOf(source_path) === -1; if (!should_process_file) return [3 /*break*/, 2]; used_rules = config.rules.filter(function (rule) { return apply_rule_condition(source_path, rule, config); }); if (!used_rules.length) { files_without_loaders.push(source_path); return [2 /*return*/, raw_content]; } loaderMeta_1 = { source_path: source_path, destination_path: destination_path, config: config, }; return [4 /*yield*/, used_rules.reduce(function (content, rule) { return __spreadArray([], __read(rule.use), false).reverse().reduce(function (content, loader) { var loaderFn; switch (typeof loader.loader) { case 'function': loaderFn = loader.loader; break; case 'string': loaderFn = require(path.resolve(loader.loader)); break; default: throw new Error('Invalid loader type'); } return loaderFn(content, loaderMeta_1); }, processed_content); }, processed_content)]; case 1: processed_content = _a.sent(); _a.label = 2; case 2: return [2 /*return*/, processed_content]; } }); }); } /** * Returns a Promise that resolves automatically after `ms` * @param ms */ function sleep(ms) { return new Promise(function (resolve) { return setTimeout(resolve, ms); }); } exports.sleep = sleep; /** * Converts your path `p` to POSIX format irrespective of whether you're already on POSIX platforms, or on win32 * @param p path string * @see https://stackoverflow.com/a/63251716/3111787 */ function definitely_posix(p) { return p.split(path.sep).join(path.posix.sep); } exports.definitely_posix = definitely_posix;