Feat v0.6.5 renderer pipeline (#40)
All checks were successful
All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #40.
This commit is contained in:
136
src/js/__tests__/renderers.test.js
Normal file
136
src/js/__tests__/renderers.test.js
Normal file
@@ -0,0 +1,136 @@
|
||||
const { describe, it } = require('node:test');
|
||||
const assert = require('node:assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const vm = require('vm');
|
||||
|
||||
const SRC = path.join(__dirname, '..');
|
||||
|
||||
/**
|
||||
* Load the renderers module into a VM context and return the factory.
|
||||
*/
|
||||
function loadRenderers() {
|
||||
const source = fs.readFileSync(path.join(SRC, 'sw/sdk/renderers.js'), 'utf-8');
|
||||
// Strip ESM syntax for VM execution
|
||||
const cjs = source.replace(/^export /gm, '');
|
||||
const sandbox = { console, module: { exports: {} } };
|
||||
vm.createContext(sandbox);
|
||||
vm.runInContext(cjs, sandbox);
|
||||
return sandbox.createRenderers;
|
||||
}
|
||||
|
||||
describe('sw.renderers', () => {
|
||||
const createRenderers = loadRenderers();
|
||||
|
||||
it('register() adds a block renderer', () => {
|
||||
const events = [];
|
||||
const r = createRenderers((name, data, opts) => events.push({ name, data }));
|
||||
r.register('test-block', { type: 'block', pattern: 'mermaid', render() {} });
|
||||
const info = r.list();
|
||||
assert.strictEqual(info.block.length, 1);
|
||||
assert.strictEqual(info.block[0].name, 'test-block');
|
||||
assert.strictEqual(events.length, 1);
|
||||
assert.strictEqual(events[0].data.action, 'register');
|
||||
});
|
||||
|
||||
it('register() adds a post renderer', () => {
|
||||
const r = createRenderers(() => {});
|
||||
r.register('test-post', { type: 'post', render() {} });
|
||||
const info = r.list();
|
||||
assert.strictEqual(info.post.length, 1);
|
||||
assert.strictEqual(info.post[0].name, 'test-post');
|
||||
});
|
||||
|
||||
it('register() replaces duplicate by name', () => {
|
||||
const r = createRenderers(() => {});
|
||||
r.register('dup', { type: 'block', pattern: 'x', render() {} });
|
||||
r.register('dup', { type: 'block', pattern: 'y', render() {} });
|
||||
const info = r.list();
|
||||
assert.strictEqual(info.block.length, 1);
|
||||
assert.strictEqual(info.block[0].pattern, 'y');
|
||||
});
|
||||
|
||||
it('unregister() removes a renderer', () => {
|
||||
const r = createRenderers(() => {});
|
||||
r.register('rm-me', { type: 'block', pattern: 'x', render() {} });
|
||||
r.unregister('rm-me');
|
||||
assert.strictEqual(r.list().block.length, 0);
|
||||
});
|
||||
|
||||
it('register() returns an unregister function', () => {
|
||||
const r = createRenderers(() => {});
|
||||
const unreg = r.register('auto-unreg', { type: 'post', render() {} });
|
||||
assert.strictEqual(r.list().post.length, 1);
|
||||
unreg();
|
||||
assert.strictEqual(r.list().post.length, 0);
|
||||
});
|
||||
|
||||
it('runBlockRenderers() matches by pattern', () => {
|
||||
const r = createRenderers(() => {});
|
||||
let called = false;
|
||||
r.register('m', { type: 'block', pattern: 'mermaid', render() { called = true; } });
|
||||
const result = r.runBlockRenderers('mermaid', 'code', {});
|
||||
assert.ok(result);
|
||||
assert.ok(called);
|
||||
});
|
||||
|
||||
it('runBlockRenderers() matches by match function', () => {
|
||||
const r = createRenderers(() => {});
|
||||
let called = false;
|
||||
r.register('k', {
|
||||
type: 'block',
|
||||
match(lang) { return lang === 'latex' || lang === 'math'; },
|
||||
render() { called = true; },
|
||||
});
|
||||
assert.ok(r.runBlockRenderers('latex', 'code', {}));
|
||||
assert.ok(called);
|
||||
});
|
||||
|
||||
it('runBlockRenderers() returns false when no match', () => {
|
||||
const r = createRenderers(() => {});
|
||||
r.register('m', { type: 'block', pattern: 'mermaid', render() {} });
|
||||
assert.strictEqual(r.runBlockRenderers('javascript', 'code', {}), false);
|
||||
});
|
||||
|
||||
it('runBlockRenderers() case-insensitive on lang', () => {
|
||||
const r = createRenderers(() => {});
|
||||
let called = false;
|
||||
r.register('m', { type: 'block', pattern: 'mermaid', render() { called = true; } });
|
||||
assert.ok(r.runBlockRenderers('Mermaid', 'code', {}));
|
||||
assert.ok(called);
|
||||
});
|
||||
|
||||
it('runPostRenderers() calls all post renderers', () => {
|
||||
const r = createRenderers(() => {});
|
||||
const order = [];
|
||||
r.register('a', { type: 'post', priority: 20, render() { order.push('a'); } });
|
||||
r.register('b', { type: 'post', priority: 10, render() { order.push('b'); } });
|
||||
r.runPostRenderers({});
|
||||
assert.deepStrictEqual(order, ['b', 'a']); // priority 10 first
|
||||
});
|
||||
|
||||
it('block renderers respect priority (first match wins)', () => {
|
||||
const r = createRenderers(() => {});
|
||||
let winner = '';
|
||||
r.register('low', { type: 'block', pattern: 'test', priority: 50, render() { winner = 'low'; } });
|
||||
r.register('high', { type: 'block', pattern: 'test', priority: 10, render() { winner = 'high'; } });
|
||||
r.runBlockRenderers('test', '', {});
|
||||
assert.strictEqual(winner, 'high');
|
||||
});
|
||||
|
||||
it('runBlockRenderers() catches render errors gracefully', () => {
|
||||
const r = createRenderers(() => {});
|
||||
r.register('bad', { type: 'block', pattern: 'err', render() { throw new Error('boom'); } });
|
||||
const result = r.runBlockRenderers('err', 'code', {});
|
||||
assert.strictEqual(result, false); // error → returns false
|
||||
});
|
||||
|
||||
it('runPostRenderers() catches errors and continues', () => {
|
||||
const r = createRenderers(() => {});
|
||||
const order = [];
|
||||
r.register('bad', { type: 'post', priority: 10, render() { throw new Error('boom'); } });
|
||||
r.register('good', { type: 'post', priority: 20, render() { order.push('good'); } });
|
||||
r.runPostRenderers({});
|
||||
assert.deepStrictEqual(order, ['good']); // continues after error
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user