@hypermod/cli
Version:
To download and run codemods, we provide a CLI tool called @hypermod/cli.
262 lines (261 loc) • 13.6 kB
JavaScript
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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const semver_1 = __importDefault(require("semver"));
const chalk_1 = __importDefault(require("chalk"));
const find_up_1 = __importDefault(require("find-up"));
const inquirer_1 = __importDefault(require("inquirer"));
const live_plugin_manager_1 = require("live-plugin-manager");
const core = __importStar(require("@hypermod/core"));
const fetcher_1 = require("@hypermod/fetcher");
const errors_1 = require("./errors");
const fetch_package_1 = require("./utils/fetch-package");
const merge_configs_1 = require("./utils/merge-configs");
const file_system_1 = require("./utils/file-system");
const module_loader_1 = __importDefault(require("./utils/module-loader"));
const prompt_1 = require("./prompt");
function main(paths, flags) {
return __awaiter(this, void 0, void 0, function* () {
if (paths.length === 0) {
throw new errors_1.InvalidUserInputError('No path provided, please specify which files your codemod should modify');
}
const pluginManagerConfig = {
pluginsPath: path_1.default.join(__dirname, '..', 'node_modules'),
};
// If a registry is provided in the CLI flags, use it for the pluginManagers configuration.
if (flags.registry !== undefined) {
pluginManagerConfig.npmRegistryUrl = flags.registry;
}
// If a registryToken is provided in the CLI flags, use it as an authentication token for the pluginManager
if (flags.registryToken !== undefined) {
pluginManagerConfig.npmRegistryConfig = {
auth: { token: flags.registryToken },
};
}
const packageManager = flags.experimentalLoader
? (0, module_loader_1.default)({
authToken: flags.registryToken,
npmRegistryUrl: flags.registry,
})
: new live_plugin_manager_1.PluginManager(pluginManagerConfig);
let transforms = [];
if (!flags.transform && !flags.packages) {
console.log(chalk_1.default.green('No transforms specified, attempting to find local hypermod.config file(s)'));
/**
* Attempt to locate a root package.json with a workspaces config.
* If found, show a prompt with all available codemods
*/
const localPackageJson = yield (0, file_system_1.getPackageJson)();
if (localPackageJson && localPackageJson.workspaces) {
const configs = yield (0, file_system_1.fetchConfigsForWorkspaces)(localPackageJson.workspaces);
const answers = yield inquirer_1.default.prompt([(0, prompt_1.getMultiConfigPrompt)(configs)]);
const selectedConfig = configs.find(({ filePath }) => answers.codemod.filePath === filePath);
if (!selectedConfig) {
throw new Error(`Unable to locate config at: ${answers.codemod.filePath}`);
}
if (selectedConfig.config.transforms &&
selectedConfig.config.transforms[answers.codemod.selection]) {
if (flags.sequence) {
Object.entries(selectedConfig.config.transforms)
.filter(([key]) => semver_1.default.satisfies(key, `>=${answers.codemod.selection}`))
.forEach(([, path]) => transforms.push(path));
}
else {
transforms.push(selectedConfig.config.transforms[answers.codemod.selection]);
}
}
else if (selectedConfig.config.presets &&
selectedConfig.config.presets[answers.codemod.selection]) {
transforms.push(selectedConfig.config.presets[answers.codemod.selection]);
}
}
else {
/**
* Otherwise, locate any config files in parent directories
*/
const configFilePath = yield (0, find_up_1.default)([
'hypermod.config.js',
'hypermod.config.mjs',
'hypermod.config.cjs',
'hypermod.config.ts',
'hypermod.config.tsx',
'src/hypermod.config.js',
'src/hypermod.config.mjs',
'src/hypermod.config.cjs',
'src/hypermod.config.ts',
'src/hypermod.config.tsx',
'codemods/hypermod.config.js',
'codemods/hypermod.config.mjs',
'codemods/hypermod.config.cjs',
'codemods/hypermod.config.ts',
'codemods/hypermod.config.tsx',
'codeshift.config.js',
'codeshift.config.mjs',
'codeshift.config.cjs',
'codeshift.config.ts',
'codeshift.config.tsx',
'src/codeshift.config.js',
'src/codeshift.config.mjs',
'src/codeshift.config.cjs',
'src/codeshift.config.ts',
'src/codeshift.config.tsx',
'codemods/codeshift.config.js',
'codemods/codeshift.config.mjs',
'codemods/codeshift.config.cjs',
'codemods/codeshift.config.ts',
'codemods/codeshift.config.tsx',
]);
if (!configFilePath) {
throw new errors_1.InvalidUserInputError('No transform provided, please specify a transform with either the --transform or --packages flags');
}
console.log(chalk_1.default.green('Found local hypermod.config file at:'), configFilePath);
const config = yield (0, fetcher_1.fetchConfigAtPath)(configFilePath);
const answers = yield inquirer_1.default.prompt([(0, prompt_1.getConfigPrompt)(config)]);
if (config.transforms && config.transforms[answers.codemod]) {
Object.entries(config.transforms)
.filter(([key]) => semver_1.default.satisfies(key, `>=${answers.codemod}`))
.forEach(([, codemod]) => transforms.push(`${configFilePath}@${codemod}`));
}
else if (config.presets && config.presets[answers.codemod]) {
transforms.push(`${configFilePath}#${answers.codemod}`);
}
}
}
if (flags.transform) {
if (flags.transform.includes(',')) {
flags.transform.split(',').forEach(t => transforms.push(t.trim()));
}
else {
transforms.push(flags.transform);
}
}
if (flags.packages) {
const pkgs = flags.packages.split(',').filter(pkg => !!pkg);
for (const pkg of pkgs) {
const shouldPrependAtSymbol = pkg.startsWith('@') ? '@' : '';
const pkgName = shouldPrependAtSymbol + pkg.split(/[@#]/).filter(str => !!str)[0];
const rawTransformIds = pkg.split(/(?=[@#])/).filter(str => !!str);
rawTransformIds.shift();
const transformIds = rawTransformIds
.filter(id => id.startsWith('@'))
.map(id => id.substring(1))
.sort((idA, idB) => {
if (semver_1.default.lt(idA, idB))
return -1;
if (semver_1.default.gt(idA, idB))
return 1;
return 0;
});
const presetIds = rawTransformIds
.filter(id => id.startsWith('#'))
.map(id => id.substring(1));
const { community, remote } = yield (0, fetch_package_1.fetchPackages)(pkgName, packageManager);
const config = (0, merge_configs_1.mergeConfigs)(community, remote);
// Validate transforms/presets
transformIds.forEach(id => {
if (!semver_1.default.valid(semver_1.default.coerce(id.substring(1)))) {
throw new errors_1.InvalidUserInputError(`Invalid version provided to the --packages flag. Unable to resolve version "${id}" for package "${pkgName}". Please try: "[scope]/[package]@[version]" for example @mylib/mypackage@10.0.0`);
}
if (!config.transforms || !config.transforms[id]) {
throw new errors_1.InvalidUserInputError(`Invalid version provided to the --packages flag. Unable to resolve version "${id}" for package "${pkgName}"`);
}
});
presetIds.forEach(id => {
if (!config.presets || !config.presets[id]) {
throw new errors_1.InvalidUserInputError(`Invalid preset provided to the --packages flag. Unable to resolve preset "${id}" for package "${pkgName}"`);
}
});
if (presetIds.length === 0 && transformIds.length === 0) {
const res = yield inquirer_1.default.prompt([
(0, prompt_1.getConfigPrompt)(config),
]);
if (semver_1.default.valid(semver_1.default.coerce(res.codemod))) {
transformIds.push(res.codemod);
}
else {
presetIds.push(res.codemod);
}
}
// Get transform file paths
if (config.transforms) {
if (flags.sequence) {
Object.entries(config.transforms)
.filter(([key]) => semver_1.default.satisfies(key, `>=${transformIds[0]}`))
.forEach(([, path]) => transforms.push(path));
}
else {
Object.entries(config.transforms)
.filter(([id]) => transformIds.includes(id))
.forEach(([, path]) => transforms.push(path));
}
}
// Get preset file paths
if (config.presets) {
Object.entries(config.presets)
.filter(([id]) => presetIds.includes(id))
.forEach(([, path]) => transforms.push(path));
}
}
}
if (!transforms.length) {
throw new errors_1.InvalidUserInputError('Unable to locate transforms from provided flags.');
}
// Dedupe transform array
transforms = transforms.filter((transform, i) => transforms.indexOf(transform) === i);
for (const transform of transforms) {
console.log(chalk_1.default.green('Running transform:'), transform);
yield core.run(transform, paths, {
verbose: flags.verbose,
dry: flags.dry,
print: false,
babel: true,
extensions: flags.extensions,
ignorePattern: flags.ignorePattern,
cpus: flags.cpus,
ignoreConfig: [],
runInBand: flags.runInBand,
silent: false,
parser: flags.parser,
stdin: false,
parserConfig: '',
failOnError: false,
});
}
});
}
exports.default = main;
;