mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-13 01:55:50 -07:00
47d31e9628
- Add extension-icons module (buildIconIndex, isSafeIconUrl, repoFaviconUrl, iconMonogram) with tests - Render each row's icon with a monogram fallback while loading or missing - Installed extensions borrow their icon from the catalogue; repo rows use the index host's favicon - Restrict icon loads to https URLs - Thread iconUrl through AvailableExtension and the runtime, document the feature
43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { buildIconIndex, iconMonogram, isSafeIconUrl, repoFaviconUrl } from './extension-icons';
|
|
|
|
test('buildIconIndex maps packages to their icon, skipping empty URLs', () => {
|
|
const index = buildIconIndex([
|
|
{ pkg: 'a.b.c', iconUrl: 'https://repo.example/icon/a.b.c.png' },
|
|
{ pkg: 'd.e.f', iconUrl: '' },
|
|
]);
|
|
assert.equal(index.get('a.b.c'), 'https://repo.example/icon/a.b.c.png');
|
|
assert.equal(index.has('d.e.f'), false);
|
|
});
|
|
|
|
test('isSafeIconUrl accepts https only', () => {
|
|
assert.equal(isSafeIconUrl('https://repo.example/icon/x.png'), true);
|
|
assert.equal(isSafeIconUrl('http://repo.example/icon/x.png'), false);
|
|
assert.equal(isSafeIconUrl('javascript:alert(1)'), false);
|
|
assert.equal(isSafeIconUrl(null), false);
|
|
assert.equal(isSafeIconUrl(undefined), false);
|
|
});
|
|
|
|
test('repoFaviconUrl points at the index host, https only', () => {
|
|
assert.equal(
|
|
repoFaviconUrl(' https://raw.githubusercontent.com/u/r/main/index.min.json '),
|
|
'https://raw.githubusercontent.com/favicon.ico',
|
|
);
|
|
assert.equal(repoFaviconUrl('http://repo.example/index.json'), null);
|
|
assert.equal(repoFaviconUrl('not a url'), null);
|
|
});
|
|
|
|
test('iconMonogram takes the first letter or digit, uppercased', () => {
|
|
assert.equal(iconMonogram('AllAnime'), 'A');
|
|
assert.equal(iconMonogram(' gogoanime'), 'G');
|
|
assert.equal(iconMonogram('» Foo'), 'F');
|
|
assert.equal(iconMonogram('9anime'), '9');
|
|
assert.equal(iconMonogram('アニメ'), 'ア');
|
|
});
|
|
|
|
test('iconMonogram falls back to a placeholder for a nameless row', () => {
|
|
assert.equal(iconMonogram(''), '?');
|
|
assert.equal(iconMonogram('---'), '?');
|
|
});
|