@codeque/cli
Version:
Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML and CSS
221 lines (220 loc) • 11.7 kB
JavaScript
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 });
exports.search = void 0;
const core_1 = require("@codeque/core");
const colorette_1 = require("colorette");
const fs_1 = __importDefault(require("fs"));
const ora_1 = __importDefault(require("ora"));
const path_1 = __importDefault(require("path"));
const terminalEditor_1 = require("./terminalEditor");
const utils_1 = require("./utils");
const waitForSearchDecision_1 = require("./waitForSearchDecision");
function search(params) {
return __awaiter(this, void 0, void 0, function* () {
const { caseInsensitive, root = process.cwd(), limit, queryPath: queryPaths = [], entry, git, invertExitCode, version, printFilesList, omitGitIgnore, allExtensions, } = params;
let { mode, query: queries = [] } = params;
if (version) {
return (0, utils_1.printVersionNumber)();
}
const shouldOpenEditor = queries.length === 0 && queryPaths.length === 0;
const resultsLimitCount = parseInt(limit, 10);
const resolvedRoot = path_1.default.resolve(root);
mode = (0, core_1.getMode)(mode);
let prevQuery = '';
const queryCachePath = path_1.default.resolve(__dirname + '/cliQuery');
try {
prevQuery = fs_1.default.readFileSync(queryCachePath).toString();
}
catch (e) {
e;
}
const cols = process.stdout.columns;
const separator = ''.padStart(process.stdout.columns, '━');
const dot = ' • ';
const modeLabel = 'Mode: ';
const caseLabel = 'Case: ';
const caseText = caseInsensitive ? 'insensitive' : 'sensitive';
const modeAndCaseText = `${(0, colorette_1.cyan)((0, colorette_1.bold)(modeLabel))}${(0, colorette_1.green)(mode)}${dot}${(0, colorette_1.cyan)((0, colorette_1.bold)(caseLabel))}${(0, colorette_1.green)(caseText)}\n`;
const remainingCharsForRoot = cols -
modeLabel.length -
mode.length -
caseLabel.length -
caseText.length -
dot.length;
const rootLabel = 'Root: ';
const minLen = dot.length + rootLabel.length + 5;
const remainingSpaceForRootPath = remainingCharsForRoot - (dot.length + rootLabel.length);
const shortenedRoot = (0, utils_1.textEllipsis)(resolvedRoot, remainingSpaceForRootPath);
const rootText = remainingCharsForRoot > minLen
? `${(0, colorette_1.cyan)((0, colorette_1.bold)(rootLabel))}${(0, colorette_1.green)(shortenedRoot)}${dot}`
: '';
if (shouldOpenEditor) {
const q = yield (0, terminalEditor_1.openAsyncEditor)({
header: `${rootText}${modeAndCaseText}\n✨ Type query:`,
code: prevQuery,
separator,
});
fs_1.default.writeFileSync(queryCachePath, q);
queries = [q];
}
else if (queryPaths.length > 0) {
try {
queries = queryPaths.map((qp) => fs_1.default.readFileSync(path_1.default.resolve(qp)).toString());
}
catch (e) {
(0, utils_1.print)('\n' + (0, colorette_1.red)((0, colorette_1.bold)(`Query file not found:`)), e.message, '\n');
process.exit(1);
}
}
const startTime = Date.now();
const parserSettings = core_1.__internal.parserSettingsMap['babel']();
const [queryParseResults, parseOk] = (0, core_1.parseQueries)(queries, caseInsensitive, parserSettings);
if (mode === 'text') {
(0, utils_1.print)(separator + '\n' + rootText + modeAndCaseText);
queries.forEach((q) => {
(0, utils_1.print)((0, colorette_1.cyan)((0, colorette_1.bold)('Query:\n\n')) + q + '\n');
});
}
else if (parseOk) {
(0, utils_1.print)(separator + '\n' + rootText + modeAndCaseText);
queries.forEach((q) => {
(0, utils_1.print)((0, colorette_1.cyan)((0, colorette_1.bold)('Query:\n\n')) + (0, utils_1.getCodeFrame)(q, 1, true) + '\n');
});
}
else {
queries.forEach((q, index) => {
const error = queryParseResults[index].error;
const hints = queryParseResults[index].hints;
if (error) {
if (q.length > 0) {
(0, utils_1.print)((0, colorette_1.red)((0, colorette_1.bold)('Query parse error:\n\n')), (0, utils_1.getCodeFrame)(q, 1, false, error === null || error === void 0 ? void 0 : error.location), '\n');
}
(0, utils_1.print)((0, colorette_1.red)((0, colorette_1.bold)('Error:')), error === null || error === void 0 ? void 0 : error.text, '\n');
}
if (hints.length > 0) {
const preparedText = (0, utils_1.prepareHintText)(hints[0]);
(0, utils_1.print)((0, colorette_1.blue)((0, colorette_1.bold)('Hint:')), preparedText, '\n');
}
});
process.exit(1);
}
let spinner = (0, ora_1.default)(`Getting files list `).start();
let filePaths = [];
try {
filePaths = yield (0, core_1.getFilesList)({
searchRoot: resolvedRoot,
entryPoint: entry,
byGitChanges: git,
omitGitIgnore,
extensionTester: allExtensions ? /\.(\w)+$/ : undefined,
});
}
catch (e) {
(0, utils_1.print)('\n');
(0, utils_1.print)((0, colorette_1.bold)((0, colorette_1.red)('Error while getting files list:')));
(0, utils_1.print)(e.message);
process.exit(1);
}
spinner.stop();
spinner = (0, ora_1.default)(`Searching `).start();
const { matches, errors } = yield (0, core_1.searchMultiThread)({
mode,
filePaths,
caseInsensitive,
queryCodes: queries,
});
spinner.stop();
const endTime = Date.now();
if (matches.length > 0) {
const groupedMatches = Object.entries((0, core_1.groupMatchesByFile)(matches));
const resultsText = matches.length <= resultsLimitCount
? `Results:\n`
: `First ${resultsLimitCount} results:\n`;
(0, utils_1.print)((0, colorette_1.cyan)((0, colorette_1.bold)(resultsText)));
let printedResultsCounter = 0;
let currentFileIndex = 0;
while (printedResultsCounter < resultsLimitCount &&
groupedMatches[currentFileIndex] !== undefined) {
const [filePath, matches] = groupedMatches[currentFileIndex];
const relativePath = root === process.cwd()
? path_1.default.relative(resolvedRoot, filePath)
: filePath;
const maxRelativePathDisplayLength = cols - 4;
const shortenRelativePath = (0, utils_1.textEllipsis)(relativePath, maxRelativePathDisplayLength);
const leftPaddingForCentering = Math.trunc((cols - shortenRelativePath.length - 4) / 2);
const leftPaddingStr = ''.padStart(leftPaddingForCentering, ' ');
(0, utils_1.print)(''.padStart(leftPaddingForCentering, '━') +
'┯'.padEnd(shortenRelativePath.length + 3, '━') +
'┯' +
''.padEnd(cols - (leftPaddingForCentering + shortenRelativePath.length + 4), '━'));
(0, utils_1.print)(leftPaddingStr + '│ ' + (0, colorette_1.bold)((0, colorette_1.green)(shortenRelativePath)) + ' │');
(0, utils_1.print)(leftPaddingStr + '╰'.padEnd(shortenRelativePath.length + 3, '─') + '╯');
(0, utils_1.print)('');
for (const match of matches) {
if (printedResultsCounter >= resultsLimitCount) {
break;
}
const resultCode = match.extendedCodeFrame
? match.extendedCodeFrame.code
: match.code;
const matchStartLine = match.loc.start.line;
const codeFrameStartLine = match.extendedCodeFrame
? match.extendedCodeFrame.startLine
: matchStartLine;
const codeFrame = (0, utils_1.getCodeFrame)(resultCode, codeFrameStartLine);
(0, utils_1.print)(`${(0, colorette_1.green)(relativePath)}:${(0, colorette_1.magenta)(matchStartLine)}:${(0, colorette_1.yellow)(match.loc.start.column + 1)}`);
(0, utils_1.print)('\n' + codeFrame + '\n');
printedResultsCounter++;
}
currentFileIndex++;
}
(0, utils_1.print)(separator);
(0, utils_1.print)('');
(0, utils_1.print)((0, colorette_1.cyan)((0, colorette_1.bold)('Total count:')), (0, colorette_1.magenta)(matches.length));
}
else {
(0, utils_1.print)((0, colorette_1.cyan)((0, colorette_1.bold)(`No results found${invertExitCode ? '!' : ' :c'}`)));
}
queryParseResults.forEach(({ hints }, queryIndex) => {
hints.forEach((hint, hintIndex) => {
if (queryIndex === 0 && hintIndex === 0) {
(0, utils_1.print)(''); // new line
}
(0, utils_1.print)((0, colorette_1.blue)((0, colorette_1.bold)('Hint:')), (0, utils_1.prepareHintText)(hint), '\n');
});
});
(0, utils_1.print)((0, colorette_1.cyan)((0, colorette_1.bold)('Found in:')), (0, colorette_1.magenta)((endTime - startTime) / 1000), 's');
(0, utils_1.print)((0, colorette_1.cyan)((0, colorette_1.bold)('Searched files:')), (0, colorette_1.magenta)(filePaths.length));
if (errors.length > 0) {
(0, utils_1.print)((0, colorette_1.red)((0, colorette_1.bold)('Search failed for:')), (0, colorette_1.magenta)(errors.length), 'file(s)');
}
if (printFilesList) {
filePaths.forEach((filePath) => (0, utils_1.print)((0, colorette_1.green)(path_1.default.relative(root, filePath))));
}
(0, utils_1.print)(''); // new line
if (shouldOpenEditor) {
const shouldStartNextSearch = yield (0, waitForSearchDecision_1.waitForSearchDecision)();
if (shouldStartNextSearch) {
yield search(params);
}
}
else {
const hasMatches = matches.length > 0;
const shouldFail = hasMatches === invertExitCode;
process.exit(shouldFail ? 1 : 0);
}
});
}
exports.search = search;
;