diff --git a/tools/router-gate-decide.mjs b/tools/router-gate-decide.mjs new file mode 100644 index 00000000..c7dce650 --- /dev/null +++ b/tools/router-gate-decide.mjs @@ -0,0 +1,12 @@ +/** + * Compare router recommendation (e.g. "#19", "superpowers:writing-plans", "writing-plans") + * with a registry node (id/slug/name). Returns true if any match. + */ +export function nodeMatches(recommendation, node) { + if (!recommendation || !node) return false; + return ( + recommendation === node.id || + recommendation === node.slug || + recommendation === node.name + ); +} diff --git a/tools/router-gate-decide.test.mjs b/tools/router-gate-decide.test.mjs new file mode 100644 index 00000000..3f725b78 --- /dev/null +++ b/tools/router-gate-decide.test.mjs @@ -0,0 +1,28 @@ +import { describe, it, expect } from 'vitest'; +import { nodeMatches } from './router-gate-decide.mjs'; + +describe('nodeMatches', () => { + it('matches #NN to node.id', () => { + expect(nodeMatches('#19', { name: 'writing-plans', id: '#19', slug: 'superpowers:writing-plans' })).toBe(true); + }); + + it('matches superpowers:X to canonical slug', () => { + expect(nodeMatches('superpowers:writing-plans', { name: 'writing-plans', id: '#19', slug: 'superpowers:writing-plans' })).toBe(true); + }); + + it('matches by name', () => { + expect(nodeMatches('writing-plans', { name: 'writing-plans', id: '#19', slug: 'superpowers:writing-plans' })).toBe(true); + }); + + it('rejects mismatch', () => { + expect(nodeMatches('#20', { name: 'writing-plans', id: '#19', slug: 'superpowers:writing-plans' })).toBe(false); + }); + + it('handles null recommendation', () => { + expect(nodeMatches(null, { name: 'writing-plans', id: '#19', slug: 'superpowers:writing-plans' })).toBe(false); + }); + + it('handles null node', () => { + expect(nodeMatches('#19', null)).toBe(false); + }); +});