feat: add protocol explorer with catalogs and live playground
This commit is contained in:
@@ -5,12 +5,15 @@ import test from 'node:test';
|
||||
import { createMarkdownProcessor } from '@astrojs/markdown-remark';
|
||||
import { load } from 'cheerio';
|
||||
import documentLinks, { contentsRoot } from '../plugins/document-links.mjs';
|
||||
import { bookTree } from '../src/lib/landing-tree.ts';
|
||||
import { publicTree } from '../src/lib/landing-tree.ts';
|
||||
import { createWorldspaceData } from '../src/lib/worldspace-data.ts';
|
||||
|
||||
const pages = {
|
||||
'/': { title: 'Worldspace Interface Protocol', href: '/', html: '<h1>Home</h1>' },
|
||||
'/book': { title: 'Book', href: '/book/', html: '<h1>Book</h1>' },
|
||||
'/sources': { title: 'Sources', href: '/sources/', html: '<h1>Sources</h1>' },
|
||||
'/packages': { title: 'Packages', href: '/packages/', html: '<h1>Packages</h1>' },
|
||||
'/playground': { title: 'Playground', href: '/playground/', html: '<h1>Playground</h1>' },
|
||||
};
|
||||
const source = (id) => ({ id, title: id, href: `/book/${id}/`, html: `<h1>${id}</h1>` });
|
||||
|
||||
@@ -49,15 +52,15 @@ function checkIdentity(data) {
|
||||
test('actual public documents keep Web and display identities but acquire real parent paths', () => {
|
||||
const data = createWorldspaceData(documents, pages);
|
||||
checkIdentity(data);
|
||||
const display = bookTree(documents);
|
||||
assert.equal(data.nodes.length, documents.length + 2);
|
||||
const display = publicTree(documents);
|
||||
assert.equal(data.nodes.length, documents.length + 5);
|
||||
assert.deepEqual(data.nodes.map((node) => node.displayPath), display.map((node) => node.path));
|
||||
for (const node of data.nodes) {
|
||||
const legacy = display.find((item) => item.path === node.displayPath);
|
||||
assert.equal(node.parent, legacy.parent === undefined ? undefined : data.nodes.find((item) => item.displayPath === legacy.parent).path);
|
||||
if (legacy.href) {
|
||||
assert.equal(node.href, legacy.href);
|
||||
assert.equal(node.html, documents.find((entry) => `/${entry.id}.md` === node.displayPath).html);
|
||||
assert.equal(node.html, (documents.find((entry) => `/${entry.id}.md` === node.displayPath) ?? pages[node.displayPath]).html);
|
||||
assert.match(node.html, /<h1/);
|
||||
}
|
||||
}
|
||||
@@ -66,7 +69,20 @@ test('actual public documents keep Web and display identities but acquire real p
|
||||
assert.equal(section.parent, '/book/1-concept.md');
|
||||
assert.equal(section.href, '/book/1.1-interaction-abstraction/');
|
||||
assert.equal(data.nodes[1].name, 'book');
|
||||
assert.equal(display[1].name, 'book/');
|
||||
assert.equal(display[1].name, 'book');
|
||||
});
|
||||
|
||||
test('catalog and playground objects retain root identity, standalone URLs and no static descendants', () => {
|
||||
const data = createWorldspaceData(documents, pages);
|
||||
assert.deepEqual(data.nodes.filter((node) => node.parent === '/').map((node) => node.path), ['/book', '/sources', '/packages', '/playground']);
|
||||
for (const path of ['/sources', '/packages', '/playground']) {
|
||||
const leaf = data.nodes.find((node) => node.path === path);
|
||||
assert.equal(leaf.displayPath, path);
|
||||
assert.equal(leaf.href, `${path}/`);
|
||||
assert.equal(leaf.html, pages[path].html);
|
||||
assert.equal(data.nodes.filter((node) => node.parent === path).length, 0);
|
||||
assert.ok(!data.nodes.some((node) => node.path.startsWith(`${path}/`)));
|
||||
}
|
||||
});
|
||||
|
||||
test('drafts are removed before hierarchy, body and URL generation', () => {
|
||||
@@ -86,6 +102,9 @@ test('nested numbering, real directories and site base prefixes remain unambiguo
|
||||
const data = createWorldspaceData(docs, {
|
||||
'/': { ...pages['/'], href: '/reference/' },
|
||||
'/book': { ...pages['/book'], href: '/reference/book/' },
|
||||
'/sources': { ...pages['/sources'], href: '/reference/sources/' },
|
||||
'/packages': { ...pages['/packages'], href: '/reference/packages/' },
|
||||
'/playground': { ...pages['/playground'], href: '/reference/playground/' },
|
||||
'/other': { title: 'other/', href: '/reference/book/other/', html: '<h1>other/</h1>' },
|
||||
});
|
||||
checkIdentity(data);
|
||||
@@ -108,11 +127,14 @@ test('invalid, duplicate and incomplete generated inputs fail rather than lose d
|
||||
assert.throws(() => createWorldspaceData([source('dir/a')], pages), /Missing rendered page: \/dir/);
|
||||
});
|
||||
|
||||
test('root and book index content is supplied by their existing page renderers', () => {
|
||||
test('root, book, catalog and playground content is supplied by their shared page renderers', () => {
|
||||
const data = createWorldspaceData([], pages);
|
||||
assert.deepEqual(data.nodes, [
|
||||
{ path: '/', name: '', displayPath: '/', ...pages['/'] },
|
||||
{ path: '/book', name: 'book', displayPath: '/book', parent: '/', ...pages['/book'] },
|
||||
{ path: '/sources', name: 'sources', displayPath: '/sources', parent: '/', ...pages['/sources'] },
|
||||
{ path: '/packages', name: 'packages', displayPath: '/packages', parent: '/', ...pages['/packages'] },
|
||||
{ path: '/playground', name: 'playground', displayPath: '/playground', parent: '/', ...pages['/playground'] },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -122,10 +144,11 @@ test('built artifact contains exactly public routes and the same rendered articl
|
||||
{ skip: process.env.WIP_TEST_GENERATED !== '1' }, async () => {
|
||||
const data = JSON.parse(await readFile(new URL('../dist/worldspace.json', import.meta.url), 'utf8'));
|
||||
checkIdentity(data);
|
||||
assert.equal(data.nodes.length, documents.length + 2);
|
||||
assert.equal(data.nodes.length, documents.length + 5);
|
||||
assert.deepEqual(new Set(data.nodes.filter((node) => node.displayPath.endsWith('.md')).map((node) => node.displayPath.slice(1))), new Set(publicFiles));
|
||||
for (const node of data.nodes) {
|
||||
const relative = node.displayPath === '/' ? 'index.html' : node.displayPath === '/book' ? 'book/index.html'
|
||||
: ['/sources', '/packages', '/playground'].includes(node.displayPath) ? `${node.displayPath.slice(1)}/index.html`
|
||||
: `book/${node.displayPath.slice(1, -3)}/index.html`;
|
||||
const page = load(await readFile(new URL(`../dist/${relative}`, import.meta.url), 'utf8'));
|
||||
// Astro adds hydration/render markers outside the actual article fragment.
|
||||
|
||||
Reference in New Issue
Block a user