@heroiclands/package-build 18.1.1 → 19.0.0
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 +153 -0
- package/CONTENT.md +2 -2
- package/ci/ci-docker.mjs +236 -0
- package/ci/ci-steps.mjs +249 -0
- package/content-config.mjs +16 -23
- package/docs/content-format.md +14 -13
- package/engine/base-compiler.mjs +2 -0
- package/engine/folder-notes.mjs +64 -0
- package/engine/foundry-entries.mjs +2 -0
- package/engine/frontmatter-lint.mjs +29 -1
- package/engine/frontmatter.mjs +1 -1
- package/engine/generate.mjs +11 -36
- package/engine/helpers.mjs +1 -119
- package/engine/item-compiler.mjs +7 -9
- package/engine/journals.mjs +6 -12
- package/engine/scenes.mjs +7 -9
- package/githooks/commit-msg +40 -0
- package/githooks/hook-enabled.sh +25 -0
- package/githooks/pre-commit +11 -0
- package/githooks/pre-merge-commit +12 -0
- package/githooks/pre-push +109 -0
- package/githooks/protected-branch.sh +62 -0
- package/hm3/actors.mjs +7 -10
- package/package.json +3 -1
- package/types/content-config.d.mts +0 -7
- package/types/engine/folder-notes.d.mts +39 -0
- package/types/engine/helpers.d.mts +0 -29
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
#
|
|
3
|
+
# Reject commit messages that carry AI/assistant attribution.
|
|
4
|
+
#
|
|
5
|
+
# This project does not want Co-Authored-By trailers naming an AI assistant, nor
|
|
6
|
+
# "Generated with Claude Code"-style signatures, in its history. The matching CI
|
|
7
|
+
# guard is the shared HeroicLands/.github/actions/no-attribution action, which
|
|
8
|
+
# this repository's .github/workflows/no-attribution.yml calls. That action holds
|
|
9
|
+
# the pattern for every repository; this hook is the only other copy, because a
|
|
10
|
+
# git hook runs from your checkout and cannot live in an action. Keep them in sync.
|
|
11
|
+
#
|
|
12
|
+
# Installed for everyone via the package.json "prepare" script, which points
|
|
13
|
+
# git at this directory (`git config core.hooksPath .githooks`) on `npm install`.
|
|
14
|
+
|
|
15
|
+
. "$(dirname "$0")/hook-enabled.sh"
|
|
16
|
+
|
|
17
|
+
# On unless refused: it costs nothing, and the No Attribution workflow enforces
|
|
18
|
+
# the same rule on GitHub, so opting out locally only moves the failure later.
|
|
19
|
+
hook_enabled noAttribution true || exit 0
|
|
20
|
+
|
|
21
|
+
msg_file="$1"
|
|
22
|
+
|
|
23
|
+
# Scan only the real message: drop the diff appended by `commit --verbose` (from
|
|
24
|
+
# the scissors comment onward) and strip remaining comment lines.
|
|
25
|
+
content="$(sed '/^#.*>8/,$d' "$msg_file" | grep -v '^#')"
|
|
26
|
+
|
|
27
|
+
# Anchored to the start of a line: real attribution is a trailer / signature at
|
|
28
|
+
# column 0, so prose that merely *mentions* these phrases mid-sentence (e.g. this
|
|
29
|
+
# hook's own docs) does not trip it. The generated-with branch tolerates a
|
|
30
|
+
# leading emoji/space.
|
|
31
|
+
pattern='^[[:space:]]*co-authored-by:.*(claude|anthropic)|^[^[:alpha:]]*generated with .*claude code'
|
|
32
|
+
|
|
33
|
+
if printf '%s\n' "$content" | grep -iEq "$pattern"; then
|
|
34
|
+
echo "commit-msg: AI/assistant attribution is not allowed in commit messages." >&2
|
|
35
|
+
printf '%s\n' "$content" | grep -iEn "$pattern" | sed 's/^/ /' >&2
|
|
36
|
+
echo "Remove the 'Co-Authored-By: …' / 'Generated with Claude Code' line and commit again." >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
exit 0
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
#
|
|
3
|
+
# Whether one hook is switched on, so every hook asks the same way.
|
|
4
|
+
#
|
|
5
|
+
# `hook_enabled <key> <default>` reads `hooks.<key>` with git's normal
|
|
6
|
+
# precedence — a plain `git config` sets it for one clone, `--global` for a
|
|
7
|
+
# machine — and falls back to the hook's own default when unset. Each hook has
|
|
8
|
+
# its own key, so they are turned on and off individually rather than as a set:
|
|
9
|
+
# a repository may well want the branch guard and not the workflow check, or
|
|
10
|
+
# the reverse.
|
|
11
|
+
#
|
|
12
|
+
# Defaults differ by hook, and deliberately: a guard that costs nothing is on
|
|
13
|
+
# unless refused, while one that runs a container for minutes is off unless
|
|
14
|
+
# asked for.
|
|
15
|
+
|
|
16
|
+
hook_enabled() {
|
|
17
|
+
_key="$1"
|
|
18
|
+
_default="$2"
|
|
19
|
+
_value="$(git config --bool "hooks.$_key" 2>/dev/null)"
|
|
20
|
+
if [ -z "$_value" ]; then
|
|
21
|
+
[ "$_default" = "true" ]
|
|
22
|
+
return $?
|
|
23
|
+
fi
|
|
24
|
+
[ "$_value" = "true" ]
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
#
|
|
3
|
+
# Refuse to commit on a protected branch. See protected-branch.sh for the rule
|
|
4
|
+
# and its opt-outs; pre-merge-commit is this hook's counterpart for merges.
|
|
5
|
+
#
|
|
6
|
+
# Installed for everyone via the package.json "prepare" script, which points git
|
|
7
|
+
# at this directory (`git config core.hooksPath .githooks`) on `npm install`.
|
|
8
|
+
|
|
9
|
+
. "$(dirname "$0")/protected-branch.sh"
|
|
10
|
+
|
|
11
|
+
guard_protected_branch
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
#
|
|
3
|
+
# Refuse to create a *merge* commit on a protected branch — the `git pull` on
|
|
4
|
+
# main case, which pre-commit never sees, because git runs this hook instead of
|
|
5
|
+
# that one for a merge. See protected-branch.sh for the rule and its opt-outs.
|
|
6
|
+
#
|
|
7
|
+
# Installed for everyone via the package.json "prepare" script, which points git
|
|
8
|
+
# at this directory (`git config core.hooksPath .githooks`) on `npm install`.
|
|
9
|
+
|
|
10
|
+
. "$(dirname "$0")/protected-branch.sh"
|
|
11
|
+
|
|
12
|
+
guard_protected_branch
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
#
|
|
3
|
+
# Before pushing, run exactly what the Build & Test workflow runs — in a
|
|
4
|
+
# container, over a clean export of HEAD — so a red GitHub check is something
|
|
5
|
+
# you chose rather than something you discover.
|
|
6
|
+
#
|
|
7
|
+
# The steps are not listed here. `utils/ci-steps.mjs` reads them out of
|
|
8
|
+
# `.github/workflows/build.yml`, because a hook holding its own copy of the
|
|
9
|
+
# command list is a second statement of one thing, and the copy is the one that
|
|
10
|
+
# goes stale — silently, since running four of five steps still exits 0.
|
|
11
|
+
#
|
|
12
|
+
# **On push rather than at `gh pr create`**, because a push is where this
|
|
13
|
+
# repository's work reaches GitHub: normally one, just before the pull request.
|
|
14
|
+
# Nothing to remember, no wrapper command, and no entry in package.json — the
|
|
15
|
+
# hook is the whole mechanism.
|
|
16
|
+
#
|
|
17
|
+
# **In a container rather than on this machine**, which is not the obvious
|
|
18
|
+
# choice until you time it. The workflow's first step is `npm ci`, so a local
|
|
19
|
+
# run costs very nearly what the container costs (134s measured, cold) — and it
|
|
20
|
+
# pays that by deleting and reinstalling your working tree's `node_modules`
|
|
21
|
+
# every time. The container runs a `git archive` of HEAD instead: same price,
|
|
22
|
+
# nothing of yours touched, plus the three classes this machine cannot catch —
|
|
23
|
+
# a dirty environment, a case-sensitive filesystem, and the runner's own
|
|
24
|
+
# architecture. It runs `linux/amd64` to match the runner, which costs nothing
|
|
25
|
+
# measurable because Docker Desktop translates it with Rosetta rather than
|
|
26
|
+
# QEMU; `ci/ci-docker.mjs` carries the timings and the `--native` opt-out.
|
|
27
|
+
#
|
|
28
|
+
# This hook ships in `@heroiclands/package-build`. A consuming repository points
|
|
29
|
+
# git at it once, in its package.json "prepare" script:
|
|
30
|
+
#
|
|
31
|
+
# git config core.hooksPath node_modules/@heroiclands/package-build/githooks
|
|
32
|
+
#
|
|
33
|
+
# so the hooks are the package's, not a copy per repository — there were twenty
|
|
34
|
+
# copies of four identical files before this moved.
|
|
35
|
+
#
|
|
36
|
+
# **Off by default.** Turn it on where you want it:
|
|
37
|
+
#
|
|
38
|
+
# git config hooks.prePushCi true this clone
|
|
39
|
+
# git config --global hooks.prePushCi true every repository on this machine
|
|
40
|
+
#
|
|
41
|
+
# **Docker is not required even then.** Without it the check reports that it
|
|
42
|
+
# could not run, says so loudly, and lets the push through — the workflow itself
|
|
43
|
+
# is what enforces this, and a contributor without Docker is still entitled to
|
|
44
|
+
# open a pull request. First run pulls the image (~400MB), once.
|
|
45
|
+
#
|
|
46
|
+
# Skipping it once, when enabled: git push --no-verify
|
|
47
|
+
#
|
|
48
|
+
# Deleting a remote branch pushes no commits, so there is nothing to check and
|
|
49
|
+
# the hook stands aside.
|
|
50
|
+
|
|
51
|
+
# **Off unless asked for.** This runs a container for a couple of minutes, and
|
|
52
|
+
# it ships to every repository that installs this package — so it cannot be
|
|
53
|
+
# something a contributor discovers by having their push get slow. Opting in is
|
|
54
|
+
# a deliberate act by whoever wants the check.
|
|
55
|
+
#
|
|
56
|
+
# Read with git's normal precedence, so `--global` opts a machine in and a plain
|
|
57
|
+
# `git config` opts in one clone (and every worktree of it).
|
|
58
|
+
#
|
|
59
|
+
# Silent when off: a message on every push, to everyone who never asked for
|
|
60
|
+
# this, is noise.
|
|
61
|
+
. "$(dirname "$0")/hook-enabled.sh"
|
|
62
|
+
|
|
63
|
+
hook_enabled prePushCi false || exit 0
|
|
64
|
+
|
|
65
|
+
# Read the ref list on stdin; a delete has an all-zero local sha.
|
|
66
|
+
has_commits=""
|
|
67
|
+
while read -r _local_ref local_sha _remote_ref _remote_sha; do
|
|
68
|
+
case "$local_sha" in
|
|
69
|
+
*[!0]*) has_commits="yes" ;;
|
|
70
|
+
esac
|
|
71
|
+
done
|
|
72
|
+
if [ -z "$has_commits" ]; then
|
|
73
|
+
exit 0
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
echo "pre-push: running the Build & Test workflow in a container over HEAD."
|
|
77
|
+
echo "pre-push: to skip once, push with --no-verify."
|
|
78
|
+
|
|
79
|
+
# The runner lives beside this hook inside the package. If it is not there,
|
|
80
|
+
# this hook is being used from somewhere else — a global `core.hooksPath`, a
|
|
81
|
+
# copy — in a repository that does not install the package. Nothing to run, and
|
|
82
|
+
# certainly nothing to refuse a push over.
|
|
83
|
+
runner="$(dirname "$0")/../ci/ci-docker.mjs"
|
|
84
|
+
if [ ! -f "$runner" ]; then
|
|
85
|
+
echo "pre-push: no workflow runner alongside this hook; skipping the check."
|
|
86
|
+
exit 0
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
node "$runner"
|
|
90
|
+
status=$?
|
|
91
|
+
|
|
92
|
+
# 2 means the check could not run — no Docker — which is not the same as a
|
|
93
|
+
# failure and must not stop the push. Whoever is pushing may not be the
|
|
94
|
+
# maintainer, may be on a machine without Docker, and is entitled to open a
|
|
95
|
+
# pull request; GitHub is what enforces the workflow. Said loudly, though: a
|
|
96
|
+
# skipped check that reads like a passed one is how a guard loses its meaning.
|
|
97
|
+
# 127 is "could not execute it at all" — no node on PATH, package not
|
|
98
|
+
# installed. Infrastructure, not a verdict, so it is handled the same way.
|
|
99
|
+
if [ "$status" -eq 2 ] || [ "$status" -eq 127 ]; then
|
|
100
|
+
echo ""
|
|
101
|
+
echo "pre-push: pushing WITHOUT having checked the workflow locally."
|
|
102
|
+
exit 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
if [ "$status" -ne 0 ]; then
|
|
106
|
+
echo ""
|
|
107
|
+
echo "pre-push: refusing to push — GitHub would report the same failure."
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
#
|
|
3
|
+
# Shared guard: refuse to create a commit while HEAD is on a protected branch.
|
|
4
|
+
#
|
|
5
|
+
# Sourced by the pre-commit and pre-merge-commit hooks, which are two hooks for
|
|
6
|
+
# one rule: git runs pre-merge-commit *instead of* pre-commit when the commit is
|
|
7
|
+
# a merge, so a repository that guards only pre-commit still lets a stray
|
|
8
|
+
# `git pull` on main write a merge commit.
|
|
9
|
+
#
|
|
10
|
+
# Why guard at commit time at all: `main` is protected on GitHub in every
|
|
11
|
+
# HeroicLands repository — changes land by pull request, squash-merged, never by
|
|
12
|
+
# a direct push. That protection fires at *push* time, by which point the commit
|
|
13
|
+
# already exists on the local branch and has to be moved off it. This moves the
|
|
14
|
+
# refusal forward to the point where the fix is still just "branch first".
|
|
15
|
+
#
|
|
16
|
+
# It is an accident guard, not a security control. `git commit --no-verify`
|
|
17
|
+
# bypasses it, and a repository that genuinely wants commits on its default
|
|
18
|
+
# branch opts out with `git config hooks.allowCommitOnMain true`.
|
|
19
|
+
#
|
|
20
|
+
# Known gap: `git cherry-pick` and `git revert` run neither hook, and a rebase
|
|
21
|
+
# replays commits with HEAD detached (deliberately allowed below).
|
|
22
|
+
#
|
|
23
|
+
# This file is copied verbatim into every HeroicLands repository, for the same
|
|
24
|
+
# reason the commit-msg hook is: a hook runs from your checkout, so it cannot be
|
|
25
|
+
# shared through a GitHub Action. Keep the copies identical.
|
|
26
|
+
|
|
27
|
+
guard_protected_branch() {
|
|
28
|
+
. "$(dirname "$0")/hook-enabled.sh"
|
|
29
|
+
|
|
30
|
+
# Off where this repository says so. Two spellings: `hooks.protectedBranch`
|
|
31
|
+
# is this hook's key in the per-hook scheme, and `hooks.allowCommitOnMain`
|
|
32
|
+
# is the name that has always meant this — kept, and still honoured, so an
|
|
33
|
+
# existing opt-out does not quietly stop working.
|
|
34
|
+
if ! hook_enabled protectedBranch true; then
|
|
35
|
+
return 0
|
|
36
|
+
fi
|
|
37
|
+
if [ "$(git config --bool hooks.allowCommitOnMain 2>/dev/null)" = "true" ]; then
|
|
38
|
+
return 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Detached HEAD — a rebase, a bisect, or an explicit checkout of a commit.
|
|
42
|
+
# There is no branch to protect, and refusing here would break `git rebase`.
|
|
43
|
+
branch="$(git symbolic-ref --quiet --short HEAD)" || return 0
|
|
44
|
+
|
|
45
|
+
case "$branch" in
|
|
46
|
+
main | master) ;;
|
|
47
|
+
*) return 0 ;;
|
|
48
|
+
esac
|
|
49
|
+
|
|
50
|
+
cat >&2 <<EOF
|
|
51
|
+
$(basename "$0"): refusing to commit on the protected branch '$branch'.
|
|
52
|
+
|
|
53
|
+
'$branch' is protected on GitHub, so this commit could never be pushed from
|
|
54
|
+
here. Move it onto a branch first — this keeps everything you have staged:
|
|
55
|
+
|
|
56
|
+
git switch -c <type>/<issue_#>_<slug>
|
|
57
|
+
|
|
58
|
+
To commit here anyway just this once, use 'git commit --no-verify'. To opt this
|
|
59
|
+
repository out permanently, 'git config hooks.allowCommitOnMain true'.
|
|
60
|
+
EOF
|
|
61
|
+
return 1
|
|
62
|
+
}
|
package/hm3/actors.mjs
CHANGED
|
@@ -259,16 +259,13 @@ export class Hm3Actors extends SystemActorCompiler {
|
|
|
259
259
|
locateFrontmatterKey(this.currentNote?.absPath, field.legacyKey),
|
|
260
260
|
);
|
|
261
261
|
|
|
262
|
-
//
|
|
263
|
-
// address
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
packFolderAddress ?
|
|
270
|
-
this.folderResolver(packFolderAddress, { isAddress: true })
|
|
271
|
-
: this.folderResolver(blockField(fm, block, "folder", null));
|
|
262
|
+
// One spelling, as everywhere else: `packFolder` names a folder note
|
|
263
|
+
// by its address. This pass once read only the Foundry id, so an HM3
|
|
264
|
+
// tree could not file an actor by address at all — which its own sweep
|
|
265
|
+
// needs; the id spelling is retired outright (#251, #255, #260).
|
|
266
|
+
const folder = this.folderResolver(blockField(fm, block, "packFolder", null), {
|
|
267
|
+
isAddress: true,
|
|
268
|
+
});
|
|
272
269
|
|
|
273
270
|
const system = {
|
|
274
271
|
// Nullish, not `||` (#218): a note that names no portrait gets the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "19.0.0",
|
|
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",
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"README.md",
|
|
106
106
|
"bin",
|
|
107
107
|
"bundle.mjs",
|
|
108
|
+
"ci",
|
|
108
109
|
"config.mjs",
|
|
109
110
|
"container.mjs",
|
|
110
111
|
"content-config.mjs",
|
|
@@ -113,6 +114,7 @@
|
|
|
113
114
|
"deploy.mjs",
|
|
114
115
|
"e2e.mjs",
|
|
115
116
|
"engine",
|
|
117
|
+
"githooks",
|
|
116
118
|
"hm3",
|
|
117
119
|
"index.mjs",
|
|
118
120
|
"lang.mjs",
|
|
@@ -214,12 +214,6 @@ export type PackSpec = {
|
|
|
214
214
|
* Whether the pack is GM-only. Default `false`.
|
|
215
215
|
*/
|
|
216
216
|
private?: boolean | undefined;
|
|
217
|
-
/**
|
|
218
|
-
* The pack's folder-hierarchy file, relative
|
|
219
|
-
* to `paths.content`. Default `null` — no
|
|
220
|
-
* folder documents are emitted.
|
|
221
|
-
*/
|
|
222
|
-
folders?: string | null | undefined;
|
|
223
217
|
/**
|
|
224
218
|
* Directory holding this pack's per-document
|
|
225
219
|
* JSON, already built. Declaring it skips
|
|
@@ -268,7 +262,6 @@ export type ResolvedPackSpec = {
|
|
|
268
262
|
type: PackDocumentType;
|
|
269
263
|
label: string;
|
|
270
264
|
private: boolean;
|
|
271
|
-
folders: string | null;
|
|
272
265
|
prebuilt: string | null;
|
|
273
266
|
system: string | null;
|
|
274
267
|
companions: readonly Readonly<ResolvedPackSpec>[];
|
|
@@ -77,6 +77,45 @@ export function buildFolderNoteIndex(folders: FolderNote[]): {
|
|
|
77
77
|
* @returns {object} The Folder document.
|
|
78
78
|
*/
|
|
79
79
|
export function folderDocument(folder: FolderNote, parent: FolderNote | null, documentType: string, stats: object): object;
|
|
80
|
+
/**
|
|
81
|
+
* Refuse a note that declares the retired `folder:` spelling.
|
|
82
|
+
*
|
|
83
|
+
* `folder:` named a compendium folder by the raw Foundry id declared in a
|
|
84
|
+
* per-pack `*-folders.yaml`. Both halves are retired together (#260): the id
|
|
85
|
+
* spelling has nothing left to resolve against once the YAML is gone, and the
|
|
86
|
+
* YAML has no reader once the spelling is refused.
|
|
87
|
+
*
|
|
88
|
+
* **Presence is the whole test.** An empty `folder:` — which parses as `null`
|
|
89
|
+
* — is still the field, and a value that happens to match a folder note's id
|
|
90
|
+
* is still the retired spelling. There is no value that makes writing it
|
|
91
|
+
* correct, so the message says what to write instead rather than which value
|
|
92
|
+
* to change.
|
|
93
|
+
*
|
|
94
|
+
* **Both positions**, because notes wrote it both ways: top-level, and inside
|
|
95
|
+
* the `sohl:` block. Checking only the more common one is how a sweep leaves
|
|
96
|
+
* a tail behind.
|
|
97
|
+
*
|
|
98
|
+
* Refused rather than ignored, on the pattern `package:` set: a retired field
|
|
99
|
+
* left ignored reads to its author as though it still works — the note says
|
|
100
|
+
* one thing and the build does another, and nothing says so.
|
|
101
|
+
*
|
|
102
|
+
* @param {object|null|undefined} fm - Parsed frontmatter, or nothing when it
|
|
103
|
+
* could not be parsed.
|
|
104
|
+
* @param {object} [options] - Options.
|
|
105
|
+
* @param {string} [options.file] - The note's path, named in the message. Omit
|
|
106
|
+
* it where the caller emits through a diagnostic, which puts the locator at
|
|
107
|
+
* the start of the line already — repeating it prints the path twice.
|
|
108
|
+
* @param {string} [options.absPath] - The note's file on disk, read only on
|
|
109
|
+
* the failing path to locate the offending line and column. The position
|
|
110
|
+
* rides on the thrown error as `position`, for a caller that emits a
|
|
111
|
+
* diagnostic.
|
|
112
|
+
* @returns {void}
|
|
113
|
+
* @throws {Error} When the note declares the field.
|
|
114
|
+
*/
|
|
115
|
+
export function assertNoDeclaredFolder(fm: object | null | undefined, { file, absPath }?: {
|
|
116
|
+
file?: string | undefined;
|
|
117
|
+
absPath?: string | undefined;
|
|
118
|
+
}): void;
|
|
80
119
|
/**
|
|
81
120
|
* The note type a folder is authored as.
|
|
82
121
|
*
|
|
@@ -428,41 +428,12 @@ export function expandNoteTables(body: string, { docs, name, fm, bodyLine, sqlTa
|
|
|
428
428
|
generated: boolean;
|
|
429
429
|
}>;
|
|
430
430
|
};
|
|
431
|
-
/**
|
|
432
|
-
* Loads a folders.yaml file as an array of folder entries. Returns []
|
|
433
|
-
* when the file is missing (logging a warning) so packs without folders
|
|
434
|
-
* can opt out simply by not committing the file.
|
|
435
|
-
*/
|
|
436
|
-
export function loadFolders(foldersFile: any): any[];
|
|
437
|
-
/**
|
|
438
|
-
* Validates folder invariants and returns a resolver function that maps a
|
|
439
|
-
* folder id to the same id (after verifying it exists). Returns `null` for
|
|
440
|
-
* a null/empty input; throws for an unknown id.
|
|
441
|
-
*
|
|
442
|
-
* Invariants:
|
|
443
|
-
* - Every folder must have a non-empty id
|
|
444
|
-
* - Every folder must have a name
|
|
445
|
-
* - Sibling folders (same parentFolderId) must have unique names
|
|
446
|
-
* - Every parentFolderId must match an existing folder id (or be "")
|
|
447
|
-
*
|
|
448
|
-
* Returns { resolver, folders } where folders is the validated list.
|
|
449
|
-
*/
|
|
450
|
-
export function buildFolderResolver(folders: any): {
|
|
451
|
-
resolver: (value: string | null | undefined) => string | null;
|
|
452
|
-
folders: any;
|
|
453
|
-
};
|
|
454
431
|
/**
|
|
455
432
|
* Builds a compendium-source filename for a folder JSON document:
|
|
456
433
|
* `folder_Name_id.json` with non-alphanumeric runs replaced by
|
|
457
434
|
* underscores.
|
|
458
435
|
*/
|
|
459
436
|
export function folderFilename(name: any, id: any): string;
|
|
460
|
-
/**
|
|
461
|
-
* Writes one JSON document per folder into `destDir`. `documentType`
|
|
462
|
-
* determines the folder's Foundry `type` field — `"Item"` for the items
|
|
463
|
-
* pack, `"JournalEntry"` for the journals pack.
|
|
464
|
-
*/
|
|
465
|
-
export function writeFolderDocs(folders: any, stats: any, destDir: any, documentType: any): void;
|
|
466
437
|
export const md: import("markdown-it").MarkdownIt;
|
|
467
438
|
export { slugify } from "./content-slug.mjs";
|
|
468
439
|
export { makeId } from "./ids.mjs";
|