Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .c8rc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"all": true,
"exclude": [
"eslint.config.mjs",
"**/*.test.mjs",
"**/fixtures",
"src/generators/legacy-html/assets",
"src/generators/web/ui",
Expand Down
83 changes: 83 additions & 0 deletions src/generators/addon-verify/__tests__/index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import assert from 'node:assert/strict';
import { mkdtemp, readFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { describe, it } from 'node:test';

import { u } from 'unist-builder';

import addon from '../index.mjs';
import {
normalizeSectionName,
generateSectionFolderName,
} from '../utils/section.mjs';
Comment thread
AugustinMauroy marked this conversation as resolved.

describe('generators/addon-verify', () => {
it('returns empty array when no code blocks match filename comment', async () => {
const entry = {
heading: { data: { name: 'Section A' } },
content: u('root', [u('code', 'console.log("no filename header");')]),
};

const result = await addon.generate([entry], {});

// No sections were buildable / no filenames extracted
assert.deepEqual(result, []);
});

it('ignores non-buildable sections (needs both .cc and .js)', async () => {
// Only a .cc file present -> not buildable
const entry = {
heading: { data: { name: 'OnlyCC' } },
content: u('root', [u('code', '// file1.cc\nint main() {}')]),
};

const result = await addon.generate([entry], {});

assert.deepEqual(result, []);
});

it('generates files array and writes files to disk when output provided', async () => {
const sectionName = 'My Addon Section';

const entry = {
heading: { data: { name: sectionName } },
content: u('root', [
u('code', '// file1.cc\nint main() {}'),
u(
'code',
"// test.js\nmodule.exports = require('./build/Release/addon');"
),
]),
};

const tmp = await mkdtemp(join(tmpdir(), 'doc-kit-'));

const returned = await addon.generate([entry], { output: tmp });

// Returned is an array of file arrays (one per section)
assert.equal(Array.isArray(returned), true);
assert.equal(returned.length, 1);

const files = returned[0];

assert.ok(files.some(f => f.name === 'file1.cc'));
assert.ok(files.some(f => f.name === 'test.js'));
assert.ok(files.some(f => f.name === 'binding.gyp'));

// Verify files were written to disk under the computed folder name
const folderName = generateSectionFolderName(
normalizeSectionName(sectionName),
0
);

const file1 = await readFile(join(tmp, folderName, 'file1.cc'), 'utf-8');
const binding = await readFile(
join(tmp, folderName, 'binding.gyp'),
'utf-8'
);

assert.match(file1, /int main/);
assert.match(binding, /targets/);
});
Comment thread
AugustinMauroy marked this conversation as resolved.
});
60 changes: 60 additions & 0 deletions src/generators/llms-txt/__tests__/index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import assert from 'node:assert/strict';
import { readFile, mkdtemp } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { describe, it } from 'node:test';

import llms from '../index.mjs';

const makeEntry = ({
title = 'MyAPI',
depth = 1,
desc = 'A description',
api = 'doc/some/path.md',
llm_description,
} = {}) => ({
heading: { depth, data: { name: title } },
content: {
children: [
{ type: 'paragraph', children: [{ type: 'text', value: desc }] },
],
},
api_doc_source: api,
llm_description,
});

describe('generators/llms-txt', () => {
it('returns filled template including depth 1 entries', async () => {
const entry = makeEntry({ title: 'Alpha', desc: 'Alpha description' });

const result = await llms.generate([entry], {});

assert.equal(typeof result, 'string');
assert.match(result, /- \[Alpha\]/);
assert.match(result, /Alpha description/);
});

it('only includes depth 1 headings', async () => {
const entry1 = makeEntry({ title: 'Top', depth: 1, desc: 'Top desc' });
const entry2 = makeEntry({ title: 'Sub', depth: 2, desc: 'Sub desc' });

const result = await llms.generate([entry1, entry2], {});

assert.match(result, /- \[Top\]/);
assert.doesNotMatch(result, /- \[Sub\]/);
});

it('writes llms.txt when output is provided', async () => {
const entry = makeEntry({ title: 'WriteTest', desc: 'Write description' });

const tmp = await mkdtemp(join(tmpdir(), 'doc-kit-'));

const returned = await llms.generate([entry], { output: tmp });

const file = await readFile(join(tmp, 'llms.txt'), 'utf-8');

assert.equal(returned, file);
assert.match(file, /- \[WriteTest\]/);
assert.match(file, /Write description/);
});
Comment thread
AugustinMauroy marked this conversation as resolved.
});
99 changes: 99 additions & 0 deletions src/generators/man-page/__tests__/index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import assert from 'node:assert/strict';
import { mkdtemp, readFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { describe, it } from 'node:test';

import { u } from 'unist-builder';

import manpage from '../index.mjs';

const textNode = txt => u('text', txt);

const createMock = ({
api = 'cli',
slug = '',
depth = 2,
headingText = '',
desc = '',
} = {}) => ({
api,
slug,
heading: { depth, data: { text: headingText } },
// eslint-disable-next-line no-sparse-arrays
content: u('root', [, u('paragraph', [textNode(desc)])]),
Comment thread
avivkeller marked this conversation as resolved.
});

describe('generators/man-page', () => {
it('throws when no cli documentation present', async () => {
await assert.rejects(
async () => {
await manpage.generate([{ api: 'not-cli' }], {});
},
{ message: /Could not find any `cli` documentation/ }
);
});

it('generates mandoc including options and environment entries', async () => {
const components = [
createMock({ api: 'cli', slug: 'cli', depth: 1 }),
createMock({ api: 'cli', slug: 'options', depth: 2 }),
createMock({
api: 'cli',
slug: 'opt-a',
depth: 3,
headingText: '`-a`, `--all`',
desc: 'Option A description',
}),
createMock({ api: 'cli', slug: 'environment-variables-1', depth: 2 }),
createMock({
api: 'cli',
slug: 'env-foo',
depth: 3,
headingText: '`FOO=bar`',
desc: 'Env FOO description',
}),
createMock({ api: 'cli', slug: 'after', depth: 2 }),
];

const result = await manpage.generate(components, {});

// Ensure mandoc markers for options and environment variables are present
assert.match(result, /\.It Fl/);
assert.match(result, /Option A description/);
assert.match(result, /\.It Ev/);
assert.match(result, /Env FOO description/);
});

it('writes node.1 to output when provided', async () => {
const components = [
createMock({ api: 'cli', slug: 'options', depth: 2 }),
createMock({
api: 'cli',
slug: 'opt-a',
depth: 3,
headingText: '`-a`',
desc: 'desc',
}),
createMock({ api: 'cli', slug: 'environment-variables-1', depth: 2 }),
createMock({
api: 'cli',
slug: 'env',
depth: 3,
headingText: '`X=`',
desc: 'env desc',
}),
createMock({ api: 'cli', slug: 'end', depth: 2 }),
];

const tmp = await mkdtemp(join(tmpdir(), 'doc-kit-'));

const returned = await manpage.generate(components, { output: tmp });

const file = await readFile(join(tmp, 'node.1'), 'utf-8');

assert.equal(returned, file);
assert.match(file, /desc/);
assert.match(file, /env desc/);
});
Comment thread
AugustinMauroy marked this conversation as resolved.
});
31 changes: 31 additions & 0 deletions src/generators/metadata/__tests__/index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { deepStrictEqual, strictEqual } from 'node:assert';
import { describe, it } from 'node:test';

import generator from '../index.mjs';

describe('generators/metadata/index', () => {
it('streams chunk results and yields flattened arrays', async () => {
const inputs = [1, 2, 3];

const worker = {
// Simulate an async generator that yields chunked results
async *stream() {
yield [[1, 2], [3]];
yield [[4]];
},
};

const results = [];

for await (const chunk of generator.generate(inputs, {
typeMap: {},
worker,
})) {
results.push(chunk);
}

strictEqual(results.length, 2);
deepStrictEqual(results[0], [1, 2, 3]);
deepStrictEqual(results[1], [4]);
});
});
Loading
Loading