chore: fix namespaces

This commit is contained in:
2026-07-04 22:40:58 +02:00
parent 832b9b2bad
commit 9d3ef431b0
6 changed files with 66 additions and 26 deletions
+31
View File
@@ -6,6 +6,8 @@ Generate tests from your JSDoc documentation for whichever testing harness you p
> See `gen-doctests --help` for more detail.
### Generate tests
Write a doctest alongside your source code:
````ts
@@ -47,6 +49,8 @@ test("isEven()", () => {
});
```
### Config
You can also define a `doctests.config.ts` file to skip the command arguments:
```ts
@@ -58,3 +62,30 @@ export default defineConfig({
outDir: "dist/",
});
```
### Skipping tests
You can specify that a test should be ignored or that it fails by specifying
that next to the language tag of the code block:
````ts
/**
* ...
* @example
* ```ts ignore
* // this test is ignored
* ```
* @example
* ```ts fails
* // this test is expected to fail
* expect(1).toBe(2)
* ```
*/
````
If you use the `--must-assert` flag or `onlyGenerateTests` option then tests
which do not use any assertions will not be included in emitted test files.
## License
Published under [MIT License](./LICENSE)
+2 -1
View File
@@ -1,7 +1,8 @@
import { defineConfig } from "./dist/config";
export default defineConfig({
include: ["src/**.ts"],
include: ["src/**/*.ts"],
outDir: "tests/generated",
templateHeader: ["console.log('hello, world!');"],
emitRegions: true,
});
+10 -3
View File
@@ -1,9 +1,12 @@
{
"name": "gen-doctests",
"author": {
"name": "BluePlum",
"url": "https://git.louiscreates.com/blueplum"
},
"description": "Tool for generating tests from JSDoc @example:s for various test harnesses",
"keywords": ["tool", "docs", "test", "doctest"],
"private": false,
"version": "0.2.2",
"version": "0.2.3",
"type": "module",
"bin": "dist/index.js",
"scripts": {
@@ -42,5 +45,9 @@
"jiti": "^2.7.0",
"picomatch": "^4.0.5",
"typescript": "^6.0.3"
}
},
"repository": {
"url": "https://git.louiscreates.com/blueplum/gen-doctests"
},
"license": "MIT"
}
+8 -5
View File
@@ -182,14 +182,14 @@ export function createGenerator(options: Options) {
fn = harness.skip;
else fn = harness.fail;
let node: Region | null = null;
let node: Region = regions;
for (const region of test.namespace) {
regions[region] ??= {};
node = regions[region];
node[region] ??= {};
node = node[region];
}
const out = fn(src, name);
if (node !== null) node[Symbol()] = out;
if (test.namespace.length !== 0) node[Symbol()] = out;
else source += out + "\n\n";
}
@@ -205,8 +205,11 @@ export function createGenerator(options: Options) {
typeof value === "object" &&
typeof key === "string"
) {
const src = emitRegions(value);
regions.push(
harness.region(emitRegions(value), key),
options.emitRegions
? harness.region(src, key)
: src,
);
}
}
-8
View File
@@ -104,17 +104,9 @@ async function main() {
function parseWithOptions(options: Options) {
const doctest = picomatch("**/*" + options.fileExtension + ".*");
/**
* @example
* Test 1
*/
const files = globSync(options.include)
.filter((v) => !doctest(v))
.filter((path) => !lstatSync(path).isDirectory());
/**
* @example
* Test 2
*/
const parsed = files
.map((path) => parseFile(path, options))
.filter((v) => v !== null);
+15 -9
View File
@@ -161,10 +161,18 @@ export function parseFile(
kind = PathFragmentType.Other;
if (identifier !== null) {
name = identifier;
newPath.push({
kind: PathFragmentType.Other,
fragment: identifier,
});
if (node.type && ts.isFunctionLike(node.type)) {
kind = PathFragmentType.Function;
newPath.push({
kind: PathFragmentType.Function,
fragment: identifier,
});
} else {
newPath.push({
kind: PathFragmentType.Namespace,
fragment: identifier,
});
}
} else if (
ts.isComputedPropertyName(node.name) &&
ts.isBinaryExpression(node.name.expression)
@@ -176,6 +184,7 @@ export function parseFile(
fragment: "unknown",
});
}
visitThis = false;
if (node.type)
node.type.forEachChild((node) => {
@@ -223,15 +232,14 @@ export function parseFile(
.filter((tag) => tag.tagName.text === "example");
if (examples.length === 0) return;
let p = [...path];
const p = [...path];
if (name !== null && kind !== null)
p.push({ kind, fragment: name });
const pOld = p;
const namespace = [];
while (
options.emitRegions &&
p[0].kind === PathFragmentType.Namespace &&
p.length > 1
) {
@@ -239,8 +247,6 @@ export function parseFile(
namespace.push(p.shift()!.fragment);
}
if (!options.emitRegions) p = pOld;
name = computeName(p);
for (const example of examples) {