@heroiclands/package-build 22.5.0 → 22.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/CONTENT.md +11 -5
- package/docs/api.md +10 -9
- package/docs/content-format.md +34 -9
- package/engine/content-index.mjs +21 -12
- package/engine/foundry-entries.mjs +32 -16
- package/engine/journals.mjs +13 -5
- package/engine/note-state.mjs +29 -0
- package/package.json +1 -1
- package/types/engine/content-index.d.mts +4 -3
- package/types/engine/note-state.d.mts +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 22.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
**Unwritten notes**
|
|
8
|
+
|
|
9
|
+
- A note left unwritten builds: an empty body no longer stops a package
|
|
10
|
+
compiling its packs.
|
|
11
|
+
- An unwritten note offers no compendium link, so nothing sends a reader to a
|
|
12
|
+
journal that was never made.
|
|
13
|
+
|
|
3
14
|
## 22.5.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/CONTENT.md
CHANGED
|
@@ -1096,11 +1096,17 @@ was never the key count.)
|
|
|
1096
1096
|
### An empty body is a stub, on purpose
|
|
1097
1097
|
|
|
1098
1098
|
A note whose body is empty is a **stub**: it carries its frontmatter into the
|
|
1099
|
-
content index and is queryable there, it keeps its `id
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1099
|
+
content index and is queryable there, it keeps its `id`, and it publishes no
|
|
1100
|
+
page, no address and no link target. A note with a body and the `draft` tag is a
|
|
1101
|
+
**draft**, and one with a body and no tag is **full**.
|
|
1102
|
+
`docs/content-format.md` states the rule; this is what the lint does with it.
|
|
1103
|
+
|
|
1104
|
+
**A document that would be empty is not created**, and the index then names no
|
|
1105
|
+
artefact — `uuid`, `path` and `address` are `null`. An unwritten note still
|
|
1106
|
+
compiles every document derived from `data:`, so an arcane talent is still its
|
|
1107
|
+
Item; what it compiles no journal for is its prose, because there is none. An
|
|
1108
|
+
infobox does not count as content: the panel renders `data:` the index already
|
|
1109
|
+
carries.
|
|
1104
1110
|
|
|
1105
1111
|
Four findings and two reports:
|
|
1106
1112
|
|
package/docs/api.md
CHANGED
|
@@ -416,15 +416,16 @@ Drawing a declared infobox: HTML for a Foundry Journal Page, Typst for the book.
|
|
|
416
416
|
|
|
417
417
|
The three states of a note — **stub**, **draft**, **full** — and the one observable fact they rest on. A note whose body is empty is a stub: it carries its facts into the index and is queryable there, and it has no page, no address and no link target. Nothing is stored: the ladder is derived once in the SQL `entries` view and no note can assert its own state.
|
|
418
418
|
|
|
419
|
-
| Export | Signature | Returns | Use it when
|
|
420
|
-
| --------------------- | ------------------------------------------- | --------------------------------------- |
|
|
421
|
-
| `NOTE_STATES` | `const NOTE_STATES` | `ReadonlyArray<string>` | naming the three states in ladder order
|
|
422
|
-
| `isEmptyBody` | `isEmptyBody(body)` | `boolean` | asking the exact question: is everything after the closing frontmatter fence whitespace?
|
|
423
|
-
| `isStubbableType` | `isStubbableType(type, vocabulary)` | `boolean` | asking whether an empty body suppresses this type's page; `folder` and `homepage` are structural and exempt
|
|
424
|
-
| `isStubNote` | `isStubNote(frontmatter, body, vocabulary)` | `boolean` | deciding whether one note is a stub, which is what the index and the site build both ask
|
|
425
|
-
| `
|
|
426
|
-
| `
|
|
427
|
-
| `
|
|
419
|
+
| Export | Signature | Returns | Use it when |
|
|
420
|
+
| --------------------- | ------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
421
|
+
| `NOTE_STATES` | `const NOTE_STATES` | `ReadonlyArray<string>` | naming the three states in ladder order |
|
|
422
|
+
| `isEmptyBody` | `isEmptyBody(body)` | `boolean` | asking the exact question: is everything after the closing frontmatter fence whitespace? |
|
|
423
|
+
| `isStubbableType` | `isStubbableType(type, vocabulary)` | `boolean` | asking whether an empty body suppresses this type's page; `folder` and `homepage` are structural and exempt |
|
|
424
|
+
| `isStubNote` | `isStubNote(frontmatter, body, vocabulary)` | `boolean` | deciding whether one note is a stub, which is what the index and the site build both ask |
|
|
425
|
+
| `journalHasContent` | `journalHasContent(body)` | `boolean` | asking whether the JournalEntry a body compiles into would hold anything, which is what decides whether one is made at all |
|
|
426
|
+
| `PLACEHOLDER_PHRASES` | `const PLACEHOLDER_PHRASES` | `ReadonlyArray<string>` | reading the phrases that stand in for prose nobody has written |
|
|
427
|
+
| `placeholderBody` | `placeholderBody(body)` | `Array<{phrase: string, line: number}>` | finding a body that reduces to nothing but placeholders, which is an abandoned draft rather than a stub |
|
|
428
|
+
| `bodyWordCount` | `bodyWordCount(body)` | `number` | counting the prose a reader meets, with a wikilink counting as the one word it renders |
|
|
428
429
|
|
|
429
430
|
### `engine.stubLint`
|
|
430
431
|
|
package/docs/content-format.md
CHANGED
|
@@ -1662,11 +1662,11 @@ convention rather than declared in a field — see
|
|
|
1662
1662
|
A note has three states, and two of them are nothing but conventions the format
|
|
1663
1663
|
already carried.
|
|
1664
1664
|
|
|
1665
|
-
| State | Body | Marker | Page | Document
|
|
1666
|
-
| --------- | ------- | --------------- | ----------- |
|
|
1667
|
-
| **stub** | empty | none | no | yes, where
|
|
1668
|
-
| **draft** | written | `tags: [draft]` | yes, marked | yes
|
|
1669
|
-
| **full** | written | none | yes | yes
|
|
1665
|
+
| State | Body | Marker | Page | Document | Link target |
|
|
1666
|
+
| --------- | ------- | --------------- | ----------- | --------------------------------- | ----------- |
|
|
1667
|
+
| **stub** | empty | none | no | yes, where one would not be empty | no |
|
|
1668
|
+
| **draft** | written | `tags: [draft]` | yes, marked | yes | yes |
|
|
1669
|
+
| **full** | written | none | yes | yes | yes |
|
|
1670
1670
|
|
|
1671
1671
|
**Full is the absence of everything.** It is the default and carries no marker,
|
|
1672
1672
|
which is right: the overwhelming majority of a finished corpus should say
|
|
@@ -1706,10 +1706,35 @@ column a table renderer already reads.
|
|
|
1706
1706
|
It keeps everything else:
|
|
1707
1707
|
|
|
1708
1708
|
- **`file`**, which is what you edit and what every diagnostic names.
|
|
1709
|
-
- **`id
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1709
|
+
- **`id`**, which is the identity every diagnostic and every table reads.
|
|
1710
|
+
- **`foundry`**, naming each document that was made.
|
|
1711
|
+
|
|
1712
|
+
#### A document that would be empty is not created
|
|
1713
|
+
|
|
1714
|
+
> **If the resulting document would be empty, it is not created** — and the
|
|
1715
|
+
> index then names no artefact: `uuid`, `path` and `address` are `null`, which
|
|
1716
|
+
> is how a record says one was not made.
|
|
1717
|
+
|
|
1718
|
+
The test is about the **output**, which is what lets one rule cover every case:
|
|
1719
|
+
|
|
1720
|
+
| The note | The document | Made? |
|
|
1721
|
+
| ---------------------------------- | -------------------------------------- | ----- |
|
|
1722
|
+
| `place`, `lore`, `doc`, `scenario` | its JournalEntry, which _is_ the prose | no |
|
|
1723
|
+
| any item type, `macro` | the Item or Macro, from `data:` | yes |
|
|
1724
|
+
| the same note's documentation | a JournalEntry of the same prose | no |
|
|
1725
|
+
| `map` | the Scene, from `data:` | yes |
|
|
1726
|
+
|
|
1727
|
+
An unwritten arcane talent still compiles into its Item, because an Item is its
|
|
1728
|
+
`data:` and that is not empty. What it has no documentation journal for is the
|
|
1729
|
+
same thing an unwritten `place` has no journal for: there is nothing to put in
|
|
1730
|
+
one.
|
|
1731
|
+
|
|
1732
|
+
**An infobox does not count as content.** The panel is a rendering of `data:`
|
|
1733
|
+
that the index already publishes, so an entry holding nothing else would tell a
|
|
1734
|
+
reader exactly what the record told them.
|
|
1735
|
+
|
|
1736
|
+
Nothing anywhere names a document that was not made: a compendium UUID for one
|
|
1737
|
+
would send every consumer that resolves it to a document the pack does not hold.
|
|
1713
1738
|
|
|
1714
1739
|
What is suppressed with the page is the web address and the link target: a
|
|
1715
1740
|
wikilink into a stub is refused, and a table cell listing one prints its name as
|
package/engine/content-index.mjs
CHANGED
|
@@ -422,9 +422,10 @@ function assertNoDerivedKeys(frontmatter, relPath, absPath, contentPackage) {
|
|
|
422
422
|
* @returns {Record<string, any>} The record, keys sorted at every depth. A
|
|
423
423
|
* **stub** — a note with an empty body, on a type an empty body suppresses —
|
|
424
424
|
* carries `address` and `anchors` as `null`: it publishes no page, so it
|
|
425
|
-
* holds no address and offers no anchor. It keeps
|
|
426
|
-
*
|
|
427
|
-
* derived from `data
|
|
425
|
+
* holds no address and offers no anchor. It keeps its `id`, and a `foundry`
|
|
426
|
+
* block naming every document that was made — which is every document
|
|
427
|
+
* derived from `data:`, and no journal, because a journal of an empty body
|
|
428
|
+
* would be empty and is not created.
|
|
428
429
|
* @throws {Error} When the note carries a key this module derives, which would
|
|
429
430
|
* otherwise be overwritten without a word. `file` and, where the file was
|
|
430
431
|
* read, `position` ride on the error.
|
|
@@ -443,16 +444,18 @@ export function buildIndexRecord({
|
|
|
443
444
|
const posix = relPath.split(path.sep).join("/");
|
|
444
445
|
const folder = posix.includes("/") ? posix.slice(0, posix.lastIndexOf("/")) : "";
|
|
445
446
|
const address = noteAddress(frontmatter, contentPackage);
|
|
446
|
-
// Derived from the address the note *would* hold, because a stub
|
|
447
|
-
//
|
|
448
|
-
//
|
|
447
|
+
// Derived from the address the note *would* hold, because a stub still
|
|
448
|
+
// compiles every document derived from `data:` — an unwritten arcane talent
|
|
449
|
+
// is its Item. The one document it has none of is the one that would be
|
|
450
|
+
// empty, and `entriesForNote` withholds that UUID, so this block names
|
|
451
|
+
// nothing that was not made.
|
|
449
452
|
const entries = foundryEntries({ frontmatter, address, body, manifest });
|
|
450
453
|
// A stub — an empty body on a type an empty body suppresses — publishes no
|
|
451
454
|
// page, so it holds no address and offers no anchor to link to. **The
|
|
452
455
|
// absent address is the signal**, and it is the column the table renderer
|
|
453
456
|
// already reads through `_ref`. Everything else the note declares is kept:
|
|
454
457
|
// its file is what the author edits and what every diagnostic names, and
|
|
455
|
-
// its `id`
|
|
458
|
+
// its `id` is the identity every diagnostic and every table reads.
|
|
456
459
|
const stub = isStubNote(frontmatter, body);
|
|
457
460
|
|
|
458
461
|
return /** @type {Record<string, any>} */ (
|
|
@@ -530,6 +533,12 @@ export function buildIndexRecord({
|
|
|
530
533
|
* @returns {Record<string, any>} The documentation journal's index record.
|
|
531
534
|
*/
|
|
532
535
|
function buildDocRecord({ frontmatter, address, entry, file, contentPackage, anchors }) {
|
|
536
|
+
// **The entry names a document only where one was made**, and where it does
|
|
537
|
+
// not, nothing on this record may name one either: no id, no address and no
|
|
538
|
+
// anchors. The record itself stays, because the index records what a note
|
|
539
|
+
// produces and `null` is how it says a document was not produced — the same
|
|
540
|
+
// signal a stub's absent address already is.
|
|
541
|
+
const made = Boolean(entry.uuid);
|
|
533
542
|
return /** @type {Record<string, any>} */ (
|
|
534
543
|
sortKeysDeep({
|
|
535
544
|
package: contentPackage,
|
|
@@ -540,13 +549,13 @@ function buildDocRecord({ frontmatter, address, entry, file, contentPackage, anc
|
|
|
540
549
|
// re-derived: every entry the index gives an identity to publishes
|
|
541
550
|
// both the id and the UUID, computed once by whatever owns that
|
|
542
551
|
// entry's derivation.
|
|
543
|
-
id: entry.id,
|
|
552
|
+
id: made ? entry.id : null,
|
|
544
553
|
nameAscii: asciiName(frontmatter?.name?.full),
|
|
545
|
-
address: { slug: address.slug, canonical: entry.key },
|
|
554
|
+
address: made ? { slug: address.slug, canonical: entry.key } : null,
|
|
546
555
|
// The record this is the documentation *for*. `documentation` is
|
|
547
556
|
// the forward link on that record, so either end reaches the other.
|
|
548
557
|
documents: address.canonical,
|
|
549
|
-
anchors,
|
|
558
|
+
anchors: made ? anchors : null,
|
|
550
559
|
foundry: foundryBlock(entry), // a journal: no system key
|
|
551
560
|
file,
|
|
552
561
|
})
|
|
@@ -637,8 +646,8 @@ export function collectContentIndex(
|
|
|
637
646
|
|
|
638
647
|
// An item note is two documents, so it is two records. Derived from
|
|
639
648
|
// the address the note *would* hold rather than from the one its
|
|
640
|
-
// record carries
|
|
641
|
-
//
|
|
649
|
+
// record carries, because a stub withholds its own address; the second
|
|
650
|
+
// record says whether the journal beside the item was made.
|
|
642
651
|
const address = noteAddress(fm, contentPackage);
|
|
643
652
|
const doc = foundryEntries({ frontmatter: fm, address, body, manifest })?.doc;
|
|
644
653
|
if (doc?.key && address) {
|
|
@@ -69,6 +69,7 @@ import { walkMarkdownTree } from "./helpers.mjs";
|
|
|
69
69
|
import { resolveNoteId } from "./note-ids.mjs";
|
|
70
70
|
import { compendiumUuid, currentType, packForType, pageUuid } from "./ids.mjs";
|
|
71
71
|
import { hasDocEntry, itemDocEntryId } from "./item-docs.mjs";
|
|
72
|
+
import { journalHasContent } from "./note-state.mjs";
|
|
72
73
|
import { isHomepage } from "./homepage.mjs";
|
|
73
74
|
import { declaresNoPack } from "./pack-router.mjs";
|
|
74
75
|
import { assertNoDeclaredPackage } from "./note-package.mjs";
|
|
@@ -163,7 +164,19 @@ export function entriesForNote(fm, name, address, body, ctx) {
|
|
|
163
164
|
// A published address must name the pack the document actually shipped in:
|
|
164
165
|
// a consumer resolves the UUID verbatim, and a repository may ship several
|
|
165
166
|
// packs of one type.
|
|
166
|
-
const uuidFor = (type, id, routeFm) =>
|
|
167
|
+
const uuidFor = (type, id, routeFm) => {
|
|
168
|
+
// **A document that would be empty is not created, so nothing names
|
|
169
|
+
// one.** A JournalEntry's content is the note's prose, and an empty
|
|
170
|
+
// body compiles no pages, so the pass emits no entry — and a manifest
|
|
171
|
+
// naming one would send every consumer to a document that is not
|
|
172
|
+
// there. Asked of the **document type**, which is what makes one
|
|
173
|
+
// statement cover both journals a note can produce: its own, and the
|
|
174
|
+
// documentation standing beside an item. Every other document is
|
|
175
|
+
// derived from `data:` and is emitted whatever the body holds.
|
|
176
|
+
if (packForType(type)?.docType === "JournalEntry" && !journalHasContent(body)) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
167
180
|
// A type this cannot name a single compendium document for has no UUID
|
|
168
181
|
// to publish, whatever id it derives. That used to follow from such a
|
|
169
182
|
// note authoring no `id:`; every addressable note derives
|
|
@@ -185,21 +198,24 @@ export function entriesForNote(fm, name, address, body, ctx) {
|
|
|
185
198
|
// statement: it publishes a page and compiles into nothing, so it has
|
|
186
199
|
// an address and no UUID. The shared declaration is what is read,
|
|
187
200
|
// because an entry names one document and this pass routes no system.
|
|
188
|
-
(
|
|
189
|
-
id
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
if (
|
|
202
|
+
!id ||
|
|
203
|
+
NEVER_PACKED_TYPES.has(String(type)) ||
|
|
204
|
+
DERIVED_PACKED_TYPES.has(String(type)) ||
|
|
205
|
+
(routeFm && declaresNoPack(routeFm))
|
|
206
|
+
) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return compendiumUuid(
|
|
211
|
+
foundryPackageId,
|
|
212
|
+
type,
|
|
213
|
+
id,
|
|
214
|
+
routeFm ?
|
|
215
|
+
packRouter.resolveOrNull(routeFm, packForType(type).docType)
|
|
216
|
+
: packRouter.defaultOf("JournalEntry"),
|
|
217
|
+
);
|
|
218
|
+
};
|
|
203
219
|
|
|
204
220
|
const carriesDoc =
|
|
205
221
|
ctx.docEntryTypes ?
|
package/engine/journals.mjs
CHANGED
|
@@ -55,6 +55,7 @@ import { infoboxesToHtml, linkToUuid } from "./infobox-render.mjs";
|
|
|
55
55
|
import { noteInfoboxes } from "./infobox-registry.mjs";
|
|
56
56
|
import { hasDocEntry, itemDocEntryId } from "./item-docs.mjs";
|
|
57
57
|
import { JOURNAL_TYPES } from "./ids.mjs";
|
|
58
|
+
import { journalHasContent } from "./note-state.mjs";
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
61
|
* Splits a markdown body into pages by top-level H1 headings. Fenced
|
|
@@ -382,17 +383,24 @@ export class Journals extends BasePackCompiler {
|
|
|
382
383
|
}
|
|
383
384
|
|
|
384
385
|
/**
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
* the
|
|
386
|
+
* **A journal that would be empty is not created**, and that is the whole
|
|
387
|
+
* rule — one test, asked of every note this pass claims, whether its
|
|
388
|
+
* journal is its own document or the documentation standing beside an item.
|
|
389
|
+
* A note with no prose gets no entry: the items pass leaves its description
|
|
390
|
+
* empty rather than pointing at nothing, a map gets no pin target, and
|
|
391
|
+
* {@link module:engine/foundry-entries} publishes no UUID, so nothing names
|
|
392
|
+
* a document that was not made.
|
|
393
|
+
*
|
|
394
|
+
* An entry holding only its infobox is empty by this test. The panel is a
|
|
395
|
+
* rendering of `data:` that the content index already carries, so a
|
|
396
|
+
* compendium entry of nothing else tells a reader what the index told them.
|
|
389
397
|
*
|
|
390
398
|
* @param {object} fm - The note's frontmatter.
|
|
391
399
|
* @param {string} body - The note body, frontmatter stripped.
|
|
392
400
|
* @returns {boolean} True to skip the note.
|
|
393
401
|
*/
|
|
394
402
|
skipNote(fm, body) {
|
|
395
|
-
return
|
|
403
|
+
return !journalHasContent(body);
|
|
396
404
|
}
|
|
397
405
|
|
|
398
406
|
/**
|
package/engine/note-state.mjs
CHANGED
|
@@ -114,6 +114,35 @@ export function isStubNote(frontmatter, body, vocabulary = NOTE_VOCABULARY) {
|
|
|
114
114
|
return isEmptyBody(body) && isStubbableType(frontmatter?.type, vocabulary);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Whether a note's body compiles into a JournalEntry that holds anything.
|
|
119
|
+
*
|
|
120
|
+
* > **A document that would be empty is not created.** Nothing names one
|
|
121
|
+
* > either: the index records the note with every field that names an artefact
|
|
122
|
+
* > set to `null`.
|
|
123
|
+
*
|
|
124
|
+
* The question is about the **output**, not the input, and that is what makes
|
|
125
|
+
* one rule serve every caller: a note's own journal, and the documentation
|
|
126
|
+
* journal an item's prose compiles into beside it, are the same document asked
|
|
127
|
+
* the same question.
|
|
128
|
+
*
|
|
129
|
+
* A JournalEntry's content is its pages, and a page comes from
|
|
130
|
+
* {@link module:engine/journals.splitPages} — a lead page of the prose before
|
|
131
|
+
* the first heading, and one page per heading after it. A body of whitespace
|
|
132
|
+
* yields neither, so an empty body is exactly an empty journal.
|
|
133
|
+
*
|
|
134
|
+
* **An infobox does not count.** The panel is a rendering of `data:`, which the
|
|
135
|
+
* index already publishes; an entry holding nothing else gives a consumer
|
|
136
|
+
* nothing it cannot read from the record.
|
|
137
|
+
*
|
|
138
|
+
* @param {string|null|undefined} body - The note body, frontmatter stripped.
|
|
139
|
+
* @returns {boolean} Whether a JournalEntry compiled from this body holds
|
|
140
|
+
* anything.
|
|
141
|
+
*/
|
|
142
|
+
export function journalHasContent(body) {
|
|
143
|
+
return !isEmptyBody(body);
|
|
144
|
+
}
|
|
145
|
+
|
|
117
146
|
/**
|
|
118
147
|
* The phrases that stand in for prose nobody has written.
|
|
119
148
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "22.5.
|
|
3
|
+
"version": "22.5.1",
|
|
4
4
|
"description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -104,9 +104,10 @@ export function asciiAliases(aliases: unknown): Array<string>;
|
|
|
104
104
|
* @returns {Record<string, any>} The record, keys sorted at every depth. A
|
|
105
105
|
* **stub** — a note with an empty body, on a type an empty body suppresses —
|
|
106
106
|
* carries `address` and `anchors` as `null`: it publishes no page, so it
|
|
107
|
-
* holds no address and offers no anchor. It keeps
|
|
108
|
-
*
|
|
109
|
-
* derived from `data
|
|
107
|
+
* holds no address and offers no anchor. It keeps its `id`, and a `foundry`
|
|
108
|
+
* block naming every document that was made — which is every document
|
|
109
|
+
* derived from `data:`, and no journal, because a journal of an empty body
|
|
110
|
+
* would be empty and is not created.
|
|
110
111
|
* @throws {Error} When the note carries a key this module derives, which would
|
|
111
112
|
* otherwise be overwritten without a word. `file` and, where the file was
|
|
112
113
|
* read, `position` ride on the error.
|
|
@@ -59,6 +59,32 @@ export function isStubbableType(type: string | null | undefined, vocabulary?: Re
|
|
|
59
59
|
export function isStubNote(frontmatter: Record<string, any> | null | undefined, body: string | null | undefined, vocabulary?: Readonly<Record<string, {
|
|
60
60
|
stubbable?: boolean;
|
|
61
61
|
}>>): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Whether a note's body compiles into a JournalEntry that holds anything.
|
|
64
|
+
*
|
|
65
|
+
* > **A document that would be empty is not created.** Nothing names one
|
|
66
|
+
* > either: the index records the note with every field that names an artefact
|
|
67
|
+
* > set to `null`.
|
|
68
|
+
*
|
|
69
|
+
* The question is about the **output**, not the input, and that is what makes
|
|
70
|
+
* one rule serve every caller: a note's own journal, and the documentation
|
|
71
|
+
* journal an item's prose compiles into beside it, are the same document asked
|
|
72
|
+
* the same question.
|
|
73
|
+
*
|
|
74
|
+
* A JournalEntry's content is its pages, and a page comes from
|
|
75
|
+
* {@link module:engine/journals.splitPages} — a lead page of the prose before
|
|
76
|
+
* the first heading, and one page per heading after it. A body of whitespace
|
|
77
|
+
* yields neither, so an empty body is exactly an empty journal.
|
|
78
|
+
*
|
|
79
|
+
* **An infobox does not count.** The panel is a rendering of `data:`, which the
|
|
80
|
+
* index already publishes; an entry holding nothing else gives a consumer
|
|
81
|
+
* nothing it cannot read from the record.
|
|
82
|
+
*
|
|
83
|
+
* @param {string|null|undefined} body - The note body, frontmatter stripped.
|
|
84
|
+
* @returns {boolean} Whether a JournalEntry compiled from this body holds
|
|
85
|
+
* anything.
|
|
86
|
+
*/
|
|
87
|
+
export function journalHasContent(body: string | null | undefined): boolean;
|
|
62
88
|
/**
|
|
63
89
|
* The placeholder phrases a body reduces to, or an empty list.
|
|
64
90
|
*
|