Fix PF2e actions: dedupe junk, show action cost, add cost filter
The AoN action index was polluted with ~2,300 trait-fragment entries
('(concentrate)', 'envision', 'command'...) and the same basic actions repeated
per source. Filter to real Title-cased names and dedupe by name (keep richest):
3,950 -> 646 real actions (also cleaned in the live data file, 3.9M -> 859K).
- pf2eMeta now shows action cost (Single Action/Reaction/...) instead of 'common'
- Added an Action cost filter to the Actions category
- Hide noisy 'common' rarity in PF2e detail facts
- Scraper postProcess() makes future fetches clean too
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
+25
-1
@@ -95,12 +95,36 @@ function normalize(src: Record<string, unknown>): Record<string, unknown> {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AoN `action` index is polluted with action-trait fragments (names like
|
||||||
|
* "(concentrate)", "envision", "command") and the same basic actions repeated
|
||||||
|
* once per source. Keep only real Title-Cased action names and dedupe by name,
|
||||||
|
* preferring the entry with the most complete text.
|
||||||
|
*/
|
||||||
|
function isRealAction(x: Record<string, unknown>): boolean {
|
||||||
|
const n = String(x.name ?? '').trim();
|
||||||
|
return n !== '' && /^[A-Z0-9"]/.test(n) && !n.startsWith('(');
|
||||||
|
}
|
||||||
|
function dedupeByName(list: Record<string, unknown>[]): Record<string, unknown>[] {
|
||||||
|
const best = new Map<string, Record<string, unknown>>();
|
||||||
|
for (const x of list) {
|
||||||
|
const k = String(x.name);
|
||||||
|
const cur = best.get(k);
|
||||||
|
if (!cur || String(x.text ?? '').length > String(cur.text ?? '').length) best.set(k, x);
|
||||||
|
}
|
||||||
|
return [...best.values()].sort((a, b) => String(a.name).localeCompare(String(b.name)));
|
||||||
|
}
|
||||||
|
function postProcess(category: string, list: Record<string, unknown>[]): Record<string, unknown>[] {
|
||||||
|
if (category === 'action') return dedupeByName(list.filter(isRealAction));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
await mkdir(OUT_DIR, { recursive: true });
|
await mkdir(OUT_DIR, { recursive: true });
|
||||||
const index: { category: string; file: string; count: number }[] = [];
|
const index: { category: string; file: string; count: number }[] = [];
|
||||||
|
|
||||||
for (const [category, file] of Object.entries(CATEGORIES)) {
|
for (const [category, file] of Object.entries(CATEGORIES)) {
|
||||||
const entries = await fetchCategory(category);
|
const entries = postProcess(category, await fetchCategory(category));
|
||||||
const path = join(OUT_DIR, `${file}.json`);
|
const path = join(OUT_DIR, `${file}.json`);
|
||||||
await writeFile(path, JSON.stringify(entries));
|
await writeFile(path, JSON.stringify(entries));
|
||||||
index.push({ category, file, count: entries.length });
|
index.push({ category, file, count: entries.length });
|
||||||
|
|||||||
@@ -132,7 +132,9 @@ export function Pf2eDetail({ entry }: { entry: CompendiumEntry }) {
|
|||||||
['Damage', entry.damage],
|
['Damage', entry.damage],
|
||||||
['Source', entry.source],
|
['Source', entry.source],
|
||||||
];
|
];
|
||||||
const shown = facts.filter(([, v]) => v !== undefined && v !== null && v !== '');
|
const shown = facts.filter(
|
||||||
|
([k, v]) => v !== undefined && v !== null && v !== '' && !(k === 'Rarity' && v === 'common'),
|
||||||
|
);
|
||||||
const text = (entry.text as string | undefined) ?? (entry.summary as string | undefined) ?? '';
|
const text = (entry.text as string | undefined) ?? (entry.summary as string | undefined) ?? '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -110,10 +110,20 @@ const levelMax = (): FilterDef => ({
|
|||||||
|
|
||||||
function pf2eMeta(e: Entry): string {
|
function pf2eMeta(e: Entry): string {
|
||||||
if (typeof e.level === 'number') return `Lvl ${e.level}`;
|
if (typeof e.level === 'number') return `Lvl ${e.level}`;
|
||||||
if (e.rarity) return String(e.rarity);
|
// action cost is the meaningful label for actions/activities
|
||||||
return '';
|
if (e.actions) return String(e.actions);
|
||||||
|
const rarity = e.rarity ? String(e.rarity) : '';
|
||||||
|
return rarity && rarity !== 'common' ? rarity : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const actionCostFilter = (): FilterDef => ({
|
||||||
|
key: 'actions',
|
||||||
|
label: 'Action cost',
|
||||||
|
kind: 'eq',
|
||||||
|
get: (e) => e.actions as string | undefined,
|
||||||
|
options: (d) => distinctStrings(d, (e) => e.actions),
|
||||||
|
});
|
||||||
|
|
||||||
function pf2eCategory(id: string, label: string, file: string, opts: { level?: boolean; linkAs?: 'spell' | 'item' } = {}): CategoryDef {
|
function pf2eCategory(id: string, label: string, file: string, opts: { level?: boolean; linkAs?: 'spell' | 'item' } = {}): CategoryDef {
|
||||||
const filters: FilterDef[] = [traitFilter(), rarityFilter()];
|
const filters: FilterDef[] = [traitFilter(), rarityFilter()];
|
||||||
if (opts.level !== false) filters.unshift(levelMin(), levelMax());
|
if (opts.level !== false) filters.unshift(levelMin(), levelMax());
|
||||||
@@ -229,7 +239,10 @@ export const CATEGORIES: CategoryDef[] = [
|
|||||||
pf2eCategory('heritages', 'Heritages', 'heritages', { level: false }),
|
pf2eCategory('heritages', 'Heritages', 'heritages', { level: false }),
|
||||||
pf2eCategory('backgrounds', 'Backgrounds', 'backgrounds', { level: false }),
|
pf2eCategory('backgrounds', 'Backgrounds', 'backgrounds', { level: false }),
|
||||||
pf2eCategory('archetypes', 'Archetypes', 'archetypes', { level: false }),
|
pf2eCategory('archetypes', 'Archetypes', 'archetypes', { level: false }),
|
||||||
pf2eCategory('actions', 'Actions', 'actions', { level: false }),
|
{
|
||||||
|
...pf2eCategory('actions', 'Actions', 'actions', { level: false }),
|
||||||
|
filters: [actionCostFilter(), traitFilter()],
|
||||||
|
},
|
||||||
pf2eCategory('conditions', 'Conditions', 'conditions', { level: false }),
|
pf2eCategory('conditions', 'Conditions', 'conditions', { level: false }),
|
||||||
pf2eCategory('deities', 'Deities', 'deities', { level: false }),
|
pf2eCategory('deities', 'Deities', 'deities', { level: false }),
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user