feat: implement build script and parsers to automate Foundry VTT journal pack generation from Obsidian markdown files
This commit is contained in:
+12
-12
@@ -1,25 +1,25 @@
|
|||||||
# Changelog — hbm-rpg-v3-lore
|
# Changelog - hbm-rpg-v3-lore
|
||||||
|
|
||||||
All notable changes to the **HbM RPG v3 — Lore** Foundry VTT module.
|
All notable changes to the **HbM RPG v3 - Lore** Foundry VTT module.
|
||||||
|
|
||||||
## [1.1.0] — 2026-04-30
|
## [1.1.0] - 2026-04-30
|
||||||
|
|
||||||
Version bump to track the companion system release. No content changes.
|
Version bump to track the companion system release. No content changes.
|
||||||
|
|
||||||
## [1.0.0] — 2026-04-29
|
## [1.0.0] - 2026-04-29
|
||||||
|
|
||||||
First production release.
|
First production release.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- 7 `JournalEntry` compendia generated from `_books/*.md` (36 entries total):
|
- 7 `JournalEntry` compendia generated from `_books/*.md` (36 entries total):
|
||||||
- `core-rules-lore` — Podręcznik Gry (5)
|
- `core-rules-lore` - Podręcznik Gry (5)
|
||||||
- `magic-book-lore` — Księga Magii (7)
|
- `magic-book-lore` - Księga Magii (7)
|
||||||
- `bestiary-lore` — Bestiariusz (1)
|
- `bestiary-lore` - Bestiariusz (1)
|
||||||
- `blood-magic-history` — Arcanum Sanguinis (4)
|
- `blood-magic-history` - Arcanum Sanguinis (4)
|
||||||
- `crimson-cult` — Chwała Szkarłatnemu Kultowi (5)
|
- `crimson-cult` - Chwała Szkarłatnemu Kultowi (5)
|
||||||
- `abyss` — Klątwa Otchłani (5)
|
- `abyss` - Klątwa Otchłani (5)
|
||||||
- `economy` — Złoto, Stal i Magia (9)
|
- `economy` - Złoto, Stal i Magia (9)
|
||||||
- Build pipeline: `scripts/parsers/journal-parser.ts` walks
|
- Build pipeline: `scripts/parsers/journal-parser.ts` walks
|
||||||
`Rozdział [IVX]+ [:.\-] Title`, deduplicates TOC vs. body, splits chapters by
|
`Rozdział [IVX]+ [:.\-] Title`, deduplicates TOC vs. body, splits chapters by
|
||||||
`____` separators into pages, converts markdown → HTML
|
`____` separators into pages, converts markdown → HTML
|
||||||
@@ -33,7 +33,7 @@ First production release.
|
|||||||
### Deferred
|
### Deferred
|
||||||
|
|
||||||
- Przewodnik Ludzkości po Magicznym Świecie packs (`world-overview`, `deities`,
|
- Przewodnik Ludzkości po Magicznym Świecie packs (`world-overview`, `deities`,
|
||||||
`universe`, `sol3-society`, `afterlife`, `documents`) — book not yet in
|
`universe`, `sol3-society`, `afterlife`, `documents`) - book not yet in
|
||||||
`_books/`. Will land in v1.1.0.
|
`_books/`. Will land in v1.1.0.
|
||||||
- Automatic UUID cross-link injection (parser emits `lore-link` placeholders
|
- Automatic UUID cross-link injection (parser emits `lore-link` placeholders
|
||||||
ready for a follow-up rewrite pass).
|
ready for a follow-up rewrite pass).
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# HbM RPG v3 — Lore (Foundry VTT module)
|
# HbM RPG v3 - Lore (Foundry VTT module)
|
||||||
|
|
||||||
Companion lore module for the [HbM RPG v3 system](https://github.com/iwo-strzebonski/hbm-foundry-system). Ships JournalEntry compendia for setting, history, and narrative chapters from the official books.
|
Companion lore module for the [HbM RPG v3 system](https://github.com/iwo-strzebonski/hbm-foundry-system). Ships JournalEntry compendia for setting, history, and narrative chapters from the official books.
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"HBM_LORE": {
|
"HBM_LORE": {
|
||||||
"module": { "name": "Homebrew Magic: RPG v3 — Lore" }
|
"module": {
|
||||||
|
"name": "Homebrew Magic: RPG v3 - Lore"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"HBM_LORE": {
|
"HBM_LORE": {
|
||||||
"module": { "name": "Homebrew Magic: RPG v3 — Lore" }
|
"module": {
|
||||||
|
"name": "Homebrew Magic: RPG v3 - Lore"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+9
-9
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"id": "hbm-rpg-v3-lore",
|
"id": "hbm-rpg-v3-lore",
|
||||||
"title": "Homebrew Magic: RPG v3 — Lore",
|
"title": "Homebrew Magic: RPG v3 - Lore",
|
||||||
"description": "Companion lore module for the HbM RPG v3 system. Provides journal entries for setting, deities, history, and narrative chapters from the official books.",
|
"description": "Companion lore module for the HbM RPG v3 system. Provides journal entries for setting, deities, history, and narrative chapters from the official books.",
|
||||||
"version": "1.3.4",
|
"version": "1.3.6",
|
||||||
"manifest": "https://vtt-content.octoturge.com/packages/module/hbm-rpg-v3-lore.json",
|
"manifest": "https://vtt-content.octoturge.com/packages/module/hbm-rpg-v3-lore.json",
|
||||||
"download": "https://vtt-content.octoturge.com/packages/module/hbm-rpg-v3-lore-v1.3.4.zip",
|
"download": "https://vtt-content.octoturge.com/packages/module/hbm-rpg-v3-lore-v1.3.6.zip",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "14"
|
"verified": "14"
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "blood-magic-history",
|
"name": "blood-magic-history",
|
||||||
"label": "Magia Krwi — Historia",
|
"label": "Magia Krwi - Historia",
|
||||||
"path": "packs/blood-magic-history",
|
"path": "packs/blood-magic-history",
|
||||||
"type": "JournalEntry",
|
"type": "JournalEntry",
|
||||||
"ownership": {
|
"ownership": {
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "magic-book-lore",
|
"name": "magic-book-lore",
|
||||||
"label": "Księga Magii — Wprowadzenia",
|
"label": "Księga Magii - Wprowadzenia",
|
||||||
"path": "packs/magic-book-lore",
|
"path": "packs/magic-book-lore",
|
||||||
"type": "JournalEntry",
|
"type": "JournalEntry",
|
||||||
"ownership": {
|
"ownership": {
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "core-rules-lore",
|
"name": "core-rules-lore",
|
||||||
"label": "Podręcznik Gry — Wprowadzenia",
|
"label": "Podręcznik Gry - Wprowadzenia",
|
||||||
"path": "packs/core-rules-lore",
|
"path": "packs/core-rules-lore",
|
||||||
"type": "JournalEntry",
|
"type": "JournalEntry",
|
||||||
"ownership": {
|
"ownership": {
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bestiary-lore",
|
"name": "bestiary-lore",
|
||||||
"label": "Bestiariusz — Lore",
|
"label": "Bestiariusz - Lore",
|
||||||
"path": "packs/bestiary-lore",
|
"path": "packs/bestiary-lore",
|
||||||
"type": "JournalEntry",
|
"type": "JournalEntry",
|
||||||
"ownership": {
|
"ownership": {
|
||||||
@@ -320,7 +320,7 @@
|
|||||||
],
|
],
|
||||||
"packFolders": [
|
"packFolders": [
|
||||||
{
|
{
|
||||||
"name": "Lore — HbM RPG v3",
|
"name": "Lore - HbM RPG v3",
|
||||||
"sorting": "a",
|
"sorting": "a",
|
||||||
"packs": [
|
"packs": [
|
||||||
"core-rules-lore",
|
"core-rules-lore",
|
||||||
@@ -334,7 +334,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Świat — HbM RPG v3",
|
"name": "Świat - HbM RPG v3",
|
||||||
"sorting": "a",
|
"sorting": "a",
|
||||||
"packs": [
|
"packs": [
|
||||||
"disciplines-lore",
|
"disciplines-lore",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hbm-rpg-v3-lore",
|
"name": "hbm-rpg-v3-lore",
|
||||||
"version": "1.3.4",
|
"version": "1.3.6",
|
||||||
"description": "Foundry VTT lore companion module for Homebrew Magic: RPG v3.",
|
"description": "Foundry VTT lore companion module for Homebrew Magic: RPG v3.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ const PACK_CONFIGS: PackConfig[] = [
|
|||||||
sources: [
|
sources: [
|
||||||
// Pure lore narrative.
|
// Pure lore narrative.
|
||||||
{ path: 'ObsidianNotes/lore/02. Otchłań i Magia.md' },
|
{ path: 'ObsidianNotes/lore/02. Otchłań i Magia.md' },
|
||||||
// Rules intro (Wstęp only — mechanics chapters are skipped).
|
// Rules intro (Wstęp only - mechanics chapters are skipped).
|
||||||
{ path: 'ObsidianNotes/rules/02. Klątwa Otchłani.md', prefaceTitle: 'Wstęp' },
|
{ path: 'ObsidianNotes/rules/02. Klątwa Otchłani.md', prefaceTitle: 'Wstęp' },
|
||||||
],
|
],
|
||||||
skip: /^(Rozdział II - Talenty|Rozdział III - Dary|Rozdział IV - Choroby|Rozdział V - Zaklęcia|Rozdział X - Artefakty)/i,
|
skip: /^(Rozdział II - Talenty|Rozdział III - Dary|Rozdział IV - Choroby|Rozdział V - Zaklęcia|Rozdział X - Artefakty)/i,
|
||||||
@@ -238,7 +238,7 @@ for (const pack of byPack.keys()) {
|
|||||||
console.log(` ✓ compiled ${pack}`);
|
console.log(` ✓ compiled ${pack}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[lore] done — ${byPack.size} packs in packs/`);
|
console.log(`[lore] done - ${byPack.size} packs in packs/`);
|
||||||
|
|
||||||
function toFoundryJournal(doc: JournalDoc, sort: number): Record<string, unknown> {
|
function toFoundryJournal(doc: JournalDoc, sort: number): Record<string, unknown> {
|
||||||
const fId = makeFoundryId(doc.id);
|
const fId = makeFoundryId(doc.id);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* `@UUID[Compendium.<pkg>.<pack>...]` patterns, and reports any reference
|
* `@UUID[Compendium.<pkg>.<pack>...]` patterns, and reports any reference
|
||||||
* to a system pack we know about but a slug that does not exist.
|
* to a system pack we know about but a slug that does not exist.
|
||||||
*
|
*
|
||||||
* Currently informational only — the journal parser does not yet emit
|
* Currently informational only - the journal parser does not yet emit
|
||||||
* UUID cross-links automatically. This script provides the framework
|
* UUID cross-links automatically. This script provides the framework
|
||||||
* for Phase 7.3/7.4 integration.
|
* for Phase 7.3/7.4 integration.
|
||||||
*/
|
*/
|
||||||
@@ -45,7 +45,7 @@ function scanFile(file: string) {
|
|||||||
try {
|
try {
|
||||||
walk(packsSrcDir);
|
walk(packsSrcDir);
|
||||||
} catch {
|
} catch {
|
||||||
console.log('[lint-uuid] no packs-src/ — run build:packs first.');
|
console.log('[lint-uuid] no packs-src/ - run build:packs first.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* A. Legacy Google-Docs export (`_books/`):
|
* A. Legacy Google-Docs export (`_books/`):
|
||||||
* - No frontmatter.
|
* - No frontmatter.
|
||||||
* - TOC is a plain-text block that reuses the same `Rozdział X — Title`
|
* - TOC is a plain-text block that reuses the same `Rozdział X - Title`
|
||||||
* headings. The parser deduplicates: the SECOND occurrence of each
|
* headings. The parser deduplicates: the SECOND occurrence of each
|
||||||
* heading is the real body.
|
* heading is the real body.
|
||||||
*
|
*
|
||||||
@@ -33,7 +33,7 @@ export interface JournalDoc {
|
|||||||
pack: string;
|
pack: string;
|
||||||
/** Source provenance for traceability. */
|
/** Source provenance for traceability. */
|
||||||
source: { book: string; chapter: string; line: number };
|
source: { book: string; chapter: string; line: number };
|
||||||
/** Pages — each becomes a `JournalEntryPage`. */
|
/** Pages - each becomes a `JournalEntryPage`. */
|
||||||
pages: JournalPage[];
|
pages: JournalPage[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,10 +66,10 @@ export interface JournalParseConfig {
|
|||||||
|
|
||||||
// Matches both plain-text (`Rozdział IV - Title`) and heading-prefixed
|
// Matches both plain-text (`Rozdział IV - Title`) and heading-prefixed
|
||||||
// (`## Rozdział IV - Title`) chapter lines. Optional trailing page number.
|
// (`## Rozdział IV - Title`) chapter lines. Optional trailing page number.
|
||||||
const CHAPTER_RE = /^(?:#{1,6}\s+)?Rozdzia[łl]\s+([IVXLC]+)\s*[:.—\-–]\s*(.+?)(?:\s+\d+)?$/;
|
const CHAPTER_RE = /^(?:#{1,6}\s+)?Rozdzia[łl]\s+([IVXLC]+)\s*[:.\-–]\s*(.+?)(?:\s+\d+)?$/;
|
||||||
const SEPARATOR = /^_{3,}$/;
|
const SEPARATOR = /^_{3,}$/;
|
||||||
const FRONTMATTER_FENCE = /^---\s*$/;
|
const FRONTMATTER_FENCE = /^---\s*$/;
|
||||||
// Obsidian TOC bullets: `- [[#Anchor|Label]]` — skip in body content too
|
// Obsidian TOC bullets: `- [[#Anchor|Label]]` - skip in body content too
|
||||||
const OBSIDIAN_TOC_BULLET = /^[-*]\s+\[\[#/;
|
const OBSIDIAN_TOC_BULLET = /^[-*]\s+\[\[#/;
|
||||||
|
|
||||||
/** Returns the first non-frontmatter line index (skips `--- ... ---` block). */
|
/** Returns the first non-frontmatter line index (skips `--- ... ---` block). */
|
||||||
@@ -94,7 +94,7 @@ export function parseJournalBook(cfg: JournalParseConfig): JournalDoc[] {
|
|||||||
if (m) occurrences.push({ idx: i, roman: m[1], title: m[2].trim(), raw: lines[i].trim() });
|
if (m) occurrences.push({ idx: i, roman: m[1], title: m[2].trim(), raw: lines[i].trim() });
|
||||||
}
|
}
|
||||||
if (occurrences.length === 0) {
|
if (occurrences.length === 0) {
|
||||||
// No chapters found — if there's a prefaceTitle, still try to emit preface.
|
// No chapters found - if there's a prefaceTitle, still try to emit preface.
|
||||||
if (cfg.prefaceTitle) {
|
if (cfg.prefaceTitle) {
|
||||||
const pages = bodyToPages(lines);
|
const pages = bodyToPages(lines);
|
||||||
if (pages.length > 0) {
|
if (pages.length > 0) {
|
||||||
@@ -117,7 +117,7 @@ export function parseJournalBook(cfg: JournalParseConfig): JournalDoc[] {
|
|||||||
}
|
}
|
||||||
bodyChapters.push(occ);
|
bodyChapters.push(occ);
|
||||||
}
|
}
|
||||||
// If no duplicates were found (no plain-text TOC — typical of native files),
|
// If no duplicates were found (no plain-text TOC - typical of native files),
|
||||||
// treat the entire list as body chapters.
|
// treat the entire list as body chapters.
|
||||||
const chapters = bodyChapters.length > 0 ? bodyChapters : occurrences;
|
const chapters = bodyChapters.length > 0 ? bodyChapters : occurrences;
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ export function parseJournalBook(cfg: JournalParseConfig): JournalDoc[] {
|
|||||||
const slug = slugify(`${ch.roman}-${ch.title}`);
|
const slug = slugify(`${ch.roman}-${ch.title}`);
|
||||||
docs.push({
|
docs.push({
|
||||||
id: `${cfg.pack}-${slug}`,
|
id: `${cfg.pack}-${slug}`,
|
||||||
name: `Rozdział ${ch.roman} — ${ch.title}`,
|
name: `Rozdział ${ch.roman} - ${ch.title}`,
|
||||||
pack: cfg.pack,
|
pack: cfg.pack,
|
||||||
source: { book: cfg.sourceBook, chapter: ch.title, line: startIdx + ch.idx + 1 },
|
source: { book: cfg.sourceBook, chapter: ch.title, line: startIdx + ch.idx + 1 },
|
||||||
pages,
|
pages,
|
||||||
|
|||||||
Reference in New Issue
Block a user