-
Notifications
You must be signed in to change notification settings - Fork 464
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tool to write multi-module tests in a single file
- Loading branch information
1 parent
f742eb0
commit ad9f91c
Showing
1 changed file
with
85 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import fs from "node:fs"; | ||
import { resolve, basename, join as joinPaths } from "node:path"; | ||
import { fileURLToPath } from "node:url"; | ||
|
||
async function* walk(dir) { | ||
for await (const d of fs.opendirSync(dir)) { | ||
const entry = joinPaths(dir, d.name); | ||
if (d.isDirectory()) yield* walk(entry); | ||
else if (d.isFile()) yield entry; | ||
} | ||
} | ||
|
||
const testsDir = resolve(fileURLToPath(import.meta.url), "../../../test"); | ||
|
||
for await (const bundleFilename of walk(testsDir)) { | ||
if (/\.multi(?:\.md)$/.test(bundleFilename)) { | ||
const folder = bundleFilename.replace(/\.multi(?:\.md)$/, "__generated"); | ||
|
||
const bundle = fs.readFileSync(bundleFilename, "utf8"); | ||
const allFiles = parse(bundleFilename, bundle); | ||
|
||
const fixtureRE = /_FIXTURE\.\w+$/; | ||
if (allFiles.filter((f) => !fixtureRE.test(f.filename)).length !== 1) { | ||
throw new Error( | ||
`Exactly one file must not end in _FIXTURE (in ${bundleFilename})` | ||
); | ||
} | ||
|
||
fs.rmSync(folder, { force: true, recursive: true }); | ||
fs.mkdirSync(folder); | ||
for (const { filename, code } of allFiles) { | ||
fs.writeFileSync(joinPaths(folder, filename), code); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @param {string} bundleFilename | ||
* @param {string} bundle | ||
*/ | ||
function parse(bundleFilename, bundle) { | ||
let index = 0; | ||
|
||
const files = []; | ||
let prefix = null; | ||
|
||
while (true) { | ||
let nextTitle = bundle.indexOf("##", index); | ||
let nextCodeStart = bundle.indexOf("```", index); | ||
let nextCodeEnd = bundle.indexOf("```", nextCodeStart + 3); | ||
if (nextCodeStart === -1 && nextTitle === -1) break; | ||
|
||
if (nextTitle === -1 || nextTitle > nextCodeStart) { | ||
throw new Error( | ||
`Code blocks must be preceded by a filename, with ## (in ${bundleFilename})` | ||
); | ||
} | ||
if (nextCodeEnd === -1) { | ||
throw new Error(`Unclosed code block (in ${bundleFilename})`); | ||
} | ||
|
||
if (prefix === null) { | ||
prefix = bundle.slice(index, nextTitle).trim(); | ||
if (prefix !== "") prefix = prefix.replaceAll(/^/gm, "// ") + "\n\n"; | ||
prefix = | ||
"// THIS FILE IS AUTOGENERATED. DO NOT EDIT DIRECTLY.\n" + | ||
`// TO MAKE CHANGES, EDIT ../${basename(bundleFilename)}\n\n` + | ||
prefix; | ||
} | ||
const filename = bundle.slice(nextTitle + 2, nextCodeStart).trim(); | ||
const code = | ||
(filename.endsWith(".js") ? prefix : "") + | ||
bundle | ||
.slice(nextCodeStart + 3, nextCodeEnd) | ||
.replace(/^\w+/, "") | ||
.trim() + | ||
"\n"; | ||
|
||
files.push({ filename, code }); | ||
|
||
index = nextCodeEnd + 3; | ||
} | ||
|
||
return files; | ||
} |