ts-ast
Version:
Command line interface for cannabis, the TypeScript advanced AST Query library
145 lines (134 loc) • 5.99 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const shelljs_1 = require("shelljs");
const path_1 = require("path");
const cannabis_1 = require("cannabis");
const misc_utils_of_mine_generic_1 = require("misc-utils-of-mine-generic");
const fs_1 = require("fs");
const glob_1 = require("glob");
function main() {
return __awaiter(this, void 0, void 0, function* () {
const options = require('yargs-parser')(process.argv.slice(2));
preconditions(options);
const query = shelljs_1.test('-f', options.query) ? misc_utils_of_mine_generic_1.tryTo(() => JSON.parse(fs_1.readFileSync(options.query).toString())) : options.query;
if (!query) {
fail('Unable to read query from ' + options.query);
}
let result;
if (options.project) {
let tsConfigFile = options.project;
if (shelljs_1.test('-d', options.project)) {
tsConfigFile = path_1.join(options.project, 'tsconfig.json');
}
if (!shelljs_1.test('-f', tsConfigFile)) {
fail(`Project's tsconfig.json file cannot be found, exiting.`);
}
const p = cannabis_1.loadProject(tsConfigFile);
const root = p.getRootDirectory();
result = cannabis_1.queryAst(query, root);
}
else if (options.files) {
const files = shelljs_1.test('-f', options.files) ? [options.files] : glob_1.sync(options.files);
const { error } = cannabis_1.queryAst(query, 'var a');
if (error) {
result = { error };
}
else {
result = { result: files.map(f => cannabis_1.queryAst(query, fs_1.readFileSync(f).toString()).result).filter(misc_utils_of_mine_generic_1.notUndefined).flat() };
}
}
if (result) {
if (result.error) {
fail(`An error ocurred: \n ${printError(result.error)}`);
}
let outputText = '';
if (options.outputCount) {
outputText = result.result.length + '';
}
else {
const output = getResultOutput(result.result, options.output);
outputText = options.outputCompress ? JSON.stringify(output) : JSON.stringify(output, null, 2);
}
if (options.outputFile) {
fs_1.writeFileSync(options.outputFile, outputText);
}
else {
process.stdout.write(outputText + '\n');
}
}
});
}
exports.main = main;
function getResultOutput(result, style = ['nodePath', 'name', 'kind']) {
return result.map(node => misc_utils_of_mine_generic_1.arrayToObject(style, s => {
if (s === 'nodePath') {
return cannabis_1.getASTNodePath(node);
}
else if (s === 'name') {
return cannabis_1.getASTNodeName(node);
}
else if (s === 'kind') {
return cannabis_1.getASTNodeKindName(node);
}
else if (s === 'text') {
return cannabis_1.getASTNodeText(node);
}
else if (s === 'filePath') {
return cannabis_1.getASTNodeFilePath(node);
}
}));
}
function printError(e) {
return `${e.name}, "${e.message}"\n * ${(e.stack || '').split('\n').join('\n * ')}`;
}
function preconditions(options) {
if (options.output) {
options.output = options.output.split(',');
}
if (options.help) {
printHelp();
process.exit(0);
}
if (!options.query) {
fail(`--query argument is mandatory and none was given. Aborting.`);
}
if (!options.files && !options.project) {
fail(`One of --files or --project arguments is mandatory and none was given. Aborting.`);
}
}
function fail(s) {
console.error(s);
process.exit(1);
}
function printHelp() {
console.log(`
Usage: cannabis --query "//ClassDeclaration [@modifiers=~'export']" --files "src/**/foo/**/*.ts*"
Options:
* '--query': the query to search. It could be a query string or a text file with the query.
If a files exists it will be used, otherwise it assumes that is a query string.
Examples: '--query "//* [@name == 'foo']"', '--query ./queries/myLongQuery.txt'.
* '--files': TypeScript files to search. Valid files are .ts, .tsx, .js, .jsx.
The value could be a glob pattern, in that case all files matching the pattern will be the input.
Examples: '--files "src/**/are42/**/*.ts?"'.
* '--project': TypeScript project in which to search. It could be a folder or a 'tsconfig.json'
path. If '--files' also given it will be used as a filter pattern.
* '--params': query parameters. It could be a json file containing an object or a literal json
text. Examples: '--params blackListWords.json', '--params '{"blackList": ["foo","bar"]}''
* '--output': the output style. Valid values: 'nodePath', 'text', 'name', 'filePath', 'kind'
or a combination of any of them, comma separated.
* '--help': prints help and exits.
* '--outputFile': If given the search result will be written in that file, otherwise will
be written in stdout.
* '--outputCompress': if given JSON output will be minified.
* '--outputCount': Just print the result count.
`);
}
//# sourceMappingURL=main.js.map