test: markdown parser subsystem (58) + custom-emoji readers (32)

Via subagents, probe-verified against real output, no bugs:
- markdown: internal/utils (11), inline/runner (7), inline/parser (21 — bold/
  italic/underline/strike/code/spoiler/link, nesting, precedence, URL lookbehind),
  block/parser (19 — headings/code-fences/quotes/lists/<br>/escapes). Closes the
  biggest coverage hole (core message rendering).
- custom-emoji: PackMetaReader (6), PackImageReader (7), PackImagesReader (4),
  utils equality+makeImagePacks (5), recent-emoji promote/increment/100-cap (10).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 14:52:48 -04:00
co-authored by Claude Opus 4.8
parent 160c09e525
commit 230ef8ed7c
9 changed files with 719 additions and 0 deletions
@@ -0,0 +1,92 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { PackImageReader } from './PackImageReader';
import { ImageUsage, PackImage } from './types';
test('fromPackImage returns undefined when url is missing or not a string', () => {
assert.equal(PackImageReader.fromPackImage('cat', {} as unknown as PackImage), undefined);
assert.equal(
PackImageReader.fromPackImage('cat', { url: 123 } as unknown as PackImage),
undefined,
);
});
test('fromPackImage builds a reader with shortcode and url', () => {
const reader = PackImageReader.fromPackImage('cat', { url: 'mxc://x/cat' });
assert.ok(reader);
assert.equal(reader?.shortcode, 'cat');
assert.equal(reader?.url, 'mxc://x/cat');
});
test('body reads only string values', () => {
assert.equal(PackImageReader.fromPackImage('c', { url: 'u', body: 'Cat' })?.body, 'Cat');
assert.equal(PackImageReader.fromPackImage('c', { url: 'u' })?.body, undefined);
assert.equal(
PackImageReader.fromPackImage('c', { url: 'u', body: 5 } as unknown as PackImage)?.body,
undefined,
);
});
test('info is passed through unchanged', () => {
const info = { w: 10, h: 10 };
assert.equal(
PackImageReader.fromPackImage('c', { url: 'u', info } as unknown as PackImage)?.info,
info,
);
assert.equal(PackImageReader.fromPackImage('c', { url: 'u' })?.info, undefined);
});
test('usage filters to known values and returns undefined when none/non-array', () => {
assert.equal(PackImageReader.fromPackImage('c', { url: 'u' })?.usage, undefined);
assert.equal(
PackImageReader.fromPackImage('c', {
url: 'u',
usage: 'emoticon' as unknown as ImageUsage[],
})?.usage,
undefined,
);
assert.equal(
PackImageReader.fromPackImage('c', {
url: 'u',
usage: ['bogus'] as unknown as ImageUsage[],
})?.usage,
undefined,
);
assert.deepEqual(
PackImageReader.fromPackImage('c', { url: 'u', usage: [ImageUsage.Sticker] })?.usage,
[ImageUsage.Sticker],
);
assert.deepEqual(
PackImageReader.fromPackImage('c', {
url: 'u',
usage: [ImageUsage.Emoticon, 'x', ImageUsage.Sticker] as unknown as ImageUsage[],
})?.usage,
[ImageUsage.Emoticon, ImageUsage.Sticker],
);
});
test('content reconstructs the PackImage from url and raw image fields', () => {
const info = { w: 1, h: 1 };
const reader = PackImageReader.fromPackImage('c', {
url: 'u',
body: 'Cat',
usage: [ImageUsage.Emoticon],
info,
} as unknown as PackImage);
assert.deepEqual(reader?.content, {
url: 'u',
body: 'Cat',
usage: [ImageUsage.Emoticon],
info,
});
});
test('content preserves raw usage even when usage getter filters it', () => {
// content uses the raw image.usage, not the filtered usage getter
const reader = PackImageReader.fromPackImage('c', {
url: 'u',
usage: ['bogus'] as unknown as ImageUsage[],
});
assert.deepEqual(reader?.content.usage, ['bogus'] as unknown as ImageUsage[]);
assert.equal(reader?.usage, undefined);
});
@@ -0,0 +1,44 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { PackImagesReader } from './PackImagesReader';
import { PackImages, ImageUsage } from './types';
test('collection builds a shortcode -> reader map', () => {
const images: PackImages = {
cat: { url: 'mxc://x/cat', usage: [ImageUsage.Emoticon] },
dog: { url: 'mxc://x/dog' },
};
const reader = new PackImagesReader(images);
const collection = reader.collection;
assert.equal(collection.size, 2);
assert.equal(collection.get('cat')?.url, 'mxc://x/cat');
assert.equal(collection.get('cat')?.shortcode, 'cat');
assert.equal(collection.get('dog')?.url, 'mxc://x/dog');
});
test('collection drops invalid images (missing/non-string url)', () => {
const images = {
good: { url: 'mxc://x/good' },
noUrl: {},
badUrl: { url: 5 },
} as unknown as PackImages;
const collection = new PackImagesReader(images).collection;
assert.equal(collection.size, 1);
assert.ok(collection.has('good'));
assert.equal(collection.has('noUrl'), false);
assert.equal(collection.has('badUrl'), false);
});
test('collection of an empty image set is an empty map', () => {
const collection = new PackImagesReader({}).collection;
assert.equal(collection.size, 0);
});
test('collection is memoized (same Map instance returned)', () => {
const reader = new PackImagesReader({ cat: { url: 'u' } });
const first = reader.collection;
const second = reader.collection;
assert.equal(first, second);
});
@@ -0,0 +1,48 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { PackMetaReader } from './PackMetaReader';
import { ImageUsage, PackMeta } from './types';
const reader = (meta: PackMeta) => new PackMetaReader(meta);
test('name reads display_name only when it is a string', () => {
assert.equal(reader({ display_name: 'Cats' }).name, 'Cats');
assert.equal(reader({}).name, undefined);
assert.equal(reader({ display_name: 42 } as unknown as PackMeta).name, undefined);
});
test('avatar reads avatar_url only when it is a string', () => {
assert.equal(reader({ avatar_url: 'mxc://x/y' }).avatar, 'mxc://x/y');
assert.equal(reader({}).avatar, undefined);
assert.equal(reader({ avatar_url: {} } as unknown as PackMeta).avatar, undefined);
});
test('attribution reads attribution only when it is a string', () => {
assert.equal(reader({ attribution: 'me' }).attribution, 'me');
assert.equal(reader({}).attribution, undefined);
assert.equal(reader({ attribution: 0 } as unknown as PackMeta).attribution, undefined);
});
test('usage falls back when missing, non-array, or empty/unknown', () => {
const fallback = [ImageUsage.Emoticon, ImageUsage.Sticker];
assert.deepEqual(reader({}).usage, fallback);
assert.deepEqual(reader({ usage: 'emoticon' } as unknown as PackMeta).usage, fallback);
assert.deepEqual(reader({ usage: [] }).usage, fallback);
assert.deepEqual(reader({ usage: ['bogus'] as unknown as ImageUsage[] }).usage, fallback);
});
test('usage filters to only known values', () => {
assert.deepEqual(reader({ usage: [ImageUsage.Emoticon] }).usage, [ImageUsage.Emoticon]);
assert.deepEqual(reader({ usage: [ImageUsage.Sticker] }).usage, [ImageUsage.Sticker]);
assert.deepEqual(
reader({
usage: [ImageUsage.Emoticon, 'bogus', ImageUsage.Sticker] as unknown as ImageUsage[],
}).usage,
[ImageUsage.Emoticon, ImageUsage.Sticker],
);
});
test('content returns the original meta object', () => {
const meta: PackMeta = { display_name: 'Cats', usage: [ImageUsage.Emoticon] };
assert.equal(reader(meta).content, meta);
});
@@ -0,0 +1,77 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { MatrixEvent } from 'matrix-js-sdk';
import { packAddressEqual, imageUsageEqual, packMetaEqual, makeImagePacks } from './utils';
import { PackAddress } from './PackAddress';
import { PackMetaReader } from './PackMetaReader';
import { ImageUsage, PackContent, PackMeta } from './types';
test('packAddressEqual handles undefined and value equality', () => {
assert.equal(packAddressEqual(undefined, undefined), true);
assert.equal(packAddressEqual(new PackAddress('!r', 'k'), undefined), false);
assert.equal(packAddressEqual(undefined, new PackAddress('!r', 'k')), false);
assert.equal(packAddressEqual(new PackAddress('!r', 'k'), new PackAddress('!r', 'k')), true);
assert.equal(packAddressEqual(new PackAddress('!r', 'k'), new PackAddress('!r', 'j')), false);
assert.equal(packAddressEqual(new PackAddress('!r', 'k'), new PackAddress('!s', 'k')), false);
});
test('imageUsageEqual compares set membership and length', () => {
assert.equal(imageUsageEqual([], []), true);
assert.equal(imageUsageEqual([ImageUsage.Emoticon], [ImageUsage.Emoticon]), true);
assert.equal(
imageUsageEqual(
[ImageUsage.Emoticon, ImageUsage.Sticker],
[ImageUsage.Sticker, ImageUsage.Emoticon],
),
true,
);
assert.equal(imageUsageEqual([ImageUsage.Emoticon], [ImageUsage.Sticker]), false);
assert.equal(
imageUsageEqual([ImageUsage.Emoticon], [ImageUsage.Emoticon, ImageUsage.Sticker]),
false,
);
});
const meta = (m: PackMeta) => new PackMetaReader(m);
test('packMetaEqual compares name, avatar, attribution and usage', () => {
assert.equal(packMetaEqual(meta({ display_name: 'A' }), meta({ display_name: 'A' })), true);
assert.equal(packMetaEqual(meta({ display_name: 'A' }), meta({ display_name: 'B' })), false);
assert.equal(packMetaEqual(meta({ avatar_url: 'u' }), meta({ avatar_url: 'v' })), false);
assert.equal(packMetaEqual(meta({ attribution: 'x' }), meta({ attribution: 'y' })), false);
// both fall back to default usage => equal
assert.equal(packMetaEqual(meta({}), meta({})), true);
assert.equal(
packMetaEqual(meta({ usage: [ImageUsage.Emoticon] }), meta({ usage: [ImageUsage.Sticker] })),
false,
);
});
const eventStub = (id: string | undefined, content: PackContent = {}): MatrixEvent =>
({
getId: () => id,
getRoomId: () => '!room:server',
getStateKey: () => 'state-key',
getContent: () => content,
}) as unknown as MatrixEvent;
test('makeImagePacks builds packs and skips events without an id', () => {
const events = [
eventStub('$1', { pack: { display_name: 'One' } }),
eventStub(undefined, { pack: { display_name: 'Skip' } }),
eventStub('$2', { images: { cat: { url: 'mxc://x/cat' } } }),
];
const packs = makeImagePacks(events);
assert.equal(packs.length, 2);
assert.equal(packs[0].id, '$1');
assert.equal(packs[0].meta.name, 'One');
assert.equal(packs[0].address?.roomId, '!room:server');
assert.equal(packs[0].address?.stateKey, 'state-key');
assert.equal(packs[1].id, '$2');
assert.equal(packs[1].images.collection.get('cat')?.url, 'mxc://x/cat');
});
test('makeImagePacks returns empty for empty input', () => {
assert.deepEqual(makeImagePacks([]), []);
});