@moonwall/cli
Version:
Testing framework for the Moon family of projects
134 lines (133 loc) • 4.06 kB
JavaScript
// src/internal/testIdParser.ts
import { Lang, parse, findInFiles } from "@ast-grep/napi";
function extractIdFromObject(objNode) {
for (const child of objNode.children()) {
if (child.kind() === "pair") {
const key = child.field("key");
const value = child.field("value");
if (key?.text() === "id" && value) {
return value.text().replace(/^['"`]|['"`]$/g, "");
}
}
}
return void 0;
}
function findIdValueNode(objNode) {
for (const child of objNode.children()) {
if (child.kind() === "pair") {
const key = child.field("key");
const value = child.field("value");
if (key?.text() === "id" && value) {
return value;
}
}
}
return void 0;
}
function extractTestIds(fileContent) {
const ast = parse(Lang.TypeScript, fileContent);
const root = ast.root();
const describeSuiteCall = root.find("describeSuite($OPTS)");
let suiteId;
if (describeSuiteCall) {
const optsNode = describeSuiteCall.getMatch("OPTS");
if (optsNode && optsNode.kind() === "object") {
suiteId = extractIdFromObject(optsNode);
}
}
const testIds = [];
const itCalls = root.findAll("it($OPTS)");
for (const itCall of itCalls) {
const optsNode = itCall.getMatch("OPTS");
if (optsNode && optsNode.kind() === "object") {
const testId = extractIdFromObject(optsNode);
if (testId) {
testIds.push(testId);
}
}
}
return { suiteId, testIds };
}
function replaceSuiteId(fileContent, newId) {
const ast = parse(Lang.TypeScript, fileContent);
const root = ast.root();
const describeSuiteCall = root.find("describeSuite($OPTS)");
if (!describeSuiteCall) {
return void 0;
}
const optsNode = describeSuiteCall.getMatch("OPTS");
if (!optsNode || optsNode.kind() !== "object") {
return void 0;
}
const idValueNode = findIdValueNode(optsNode);
if (!idValueNode) {
return void 0;
}
const originalText = idValueNode.text();
const quoteChar = originalText[0];
const edit = idValueNode.replace(`${quoteChar}${newId}${quoteChar}`);
return root.commitEdits([edit]);
}
function hasSuiteDefinition(fileContent) {
const ast = parse(Lang.TypeScript, fileContent);
const root = ast.root();
return root.find("describeSuite($$$)") !== null;
}
async function findTestFilesMatchingPattern(testDirs, includeGlobs, idPattern) {
const matches = [];
let processedCount = 0;
let expectedCount;
await new Promise((resolve, reject) => {
findInFiles(
Lang.TypeScript,
{
paths: testDirs,
matcher: { rule: { pattern: "describeSuite($OPTS)" } },
languageGlobs: includeGlobs
},
(err, nodes) => {
if (err) {
reject(err);
return;
}
if (nodes.length === 0) return;
const node = nodes[0];
const filePath = node.getRoot().filename();
const root = node.getRoot().root();
const optsNode = node.getMatch("OPTS");
if (!optsNode || optsNode.kind() !== "object") return;
const suiteId = extractIdFromObject(optsNode);
if (!suiteId) return;
const testIds = [];
const itCalls = root.findAll("it($OPTS)");
for (const itCall of itCalls) {
const itOpts = itCall.getMatch("OPTS");
if (itOpts && itOpts.kind() === "object") {
const testId = extractIdFromObject(itOpts);
if (testId) testIds.push(testId);
}
}
const allIds = [suiteId, ...testIds.map((tid) => suiteId + tid)];
if (allIds.some((id) => idPattern.test(id))) {
matches.push(filePath);
}
processedCount++;
if (expectedCount !== void 0 && processedCount >= expectedCount) {
resolve();
}
}
).then((count) => {
expectedCount = count;
if (count === 0 || processedCount >= count) {
resolve();
}
}).catch(reject);
});
return matches;
}
export {
extractTestIds,
findTestFilesMatchingPattern,
hasSuiteDefinition,
replaceSuiteId
};