Step 1/17 of ultraplan-2026-04-17-jetbrains-ide-scan. - Populate top-jetbrains-plugins.json with 56 canonical xmlIds (bundled + popular third-party): com.intellij.java, org.jetbrains.kotlin, com.jetbrains.python.community, org.rust.lang, com.github.copilot, mobi.hsz.idea.gitignore, the legitimate-typo 'Lombook Plugin', etc. - Add loadJetBrainsBlocklist() export mirroring loadVSCodeBlocklist shape. Blocklist is empty by design — no public confirmed-malicious JetBrains Marketplace plugins as of 2026-04-17. - Add tests/scanners/ide-extension-data.test.mjs (9 tests, all pass). - Fix cache bug in loadTopJetBrains: map normalizeId on cache-hit path too (was previously unnormalized on second call). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
100 lines
2.9 KiB
JavaScript
100 lines
2.9 KiB
JavaScript
// ide-extension-data.test.mjs — Unit tests for knowledge-file loaders.
|
|
//
|
|
// Verifies loadTopJetBrains, loadJetBrainsBlocklist behavior + cache
|
|
// discipline shared with VS Code loaders.
|
|
|
|
import { describe, it, beforeEach } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
loadTopJetBrains,
|
|
loadJetBrainsBlocklist,
|
|
loadTopVSCode,
|
|
loadVSCodeBlocklist,
|
|
normalizeId,
|
|
_resetCache,
|
|
} from '../../scanners/lib/ide-extension-data.mjs';
|
|
|
|
describe('loadTopJetBrains', () => {
|
|
beforeEach(() => _resetCache());
|
|
|
|
it('returns >= 40 canonical xmlIds', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
assert.ok(Array.isArray(ids));
|
|
assert.ok(
|
|
ids.length >= 40,
|
|
`expected >= 40 entries, got ${ids.length}`,
|
|
);
|
|
});
|
|
|
|
it('returns lowercased trimmed entries (normalizeId applied)', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
for (const id of ids) {
|
|
assert.equal(id, id.toLowerCase(), `not lowercased: ${id}`);
|
|
assert.equal(id, id.trim(), `not trimmed: ${id}`);
|
|
assert.notEqual(id, '', 'empty entry found');
|
|
}
|
|
});
|
|
|
|
it('includes bundled JetBrains xmlIds', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
assert.ok(
|
|
ids.includes('com.intellij.java'),
|
|
'missing com.intellij.java',
|
|
);
|
|
assert.ok(
|
|
ids.includes('org.jetbrains.kotlin'),
|
|
'missing org.jetbrains.kotlin',
|
|
);
|
|
});
|
|
|
|
it('includes the legitimate-typo "lombook plugin" xmlId', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
assert.ok(
|
|
ids.includes('lombook plugin'),
|
|
'missing "lombook plugin" — canonical xmlId for Lombok integration',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('loadJetBrainsBlocklist', () => {
|
|
beforeEach(() => _resetCache());
|
|
|
|
it('returns an empty array (empty by design)', async () => {
|
|
const bl = await loadJetBrainsBlocklist();
|
|
assert.ok(Array.isArray(bl));
|
|
assert.equal(
|
|
bl.length,
|
|
0,
|
|
'blocklist should be empty by design in v6.6.0',
|
|
);
|
|
});
|
|
|
|
it('does not throw on repeated invocation', async () => {
|
|
await assert.doesNotReject(() => loadJetBrainsBlocklist());
|
|
await assert.doesNotReject(() => loadJetBrainsBlocklist());
|
|
});
|
|
});
|
|
|
|
describe('cache sanity', () => {
|
|
beforeEach(() => _resetCache());
|
|
|
|
it('calling loadTopJetBrains then loadJetBrainsBlocklist does not throw', async () => {
|
|
const ids = await loadTopJetBrains();
|
|
const bl = await loadJetBrainsBlocklist();
|
|
assert.ok(Array.isArray(ids) && ids.length > 0);
|
|
assert.ok(Array.isArray(bl));
|
|
});
|
|
|
|
it('second loadTopJetBrains call returns same data (cache hit)', async () => {
|
|
const a = await loadTopJetBrains();
|
|
const b = await loadTopJetBrains();
|
|
assert.deepEqual(a, b);
|
|
});
|
|
|
|
it('VS Code loaders still work alongside JetBrains loaders', async () => {
|
|
const jb = await loadTopJetBrains();
|
|
const vs = await loadTopVSCode();
|
|
assert.ok(jb.length >= 40);
|
|
assert.ok(Array.isArray(vs));
|
|
});
|
|
});
|