loro/scripts/run-js-doc-tests.ts
Zixuan Chen e2be56b0c2
Some checks failed
Release WASM / Release (push) Has been cancelled
Test All / build (push) Has been cancelled
docs: update ts docs (#529)
* docs: update ts docs

* docs: update rust docs

* test: add js doc tests and fix outdated js docs
2024-10-25 16:35:33 +08:00

117 lines
3.7 KiB
TypeScript

const LORO_VERSION = "1.0.7";
export interface CodeBlock {
filename: string;
filePath: string;
lineNumber: number;
lang: string;
content: string;
}
export function extractCodeBlocks(
fileContent: string,
codeBlocks: CodeBlock[],
name: string,
path: string,
) {
// Regular expression to detect TypeScript code blocks
const codeBlockRegex = /```(typescript|ts|js|javascript)\n([\s\S]*?)```/g;
let match;
while ((match = codeBlockRegex.exec(fileContent)) !== null) {
const startLine =
fileContent.substring(0, match.index).split("\n").length;
let content = match[2];
content = content.replace(/^\s*\*/g, "");
content = content.replace(/\n\s*\*/g, "\n");
content = content.replace(/^\s*\/\/\//g, "");
content = content.replace(/\n\s*\/\/\//g, "\n");
content = replaceImportVersion(content, LORO_VERSION);
if (!content.includes("loro-crdt")) {
content = IMPORTS + content;
}
codeBlocks.push({
filename: name,
filePath: path,
lineNumber: startLine,
content,
lang: match[1],
});
}
}
function replaceImportVersion(input: string, targetVersion: string): string {
const regex = /from "loro-crdt"/g;
const replacement = `from "npm:loro-crdt@${targetVersion}"`;
return input.replace(regex, replacement);
}
const IMPORTS =
`import { Loro, LoroDoc, LoroMap, LoroText, LoroList, Delta, UndoManager, getType, isContainer } from "npm:loro-crdt@${LORO_VERSION}";
import { expect } from "npm:expect@29.7.0";\n
`;
Deno.test("extract doc tests", async () => {
const filePath = "./doc-tests-tests/example.txt";
const fileContent = await Deno.readTextFile(filePath);
const codeBlocks: CodeBlock[] = [];
extractCodeBlocks(fileContent, codeBlocks, "example.txt", filePath);
for (const block of codeBlocks) {
console.log(block.content);
console.log("==============================");
}
await runCodeBlocks(codeBlocks);
});
export async function runDocTests(paths: string[]) {
const codeBlocks: CodeBlock[] = [];
for (const path of paths) {
const fileContent = await Deno.readTextFile(path);
extractCodeBlocks(fileContent, codeBlocks, path, path);
}
await runCodeBlocks(codeBlocks);
}
async function runCodeBlocks(codeBlocks: CodeBlock[]) {
let testCases = 0;
let passed = 0;
let failed = 0;
for (const block of codeBlocks) {
try {
const command = new Deno.Command("deno", {
args: ["eval", "--ext=ts", block.content],
stdout: "null",
stderr: "inherit",
});
const process = command.spawn();
const status = await process.status;
testCases += 1;
if (status.success) {
passed += 1;
} else {
console.log("----------------");
console.log(block.content);
console.log("-----------------");
console.error(
`\x1b[31;1mError in \x1b[4m${block.filePath}:${block.lineNumber}\x1b[0m\n\n\n\n\n`,
);
failed += 1;
}
} catch (error) {
console.error("Error:", error);
}
await Deno.stdout.write(
new TextEncoder().encode(
`\r🧪 ${testCases} tests, ✅ ${passed} passed,${
failed > 0 ? " ❌" : ""
} ${failed} failed`,
),
);
}
}
if (Deno.args.length > 0) {
await runDocTests(Deno.args);
} else {
console.log("No paths provided. Please provide paths as arguments.");
}