gutterpress 0.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/README.md +422 -0
- package/dist/CGATS21_CRPC1-g0e3k7kr.icc +0 -0
- package/dist/api/index.d.ts +76 -0
- package/dist/api/index.js +272 -0
- package/dist/assets/preview/scripts/pagedjs-bridge.d.ts +1 -0
- package/dist/assets/preview/scripts/pagedjs-interface.d.ts +1 -0
- package/dist/assets/preview/scripts/preview-shell.d.ts +1 -0
- package/dist/audit-1jrwwacz.js +66 -0
- package/dist/build-5s92kgpc.js +77 -0
- package/dist/chapter-01-6fn9pvd0.md +31 -0
- package/dist/chapter-01-7jwqg1ct.md +20 -0
- package/dist/chapter-01-jj8ftn4c.md +29 -0
- package/dist/chapter-01-rkpyvjna.md +26 -0
- package/dist/checks/asset/approved-fonts.d.ts +3 -0
- package/dist/checks/asset/extensions.d.ts +41 -0
- package/dist/checks/asset/font-license.d.ts +3 -0
- package/dist/checks/asset/image-alpha.d.ts +3 -0
- package/dist/checks/asset/image-color-space.d.ts +3 -0
- package/dist/checks/asset/image-file-size.d.ts +3 -0
- package/dist/checks/asset/image-resolution.d.ts +3 -0
- package/dist/checks/asset/image-tac.d.ts +3 -0
- package/dist/checks/asset/index.d.ts +7 -0
- package/dist/checks/formatter.d.ts +3 -0
- package/dist/checks/heuristic/index.d.ts +4 -0
- package/dist/checks/heuristic/layer-count.d.ts +3 -0
- package/dist/checks/heuristic/placement-variance.d.ts +3 -0
- package/dist/checks/heuristic/section-density.d.ts +3 -0
- package/dist/checks/heuristic/text-density.d.ts +3 -0
- package/dist/checks/pdf/bleed.d.ts +3 -0
- package/dist/checks/pdf/bookmarks.d.ts +3 -0
- package/dist/checks/pdf/color-spaces.d.ts +3 -0
- package/dist/checks/pdf/cross-refs.d.ts +3 -0
- package/dist/checks/pdf/embedded-fonts.d.ts +3 -0
- package/dist/checks/pdf/image-resolution.d.ts +3 -0
- package/dist/checks/pdf/index.d.ts +15 -0
- package/dist/checks/pdf/ink-coverage.d.ts +3 -0
- package/dist/checks/pdf/page-labels.d.ts +3 -0
- package/dist/checks/pdf/page-size.d.ts +3 -0
- package/dist/checks/pdf/pdfx-markers.d.ts +3 -0
- package/dist/checks/pdf/pdfx-metadata.d.ts +3 -0
- package/dist/checks/pdf/pdfx-structure.d.ts +6 -0
- package/dist/checks/pdf/qpdf-structure.d.ts +3 -0
- package/dist/checks/pdf/rasterized-pages.d.ts +3 -0
- package/dist/checks/pdf/toc-links.d.ts +3 -0
- package/dist/checks/pdf/transparency.d.ts +3 -0
- package/dist/checks/policy.d.ts +61 -0
- package/dist/checks/register-builtins.d.ts +17 -0
- package/dist/checks/registry.d.ts +40 -0
- package/dist/checks/runner.d.ts +25 -0
- package/dist/checks/source/accessibility-alt-text.d.ts +3 -0
- package/dist/checks/source/accessibility-heading-order.d.ts +3 -0
- package/dist/checks/source/config-file.d.ts +8 -0
- package/dist/checks/source/htmlhint.d.ts +3 -0
- package/dist/checks/source/index.d.ts +6 -0
- package/dist/checks/source/local-refs.d.ts +3 -0
- package/dist/checks/source/markdownlint.d.ts +3 -0
- package/dist/checks/source/stylelint.d.ts +3 -0
- package/dist/checks/tool-check.d.ts +23 -0
- package/dist/checks/types.d.ts +52 -0
- package/dist/cli-1tyj4bk3.js +124 -0
- package/dist/cli-37x76zdn.js +4 -0
- package/dist/cli-506tg37g.js +26 -0
- package/dist/cli-5bxx0c4y.js +464 -0
- package/dist/cli-7ykx7pp0.js +12378 -0
- package/dist/cli-h7phg3ka.js +746 -0
- package/dist/cli-hvqjs342.js +284 -0
- package/dist/cli-yja077f6.js +92 -0
- package/dist/cli.js +157 -0
- package/dist/constants.d.ts +17 -0
- package/dist/doctor-25zjt8dz.js +57 -0
- package/dist/favicon-wkbm9cjn.ico +0 -0
- package/dist/git-http-yrb4ag6z.js +17 -0
- package/dist/index-1tyj4bk3.js +124 -0
- package/dist/index-37x76zdn.js +4 -0
- package/dist/index-3h3fef7r.js +15218 -0
- package/dist/index-5bxx0c4y.js +464 -0
- package/dist/index-yja077f6.js +92 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +310 -0
- package/dist/lib/app-heartbeat.d.ts +102 -0
- package/dist/lib/asset-inline.d.ts +73 -0
- package/dist/lib/browser-pool.d.ts +17 -0
- package/dist/lib/build-error.d.ts +52 -0
- package/dist/lib/build-fingerprint.d.ts +15 -0
- package/dist/lib/build-preflight.d.ts +43 -0
- package/dist/lib/build-runner.d.ts +161 -0
- package/dist/lib/build-staging.d.ts +64 -0
- package/dist/lib/chromium.d.ts +20 -0
- package/dist/lib/cli-args.d.ts +45 -0
- package/dist/lib/desktop.d.ts +14 -0
- package/dist/lib/diagnostics.d.ts +64 -0
- package/dist/lib/embedded-assets.d.ts +29 -0
- package/dist/lib/exec.d.ts +84 -0
- package/dist/lib/fetch-timeout.d.ts +41 -0
- package/dist/lib/ghostscript.d.ts +48 -0
- package/dist/lib/host-policy.d.ts +75 -0
- package/dist/lib/image-inspect.d.ts +32 -0
- package/dist/lib/install-hints.d.ts +21 -0
- package/dist/lib/lint-runner.d.ts +10 -0
- package/dist/lib/manifest-config.d.ts +31 -0
- package/dist/lib/manifest-doc.d.ts +25 -0
- package/dist/lib/manifest.d.ts +41 -0
- package/dist/lib/markdown/assemble.d.ts +78 -0
- package/dist/lib/markdown/chapter-id.d.ts +24 -0
- package/dist/lib/markdown/images.d.ts +34 -0
- package/dist/lib/markdown/index.d.ts +78 -0
- package/dist/lib/markdown/markdown-it-paged.d.ts +30 -0
- package/dist/lib/markdown/plugins.d.ts +69 -0
- package/dist/lib/markdown/renderer.d.ts +111 -0
- package/dist/lib/npm-plugin-installer.d.ts +33 -0
- package/dist/lib/open-path.d.ts +5 -0
- package/dist/lib/output-paths.d.ts +23 -0
- package/dist/lib/pagedjs-marker.d.ts +42 -0
- package/dist/lib/pagedjs.d.ts +26 -0
- package/dist/lib/pagination.d.ts +169 -0
- package/dist/lib/pdf-inspect.d.ts +123 -0
- package/dist/lib/pdf-parse.d.ts +57 -0
- package/dist/lib/plugin-manager.d.ts +108 -0
- package/dist/lib/plugin-vendor.d.ts +107 -0
- package/dist/lib/presets.d.ts +45 -0
- package/dist/lib/printsafe.d.ts +17 -0
- package/dist/lib/project-scaffold.d.ts +116 -0
- package/dist/lib/project-source.d.ts +140 -0
- package/dist/lib/project-templates.d.ts +49 -0
- package/dist/lib/publish/butler.d.ts +10 -0
- package/dist/lib/publish/command-runner.d.ts +18 -0
- package/dist/lib/publish/connect.d.ts +23 -0
- package/dist/lib/publish/manifest-publish.d.ts +9 -0
- package/dist/lib/publish/providers/azure-swa.d.ts +3 -0
- package/dist/lib/publish/providers/drivethrurpg.d.ts +10 -0
- package/dist/lib/publish/providers/guided.d.ts +3 -0
- package/dist/lib/publish/providers/itch.d.ts +5 -0
- package/dist/lib/publish/providers/kdp.d.ts +9 -0
- package/dist/lib/publish/providers/shopify.d.ts +5 -0
- package/dist/lib/publish/registry.d.ts +5 -0
- package/dist/lib/publish/run-publish.d.ts +30 -0
- package/dist/lib/publish/selections.d.ts +25 -0
- package/dist/lib/publish/types.d.ts +258 -0
- package/dist/lib/remote-auth/clone.d.ts +87 -0
- package/dist/lib/remote-auth/conflict-resolution.d.ts +29 -0
- package/dist/lib/remote-auth/diagnose.d.ts +77 -0
- package/dist/lib/remote-auth/generic-auth.d.ts +97 -0
- package/dist/lib/remote-auth/git-http.d.ts +85 -0
- package/dist/lib/remote-auth/github-auth.d.ts +69 -0
- package/dist/lib/remote-auth/github-repos.d.ts +64 -0
- package/dist/lib/remote-auth/operation-log.d.ts +66 -0
- package/dist/lib/remote-auth/recovery/abort-interrupted-operation.d.ts +103 -0
- package/dist/lib/remote-auth/recovery/backup.d.ts +113 -0
- package/dist/lib/remote-auth/recovery/classify.d.ts +109 -0
- package/dist/lib/remote-auth/recovery/context.d.ts +47 -0
- package/dist/lib/remote-auth/recovery/dispatch.d.ts +33 -0
- package/dist/lib/remote-auth/recovery/failsafe.d.ts +33 -0
- package/dist/lib/remote-auth/recovery/inspect.d.ts +74 -0
- package/dist/lib/remote-auth/recovery/manual-guidance.d.ts +28 -0
- package/dist/lib/remote-auth/recovery/outcome-mapping.d.ts +58 -0
- package/dist/lib/remote-auth/recovery/policy.d.ts +47 -0
- package/dist/lib/remote-auth/recovery/recover-auth.d.ts +42 -0
- package/dist/lib/remote-auth/recovery/recover-binary-conflict.d.ts +37 -0
- package/dist/lib/remote-auth/recovery/recover-corrupt-index.d.ts +40 -0
- package/dist/lib/remote-auth/recovery/recover-detached-head.d.ts +70 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-cherry-pick.d.ts +23 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-merge.d.ts +28 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-rebase.d.ts +39 -0
- package/dist/lib/remote-auth/recovery/recover-merge-conflict.d.ts +34 -0
- package/dist/lib/remote-auth/recovery/recover-missing-git-dir.d.ts +37 -0
- package/dist/lib/remote-auth/recovery/recover-missing-objects.d.ts +56 -0
- package/dist/lib/remote-auth/recovery/recover-network.d.ts +34 -0
- package/dist/lib/remote-auth/recovery/recover-non-fast-forward.d.ts +27 -0
- package/dist/lib/remote-auth/recovery/recover-stale-lock.d.ts +76 -0
- package/dist/lib/remote-auth/recovery/recover-unrelated-histories.d.ts +44 -0
- package/dist/lib/remote-auth/recovery/recover-wrong-remote.d.ts +35 -0
- package/dist/lib/remote-auth/recovery/types.d.ts +235 -0
- package/dist/lib/remote-auth/resolution-plan.d.ts +64 -0
- package/dist/lib/remote-auth/sync-messages.d.ts +26 -0
- package/dist/lib/remote-auth/sync-types.d.ts +225 -0
- package/dist/lib/remote-auth/sync.d.ts +45 -0
- package/dist/lib/remote-auth/test-access.d.ts +47 -0
- package/dist/lib/remote-auth/test-support/git-http-server.d.ts +71 -0
- package/dist/lib/remote-auth/token-store.d.ts +95 -0
- package/dist/lib/remote-auth/transport.d.ts +105 -0
- package/dist/lib/slug.d.ts +28 -0
- package/dist/lib/snippets.d.ts +39 -0
- package/dist/lib/source-provider.d.ts +244 -0
- package/dist/lib/static-serve.d.ts +54 -0
- package/dist/lib/style-resolver.d.ts +30 -0
- package/dist/lib/theme-import.d.ts +70 -0
- package/dist/lib/theme-manager.d.ts +128 -0
- package/dist/lib/tool-probe.d.ts +37 -0
- package/dist/lib/validation-exec.d.ts +47 -0
- package/dist/lib/validation-profile.d.ts +18 -0
- package/dist/lib/version.d.ts +9 -0
- package/dist/lint-f63nxjfj.js +65 -0
- package/dist/manifest-n1gh3qw5.yaml +9 -0
- package/dist/manifest-ryyg71nf.yaml +9 -0
- package/dist/manifest.schema-rn1dpdpn.json +564 -0
- package/dist/new-7b08a42h.js +105 -0
- package/dist/paged.polyfill-n95pbxfn.js +33288 -0
- package/dist/pagedjs-bridge-vn4hk9fx.js +111 -0
- package/dist/pagedjs-interface-80g3xa8p.js +498 -0
- package/dist/platform.d.ts +100 -0
- package/dist/plugin-wf2cbmwc.js +129 -0
- package/dist/preflight-tg4mpz1h.js +222 -0
- package/dist/preview/file-watcher.d.ts +174 -0
- package/dist/preview/http-server.d.ts +45 -0
- package/dist/preview/lifecycle.d.ts +67 -0
- package/dist/preview/server-context.d.ts +36 -0
- package/dist/preview-h2bwbb2x.js +102 -0
- package/dist/preview-shell-rghtfmc8.js +155 -0
- package/dist/project-source-0tg0r6vm.js +17 -0
- package/dist/publish-ztaet53r.js +233 -0
- package/dist/render.d.ts +20 -0
- package/dist/render.js +682 -0
- package/dist/repair-jkp4n3j8.js +171 -0
- package/dist/schema/manifest.types.d.ts +218 -0
- package/dist/server.d.ts +34 -0
- package/dist/source-provider-hp96b5jf.js +46 -0
- package/dist/test-helpers/testkit.d.ts +91 -0
- package/dist/theme-0yzvthe8.css +65 -0
- package/dist/theme-570zmh2t.css +58 -0
- package/dist/theme-6a2fngc8.json +6 -0
- package/dist/theme-cd6efzjw.json +6 -0
- package/dist/theme-nya4nqh6.css +70 -0
- package/dist/theme-tqfypc1w.json +6 -0
- package/dist/theme-xt0hjb1b.json +6 -0
- package/dist/theme-zz2ktzqs.css +60 -0
- package/dist/types.d.ts +31 -0
- package/dist/utils/file-utils.d.ts +53 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/validate-k2drs19j.js +99 -0
- package/package.json +102 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-free raster image header reader — the in-process replacement for
|
|
3
|
+
* ImageMagick `identify` used by the asset checks (Phase 3 of ADR 0002).
|
|
4
|
+
*
|
|
5
|
+
* Why not `sharp`? sharp is the most capable option but is a native addon whose
|
|
6
|
+
* platform binaries are resolved through `node_modules` at runtime — exactly the
|
|
7
|
+
* pattern that breaks `bun build --compile` (ADR 0001 §1/§3). A small header
|
|
8
|
+
* parser for the formats print authors actually use (PNG, JPEG, TIFF) keeps a
|
|
9
|
+
* single code path that bundles into the standalone binary AND runs in the
|
|
10
|
+
* Electron desktop, with zero system/native dependency.
|
|
11
|
+
*
|
|
12
|
+
* Scope: width/height, x/y DPI, alpha presence, and a coarse color-space token
|
|
13
|
+
* ("srgb" | "gray" | "cmyk"). This matches what the three asset checks consume.
|
|
14
|
+
* Tokens are lowercased to line up with the lowercased `identify %[colorspace]`
|
|
15
|
+
* values the existing config compares against.
|
|
16
|
+
*
|
|
17
|
+
* DPI parity note: like `identify`, an image with no density metadata is treated
|
|
18
|
+
* as 72 DPI (ImageMagick's default) so the opt-in min-DPI check behaves as before.
|
|
19
|
+
*/
|
|
20
|
+
export type ColorSpace = "srgb" | "gray" | "cmyk" | "";
|
|
21
|
+
export interface ImageInfo {
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
/** Effective DPI; defaults to 72 when the file carries no density metadata. */
|
|
25
|
+
xDpi: number;
|
|
26
|
+
yDpi: number;
|
|
27
|
+
hasAlpha: boolean;
|
|
28
|
+
colorSpace: ColorSpace;
|
|
29
|
+
}
|
|
30
|
+
/** Inspect a PNG/JPEG/TIFF file; returns null for unreadable/unknown formats. */
|
|
31
|
+
export declare function inspectImage(path: string): Promise<ImageInfo | null>;
|
|
32
|
+
export declare function collectImageFiles(dirs: string[], exts: readonly string[], ignore?: readonly string[]): Promise<string[]>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical per-tool install-hint copy — the text a stuck non-technical
|
|
3
|
+
* author actually reads when a build fails because gs/qpdf/Chromium isn't
|
|
4
|
+
* installed.
|
|
5
|
+
*
|
|
6
|
+
* This is the single source of truth. `build-preflight.ts` (preflight error),
|
|
7
|
+
* `diagnostics.ts` (desktop Help/About dialog + `gutterpress doctor`), and
|
|
8
|
+
* `chromium.ts` (`requireChromiumExecutable`'s thrown error) all import
|
|
9
|
+
* from here instead of hand-copying the per-platform install commands —
|
|
10
|
+
* previously three diverging copies existed (see
|
|
11
|
+
* docs/reviews/2026-07-10-architecture-critical-review.md, finding #15).
|
|
12
|
+
*/
|
|
13
|
+
export interface InstallHint {
|
|
14
|
+
/** Human label for the tool, used in "Install <label>:" headers. */
|
|
15
|
+
label: string;
|
|
16
|
+
/** Indented, per-platform install commands. No header, no trailing newline. */
|
|
17
|
+
body: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const INSTALL_HINTS: Record<"chromium" | "gs" | "qpdf", InstallHint>;
|
|
20
|
+
/** "Install <label>:\n<body>" — the full standalone hint (diagnostics/doctor). */
|
|
21
|
+
export declare function fullInstallHint(tool: keyof typeof INSTALL_HINTS): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface LintRunnerOptions {
|
|
2
|
+
files?: string;
|
|
3
|
+
manifest?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface LintRunnerResult {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
riskyCount: number;
|
|
8
|
+
filesLinted: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function runLint(opts?: LintRunnerOptions): Promise<LintRunnerResult>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The author-facing manifest subset the Config view can read + write. */
|
|
2
|
+
export interface ProjectConfigFields {
|
|
3
|
+
title?: string;
|
|
4
|
+
authors?: string[];
|
|
5
|
+
/** `source.files` — the markdown inputs (null means "all chapter files"). */
|
|
6
|
+
sourceFiles?: string[] | null;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Apply the author-facing manifest field updates in a single yaml round-trip.
|
|
10
|
+
* Only the keys present in `updates` are written; everything else is left
|
|
11
|
+
* untouched (so unrelated comments + sections survive). `sourceFiles: null`
|
|
12
|
+
* deletes the `source.files` entry (back to "all chapter files").
|
|
13
|
+
*/
|
|
14
|
+
export declare function setManifestFields(projectDir: string, updates: ProjectConfigFields): Promise<ProjectConfigFields>;
|
|
15
|
+
/**
|
|
16
|
+
* Read the author-facing manifest subset for the Config view's Details section.
|
|
17
|
+
* Loads via the same shared {@link loadManifestDoc} every other manifest reader/
|
|
18
|
+
* writer in this module uses (ARCH finding #25 — this used to re-implement
|
|
19
|
+
* loadManifestDoc's read-and-parse inline) and surfaces empty/absent fields as
|
|
20
|
+
* empty strings so the form inputs are editable.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readManifestFields(projectDir: string): Promise<ProjectConfigFields>;
|
|
23
|
+
/**
|
|
24
|
+
* Replace the manifest's entire `styles:` list with `paths`. This is the
|
|
25
|
+
* generic "which stylesheets are active" control the unified Config view's
|
|
26
|
+
* Styles section drives — toggling a stylesheet on/off or reordering the active
|
|
27
|
+
* set. Theme-apply still owns copying the theme folder; this only rewrites the
|
|
28
|
+
* list entry order. `paths` are project-relative, forward-slash strings (how
|
|
29
|
+
* they appear in the manifest, e.g. `themes/zine/theme.css`, `styles/print.css`).
|
|
30
|
+
*/
|
|
31
|
+
export declare function setActiveStyles(projectDir: string, paths: string[]): Promise<string[]>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { YAMLSeq } from "yaml";
|
|
2
|
+
import type { Document } from "yaml";
|
|
3
|
+
/** Resolve `manifest.yaml` inside a project dir. */
|
|
4
|
+
export declare function resolveManifestPath(projectDir: string): string;
|
|
5
|
+
/** Load the manifest as a yaml Document (empty doc when absent). */
|
|
6
|
+
export declare function loadManifestDoc(projectDir: string): Promise<{
|
|
7
|
+
doc: Document.Parsed;
|
|
8
|
+
file: string;
|
|
9
|
+
}>;
|
|
10
|
+
/** Atomically write the doc back, creating the project dir if needed. */
|
|
11
|
+
export declare function writeManifestDoc(file: string, doc: Document.Parsed): Promise<void>;
|
|
12
|
+
/** The named sequence node, creating (and attaching) an empty one if missing. */
|
|
13
|
+
export declare function ensureSeq(doc: Document.Parsed, key: string): YAMLSeq;
|
|
14
|
+
/**
|
|
15
|
+
* Unwrap a yaml seq item (or `getIn`-style Pair) to its string value: `null`
|
|
16
|
+
* when the item isn't a string. Handles both a bare Scalar/Pair-shaped node
|
|
17
|
+
* (`{ value: … }`, as `doc.get(key, true)` returns for seq items) and a
|
|
18
|
+
* plain JS string (as a freshly-constructed `Scalar`'s `.value` or a raw
|
|
19
|
+
* array entry would be).
|
|
20
|
+
*
|
|
21
|
+
* ARCH finding #25: this was two near-duplicate helpers — `unwrapScalar`
|
|
22
|
+
* (manifest-config.ts) and `styleHrefOf` (theme-manager.ts) — with the same
|
|
23
|
+
* shape-sniffing logic. One implementation here, consumed by both.
|
|
24
|
+
*/
|
|
25
|
+
export declare function scalarString(item: unknown): string | null;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { GutterpressManifest, ResolvedConfig } from "../schema/manifest.types";
|
|
2
|
+
/**
|
|
3
|
+
* The manifest file name Gutterpress recognizes.
|
|
4
|
+
* Single source of truth — any code that needs to find/match a manifest file
|
|
5
|
+
* (project scanning, GitHub repo book discovery, …) should consume this
|
|
6
|
+
* instead of hardcoding the names.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MANIFEST_FILENAMES: readonly ["manifest.yaml"];
|
|
9
|
+
/** True when a directory contains any recognized project manifest file. */
|
|
10
|
+
export declare function hasProjectManifest(dir: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Load a recognized manifest from a given path or CWD.
|
|
13
|
+
* Returns an empty object if the file doesn't exist.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadManifest(pathOrDir?: string): Promise<GutterpressManifest>;
|
|
16
|
+
/**
|
|
17
|
+
* Load a recognized manifest and return its contents, directory, and resolved path.
|
|
18
|
+
* Returns an empty manifest, a null path, and the current working directory if none is found —
|
|
19
|
+
* UNLESS `explicit` is set (ARCH finding #12/PR #98): a caller that resolved
|
|
20
|
+
* `pathOrDir` from a user-supplied `--manifest` flag (as opposed to a project
|
|
21
|
+
* directory being scanned for a manifest that may legitimately not exist) must
|
|
22
|
+
* pass `{ explicit: true }` so a missing/typo'd path throws instead of
|
|
23
|
+
* silently resolving to an empty manifest. A typo like `--manifest
|
|
24
|
+
* ./typo.yaml` previously fell through to the "no manifest" default AND left
|
|
25
|
+
* `manifestDir` pointing at the nonexistent path itself
|
|
26
|
+
* (`resolve("./typo.yaml")`), so a later `path.resolve(manifestDir,
|
|
27
|
+
* config.output.dir)` could create build output beneath a directory named
|
|
28
|
+
* after the missing file.
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadManifestWithPath(pathOrDir?: string, opts?: {
|
|
31
|
+
explicit?: boolean;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
manifest: GutterpressManifest;
|
|
34
|
+
manifestDir: string;
|
|
35
|
+
manifestPath: string | null;
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* Merge CLI args > manifest > preset defaults into a fully-resolved config.
|
|
39
|
+
* Any field explicitly set in `cliOverrides` wins, then manifest, then preset.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveConfig(cliOverrides: Partial<GutterpressManifest>, manifest: GutterpressManifest): ResolvedConfig;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type LoadedPlugin } from "./renderer";
|
|
2
|
+
/** Reader injected by the host: resolve a project-root-relative file → its text. */
|
|
3
|
+
export type ReadText = (relPath: string) => Promise<string>;
|
|
4
|
+
/**
|
|
5
|
+
* One author-mistake warning emitted by `markdown-it-paged` (ARCH finding #4).
|
|
6
|
+
* Mirrors the shape `markdown-it-paged.js`'s `warn()` pushes onto
|
|
7
|
+
* `env.layoutWarnings` — see that file's header comment for the 8 warning
|
|
8
|
+
* `type`s (`ambiguous_marker_token`, `section_without_page`, `nested_spread`,
|
|
9
|
+
* `continue_without_section`, `spread_without_pages`, `spread_eof_close`,
|
|
10
|
+
* `page_outside_spread`, `implicit_page`).
|
|
11
|
+
*/
|
|
12
|
+
export interface LayoutWarning {
|
|
13
|
+
line: number;
|
|
14
|
+
type: string;
|
|
15
|
+
message: string;
|
|
16
|
+
marker?: unknown;
|
|
17
|
+
}
|
|
18
|
+
export interface AssembleBookHtmlOptions {
|
|
19
|
+
/** Ordered list of project-root-relative `.md` files to concatenate. */
|
|
20
|
+
files: string[];
|
|
21
|
+
/** Async reader the assembler uses to fetch each file's contents. */
|
|
22
|
+
readText: ReadText;
|
|
23
|
+
/**
|
|
24
|
+
* Fully-inlined project CSS (fonts already embedded as `data:` URIs by
|
|
25
|
+
* `lib/asset-inline.ts`). Emitted as a `<style data-project-css>` block —
|
|
26
|
+
* NOT as `<link href>`.
|
|
27
|
+
*
|
|
28
|
+
* Inlining is what makes a stylesheet's location irrelevant to the output, so
|
|
29
|
+
* themes (`themes/<id>/theme.css`) and shared design systems
|
|
30
|
+
* (`../design-guide/styles/guide.css`) need no copying, no flattening and no
|
|
31
|
+
* destination indirection. It is also what Paged.js does to the document
|
|
32
|
+
* anyway — it deletes every `<link>`/`<style>` and re-emits the CSS inline —
|
|
33
|
+
* so a `<link>` never survived the render path to begin with.
|
|
34
|
+
*/
|
|
35
|
+
projectCss?: string;
|
|
36
|
+
title?: string;
|
|
37
|
+
plugins?: LoadedPlugin[];
|
|
38
|
+
pluginCss?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Add `data-chapter-src="<file>"` to the same source-mapped block elements
|
|
41
|
+
* that receive `data-source-line`. The historical option name is retained as
|
|
42
|
+
* public API, but no wrapper is emitted: even `display: contents` changes CSS
|
|
43
|
+
* selector relationships such as `body > *`, `:first-child`, and cross-file
|
|
44
|
+
* siblings, which can change pagination. Off by default; build output is
|
|
45
|
+
* unaffected.
|
|
46
|
+
*/
|
|
47
|
+
wrapChapters?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* ARCH finding #4: per-chapter callback receiving any `env.layoutWarnings`
|
|
50
|
+
* `markdown-it-paged` computed while rendering `file` (only called when
|
|
51
|
+
* that chapter produced at least one). `file` is the same canonical
|
|
52
|
+
* chapter id used for `data-chapter-src`, so a host can attribute a warning
|
|
53
|
+
* to the exact source file. Additive/optional — omitting it reproduces the
|
|
54
|
+
* prior throwaway-env behavior exactly, so this cannot change output for
|
|
55
|
+
* existing callers (e.g. the desktop's WebAdapter, which still gets a plain
|
|
56
|
+
* `Promise<string>` back).
|
|
57
|
+
*/
|
|
58
|
+
onChapterWarnings?: (file: string, warnings: LayoutWarning[]) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Every image reference the assembled document emits, deduped and in document
|
|
61
|
+
* order — markdown image tokens (recorded by `registerImageRule`) plus raw
|
|
62
|
+
* HTML `<img src>` found by scanning the output.
|
|
63
|
+
*
|
|
64
|
+
* This is what makes "referenced means shipped" true: the build turns these
|
|
65
|
+
* into its copy plan (`planImageCopies`), so no author-maintained directory
|
|
66
|
+
* list can drift from what the book actually uses.
|
|
67
|
+
*/
|
|
68
|
+
onImageRefs?: (refs: string[]) => void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Assemble a single `book.html` string from the given markdown files.
|
|
72
|
+
*
|
|
73
|
+
* Pure: every input (the file list, their contents via `readText`, the resolved
|
|
74
|
+
* CSS hrefs) is supplied by the caller. Mirrors the exact `<head>`/body/CSS
|
|
75
|
+
* emission the old `renderChapters` produced, so the CLI output is byte-identical
|
|
76
|
+
* for identical inputs.
|
|
77
|
+
*/
|
|
78
|
+
export declare function assembleBookHtml(opts: AssembleBookHtmlOptions): Promise<string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical chapter identity.
|
|
3
|
+
*
|
|
4
|
+
* A chapter is identified by ONE canonical string everywhere it crosses a
|
|
5
|
+
* boundary: project-root-relative, forward slashes, no `./` prefix, no
|
|
6
|
+
* duplicate slashes. This single form is used by:
|
|
7
|
+
*
|
|
8
|
+
* - preview source blocks' `data-chapter-src` tagging
|
|
9
|
+
* (lib/markdown/assemble.ts assembleBookHtml — index.ts's renderChapters
|
|
10
|
+
* is now just the thin node:fs wrapper around it)
|
|
11
|
+
* - preview source inspection and chapter-scoped scroll restoration
|
|
12
|
+
* (preview/file-watcher.ts)
|
|
13
|
+
* - the desktop's editor↔preview sync scoping
|
|
14
|
+
* (packages/desktop +page.svelte editorChapter)
|
|
15
|
+
*
|
|
16
|
+
* WHY: manifest `source.files` entries are author-written and arrive in many
|
|
17
|
+
* spellings (`./chapters/03.md`, `chapters\03.md` on Windows, `chapters//03.md`),
|
|
18
|
+
* while the watcher broadcasts `path.relative(inputPath, file)`. Before this
|
|
19
|
+
* helper the build tagged the manifest string VERBATIM, so any `./`-prefixed
|
|
20
|
+
* or backslashed manifest entry made source-attribution and scroll-restoration
|
|
21
|
+
* lookups miss every `data-chapter-src` in the live DOM (and the desktop's
|
|
22
|
+
* editor↔preview chapter scoping silently broke the same way).
|
|
23
|
+
*/
|
|
24
|
+
export declare function canonicalChapterId(p: string): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type MarkdownIt from "markdown-it";
|
|
2
|
+
/**
|
|
3
|
+
* Markdown-it `image` renderer rule that RECORDS every image reference the
|
|
4
|
+
* document emits, on `env.imageRefs`.
|
|
5
|
+
*
|
|
6
|
+
* This replaces the previous `normalizeImageSrc` rewriter, which collapsed
|
|
7
|
+
* `temp/images/…` and `./images/…` to `images/…`. That rewrite had zero
|
|
8
|
+
* producers anywhere in the codebase or its history, and it silently broke any
|
|
9
|
+
* author who kept art in a folder literally named `temp/images/` — the HTML
|
|
10
|
+
* pointed at `images/<file>`, which no code path ever created, and adding the
|
|
11
|
+
* folder to the old `source.assets` list could not fix it.
|
|
12
|
+
*
|
|
13
|
+
* Recording instead of rewriting is what lets the build copy exactly the files
|
|
14
|
+
* the book references (`lib/asset-inline.ts` → `planImageCopies`), so the
|
|
15
|
+
* author's own folder layout is the layout that ships. Paths are emitted
|
|
16
|
+
* verbatim; the build resolves them against the project root, which is the
|
|
17
|
+
* frame `book.html` is served from.
|
|
18
|
+
*/
|
|
19
|
+
/** Env slot the rule appends to. Absent when nothing referenced an image. */
|
|
20
|
+
export interface ImageRefEnv {
|
|
21
|
+
imageRefs?: string[];
|
|
22
|
+
}
|
|
23
|
+
export declare function registerImageRule(md: MarkdownIt): void;
|
|
24
|
+
/**
|
|
25
|
+
* Collect local image references from raw HTML in rendered output.
|
|
26
|
+
*
|
|
27
|
+
* Covers `src` on `<img>` AND every candidate in a `srcset` (on `<img>` or on
|
|
28
|
+
* `<source>` inside `<picture>`). A responsive image's candidates are real files
|
|
29
|
+
* the browser may choose: the preview serves them straight from the project so
|
|
30
|
+
* they look fine, but the build only ships what the copy plan names — so a
|
|
31
|
+
* candidate that never entered the plan 404s during pagination and drops out of
|
|
32
|
+
* the PDF silently. Scanning only `src` was exactly that gap.
|
|
33
|
+
*/
|
|
34
|
+
export declare function collectHtmlImageRefs(html: string): string[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type LayoutWarning } from "./assemble";
|
|
2
|
+
import { type AssetCopy } from "../asset-inline";
|
|
3
|
+
import type { LoadedPlugin } from "./renderer";
|
|
4
|
+
export type { LayoutWarning } from "./assemble";
|
|
5
|
+
export { createMarkdownRenderer } from "./renderer";
|
|
6
|
+
/**
|
|
7
|
+
* THE canonical "which markdown files make up this book, and in what order?"
|
|
8
|
+
* resolver — markdown's counterpart to `resolveActiveStyles` (style-resolver.ts).
|
|
9
|
+
* Both `renderChapters` below AND validation/lint (validation-exec.ts,
|
|
10
|
+
* lint-runner.ts) call this, so what gets checked is always what gets rendered
|
|
11
|
+
* (2026-07-28 duplication audit — those two used to each re-derive their own
|
|
12
|
+
* recursive-glob approximation of "the book's markdown files" instead of
|
|
13
|
+
* calling this):
|
|
14
|
+
* 1. `configuredFiles` (the manifest `source.files` list), if it has entries,
|
|
15
|
+
* in that order; else
|
|
16
|
+
* 2. every `.md` file directly inside `inputDir` — NOT recursive, since a
|
|
17
|
+
* book's chapters live at the project root by convention — alphabetically.
|
|
18
|
+
* Returned entries are exactly as authored/discovered (relative to `inputDir`,
|
|
19
|
+
* un-normalised); callers that need a readable path must resolve them the same
|
|
20
|
+
* way `renderChapters` does below (`join(inputDir, canonicalChapterId(f))`).
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveActiveMarkdownFiles(inputDir: string, configuredFiles?: string[] | null): Promise<string[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Render all chapter markdown files to a single HTML string.
|
|
25
|
+
*
|
|
26
|
+
* If files are specified, they will be included in the provided order.
|
|
27
|
+
* If files are not specified, all .md files in the directory will be included in alphabetical order.
|
|
28
|
+
*
|
|
29
|
+
* This is the thin **Node wrapper** around the pure `assembleBookHtml`
|
|
30
|
+
* (`./assemble.ts`): it resolves the CSS list + the file list off disk and
|
|
31
|
+
* supplies a `node:fs/promises`-backed `readText`. The pure assembler owns the
|
|
32
|
+
* markdown→HTML→book.html work, so the browser/PWA WebAdapter can reuse the
|
|
33
|
+
* exact same render path with a File System Access reader (#33).
|
|
34
|
+
*/
|
|
35
|
+
export declare function renderChapters(inputDir: string, opts?: {
|
|
36
|
+
title?: string;
|
|
37
|
+
styles?: string[];
|
|
38
|
+
files?: string[] | null;
|
|
39
|
+
plugins?: LoadedPlugin[];
|
|
40
|
+
pluginCss?: string;
|
|
41
|
+
/** Add chapter identity to source-mapped blocks for preview inspection. */
|
|
42
|
+
wrapChapters?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* ARCH finding #4: per-chapter author-mistake warnings computed by
|
|
45
|
+
* markdown-it-paged (`env.layoutWarnings`), forwarded straight through
|
|
46
|
+
* from {@link assembleBookHtml}. See that option's docstring — omitting
|
|
47
|
+
* it is fully backward compatible.
|
|
48
|
+
*/
|
|
49
|
+
onChapterWarnings?: (file: string, warnings: LayoutWarning[]) => void;
|
|
50
|
+
/** See {@link assembleBookHtml}'s option of the same name. */
|
|
51
|
+
onImageRefs?: (refs: string[]) => void;
|
|
52
|
+
/**
|
|
53
|
+
* Files the inlined CSS needs alongside the book (content-addressed images
|
|
54
|
+
* too large to embed). The build adds these to its copy plan.
|
|
55
|
+
*/
|
|
56
|
+
onCssAssets?: (copies: AssetCopy[]) => void;
|
|
57
|
+
/** Non-fatal notices from the inliner (e.g. a remote `url()` left as-is). */
|
|
58
|
+
onStyleWarnings?: (warnings: string[]) => void;
|
|
59
|
+
}): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Render chapters and write the result to a file.
|
|
62
|
+
*
|
|
63
|
+
* The output filename is fixed at `book.html` (BOOK_HTML_FILENAME) — the
|
|
64
|
+
* gutterpress desktop (`index.html`) loads this via a relative iframe `src`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function renderChaptersToFile(inputDir: string, outDir: string, opts?: {
|
|
67
|
+
title?: string;
|
|
68
|
+
styles?: string[];
|
|
69
|
+
files?: string[] | null;
|
|
70
|
+
plugins?: LoadedPlugin[];
|
|
71
|
+
pluginCss?: string;
|
|
72
|
+
/** ARCH finding #4 — see {@link renderChapters}'s option of the same name. */
|
|
73
|
+
onChapterWarnings?: (file: string, warnings: LayoutWarning[]) => void;
|
|
74
|
+
/** See {@link renderChapters}'s options of the same names. */
|
|
75
|
+
onImageRefs?: (refs: string[]) => void;
|
|
76
|
+
onCssAssets?: (copies: AssetCopy[]) => void;
|
|
77
|
+
onStyleWarnings?: (warnings: string[]) => void;
|
|
78
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export default function plugin(md: any, pluginOptions?: {}): void;
|
|
2
|
+
/**
|
|
3
|
+
* Minimal Paged.js-friendly CSS for the classes this plugin emits.
|
|
4
|
+
* Consumers should inject this into <head> after their user stylesheets so
|
|
5
|
+
* the layout contract (page/section/column breaks) wins at equal specificity.
|
|
6
|
+
*
|
|
7
|
+
* Also ships five author-facing image/block utility classes (CLAUDE.md §0 —
|
|
8
|
+
* a behavior broadly useful to non-technical authors belongs in core, not a
|
|
9
|
+
* project layer; see UX finding M17). markdown-it-attrs is bundled by
|
|
10
|
+
* default (renderer.ts), so `{.full-bleed}` already attaches
|
|
11
|
+
* the class to the rendered `<img>` — these rules are what make that class
|
|
12
|
+
* actually do something print-safe:
|
|
13
|
+
*
|
|
14
|
+
* .center — centers a block element (margin-inline: auto).
|
|
15
|
+
* .float-left — floats left with clearance margins.
|
|
16
|
+
* .float-right — floats right with clearance margins.
|
|
17
|
+
* .full-width — fills the page's content width (100%).
|
|
18
|
+
* .full-bleed — forces its own page (break-before) and cancels the
|
|
19
|
+
* page's LEFT/RIGHT margins via Paged.js's real
|
|
20
|
+
* `--pagedjs-margin-left`/`--pagedjs-margin-right` custom
|
|
21
|
+
* properties (set per-page by the polyfill from the active
|
|
22
|
+
* `@page` rule — see pagedjs/src/polisher/base.js), so
|
|
23
|
+
* content spans the page edge-to-edge horizontally. This
|
|
24
|
+
* does NOT cancel the top/bottom margins, extend past the
|
|
25
|
+
* trim into printer bleed overage, apply a named `@page`
|
|
26
|
+
* template, or remove headers/footers — none of that is
|
|
27
|
+
* implemented; the custom-property fallback of 0 means it
|
|
28
|
+
* degrades to plain full-width outside a Paged.js render.
|
|
29
|
+
*/
|
|
30
|
+
export const PAGED_CSS: "\n.md-page-break { break-before: page; }\n.page { break-before: page; }\n.spread { break-before: page; }\n.section { break-inside: avoid; }\n.section.col-split { break-inside: auto; }\n.md-column-break { break-after: column; height: 0; font-size: 0; line-height: 0; visibility: hidden; }\n\n.center { display: block; margin-left: auto; margin-right: auto; max-width: 100%; }\n.float-left { float: left; margin: 0 1em 1em 0; max-width: 50%; }\n.float-right { float: right; margin: 0 0 1em 1em; max-width: 50%; }\n.full-width { display: block; width: 100%; max-width: 100%; }\n.full-bleed {\n display: block;\n break-before: page;\n max-width: none;\n width: calc(100% + var(--pagedjs-margin-left, 0px) + var(--pagedjs-margin-right, 0px));\n margin-left: calc(-1 * var(--pagedjs-margin-left, 0px));\n margin-right: calc(-1 * var(--pagedjs-margin-right, 0px));\n}\n";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ResolvedPluginConfig } from "../../schema/manifest.types";
|
|
2
|
+
import type { LoadedPlugin } from "./renderer";
|
|
3
|
+
export type { GutterpressPlugin, GutterpressPluginMetadata, GutterpressPluginExport, LoadedPlugin, } from "./renderer";
|
|
4
|
+
export { applyPlugins, collectPluginCss } from "./renderer";
|
|
5
|
+
/** Test-only mutation seam between snapshot completion and snapshot verification. */
|
|
6
|
+
export declare function __setVendorSnapshotHookForTests(hook?: (sourceRoot: string, snapshotRoot: string) => void | Promise<void>): void;
|
|
7
|
+
export declare function clearVendoredPluginResolver(baseDir: string, packageName: string, version: string): void;
|
|
8
|
+
/** Test-only: reset the path-plugin cache between test cases. */
|
|
9
|
+
export declare function __resetPathPluginCacheForTests(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Load a single plugin from a file path or npm package.
|
|
12
|
+
*
|
|
13
|
+
* Throws if the plugin cannot be resolved, imported, or doesn't export a
|
|
14
|
+
* valid plugin function. The error message identifies which manifest entry
|
|
15
|
+
* failed so users can find it.
|
|
16
|
+
*
|
|
17
|
+
* Path plugins always go through the mtime cache (see the call below): it is
|
|
18
|
+
* correct in both a one-shot CLI build and the long-lived Electron host that
|
|
19
|
+
* runs `runBuild` in-process, so no caller-selected cache mode is needed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadPlugin(config: ResolvedPluginConfig, baseDir: string): Promise<LoadedPlugin>;
|
|
22
|
+
/**
|
|
23
|
+
* Load all plugins from the resolved configuration.
|
|
24
|
+
*
|
|
25
|
+
* Two failure modes, selected by whether `onError` is supplied:
|
|
26
|
+
*
|
|
27
|
+
* - **Fail-fast (no `onError`)** — the default for build/export/validate. If
|
|
28
|
+
* any plugin fails to load, the whole operation aborts with the underlying
|
|
29
|
+
* error. A final artifact must never silently omit author-configured
|
|
30
|
+
* formatting.
|
|
31
|
+
* - **Degrade-and-report (`onError` supplied)** — for the LIVE PREVIEW. A
|
|
32
|
+
* plugin that can't load (e.g. a vendored folder was omitted when a
|
|
33
|
+
* project was copied) is skipped, `onError` is invoked with the
|
|
34
|
+
* offending ref + error, and the rest of the document still renders. This
|
|
35
|
+
* is NOT silent skipping (the failure mode §5 warns against): the caller
|
|
36
|
+
* surfaces every skip loudly (preview warns in its log; the Plugins panel
|
|
37
|
+
* shows the plugin error with fix instructions).
|
|
38
|
+
*
|
|
39
|
+
* Path plugins are loaded through the mtime cache in `loadPlugin` regardless
|
|
40
|
+
* of mode (finding #5): an edited plugin reloads across renders while an
|
|
41
|
+
* unedited one is never re-imported, correct in both a one-shot CLI build and
|
|
42
|
+
* the long-lived Electron host.
|
|
43
|
+
*/
|
|
44
|
+
export declare function loadPlugins(configs: ResolvedPluginConfig[], baseDir: string, onError?: (pluginRef: string, error: Error) => void): Promise<LoadedPlugin[]>;
|
|
45
|
+
/** Result of {@link loadPluginsWithCss}: loaded plugins ready for `applyPlugins`
|
|
46
|
+
* plus their concatenated CSS ready for injection into the rendered document. */
|
|
47
|
+
export interface LoadedPluginsWithCss {
|
|
48
|
+
/** `undefined` (not `[]`) when there were no configs to load — matches the
|
|
49
|
+
* `plugins?:` field the renderer options expect, so callers can pass this
|
|
50
|
+
* straight through without an `?? []` at every call site. */
|
|
51
|
+
plugins: LoadedPlugin[] | undefined;
|
|
52
|
+
pluginCss: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Shared "load plugins -> collect their CSS" preamble (ARCH finding #53).
|
|
56
|
+
* Both real render paths — build/export's fail-fast `renderBook`
|
|
57
|
+
* (build-runner.ts) and the live preview's degrade-and-report
|
|
58
|
+
* `renderPreviewBook` (preview/file-watcher.ts) — did this in lockstep,
|
|
59
|
+
* differing ONLY in whether `onError` was supplied. `onError` presence still
|
|
60
|
+
* selects fail-fast vs degrade-and-report (see {@link loadPlugins}) and the
|
|
61
|
+
* matching path-plugin cache mode; this helper just removes the duplicated
|
|
62
|
+
* wiring around it.
|
|
63
|
+
*
|
|
64
|
+
* A `configs` of `undefined`/empty short-circuits WITHOUT calling
|
|
65
|
+
* `loadPlugins` at all (`plugins: undefined`, `pluginCss: ""`) — matching
|
|
66
|
+
* both call sites' prior behavior of never plugin-loading when the manifest
|
|
67
|
+
* declares no plugins.
|
|
68
|
+
*/
|
|
69
|
+
export declare function loadPluginsWithCss(configs: ResolvedPluginConfig[] | undefined | null, baseDir: string, onError?: (pluginRef: string, error: Error) => void): Promise<LoadedPluginsWithCss>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure (node-free) markdown rendering core.
|
|
3
|
+
*
|
|
4
|
+
* §1/§8 / ADR 0004: this module imports ONLY pure JS — markdown-it and its
|
|
5
|
+
* plugins, the inlined `markdown-it-paged.js`, and the node-free leveled
|
|
6
|
+
* logger (console-only). It contains NO `node:*`,
|
|
7
|
+
* NO `fs`/`path`/`url`, and NO filesystem access, so it can be imported by the
|
|
8
|
+
* browser renderer (the PWA WebAdapter, #33) AND bundled into the
|
|
9
|
+
* `bun build --compile` CLI binary alike.
|
|
10
|
+
*
|
|
11
|
+
* The plugin *author* types and the markdown-it factory live here (not in
|
|
12
|
+
* `plugins.ts`) precisely because `plugins.ts` is the node-coupled plugin
|
|
13
|
+
* *loader* (`node:fs`/`node:path`/`node:url`/`node:module`). Splitting the pure
|
|
14
|
+
* factory out keeps the browser import graph free of node code. `plugins.ts`
|
|
15
|
+
* re-exports these for backward compatibility, so existing callers are
|
|
16
|
+
* unaffected.
|
|
17
|
+
*/
|
|
18
|
+
import MarkdownIt from "markdown-it";
|
|
19
|
+
/**
|
|
20
|
+
* Plugin author API.
|
|
21
|
+
*
|
|
22
|
+
* A gutterpress plugin is a standard markdown-it plugin — any plugin from npm
|
|
23
|
+
* with the signature `(md, options) => void` will work, including the entire
|
|
24
|
+
* markdown-it plugin ecosystem.
|
|
25
|
+
*
|
|
26
|
+
* Authors of *new* plugins can `import type { GutterpressPlugin } from
|
|
27
|
+
* 'gutterpress'` for type-only support; no runtime dependency on
|
|
28
|
+
* gutterpress is required (or recommended).
|
|
29
|
+
*/
|
|
30
|
+
export type GutterpressPlugin = (md: MarkdownIt, options?: Record<string, unknown>) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Optional metadata a plugin may export alongside its default plugin function.
|
|
33
|
+
* Surfaced in load-time log lines so users can see which plugins are active.
|
|
34
|
+
*/
|
|
35
|
+
export interface GutterpressPluginMetadata {
|
|
36
|
+
name?: string;
|
|
37
|
+
version?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
author?: string;
|
|
40
|
+
keywords?: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Full shape a plugin module may export. Only `default` is required.
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const plugin: GutterpressPlugin = (md) => { ... };
|
|
47
|
+
* export default plugin;
|
|
48
|
+
* export const metadata: GutterpressPluginMetadata = { name: 'my-plugin', version: '1.0.0' };
|
|
49
|
+
* export const css = `.my-class { color: red; }`;
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export interface GutterpressPluginExport {
|
|
53
|
+
default: GutterpressPlugin;
|
|
54
|
+
metadata?: GutterpressPluginMetadata;
|
|
55
|
+
/** CSS injected into <head> after user stylesheets. Use sparingly — has equal cascade specificity. */
|
|
56
|
+
css?: string;
|
|
57
|
+
}
|
|
58
|
+
/** Internal representation of a loaded plugin, ready for `md.use()`. */
|
|
59
|
+
export interface LoadedPlugin {
|
|
60
|
+
name: string;
|
|
61
|
+
plugin: GutterpressPlugin;
|
|
62
|
+
metadata?: GutterpressPluginMetadata;
|
|
63
|
+
css?: string;
|
|
64
|
+
options: Record<string, unknown>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Bundled, opt-in markdown plugins keyed by their npm name. Enabling one of
|
|
68
|
+
* these (manifest `plugins: - <name>` or the desktop's plugin manager) resolves
|
|
69
|
+
* it from HERE — no project install, no network, works offline and in the
|
|
70
|
+
* compiled binary. The plugin loader (`plugins.ts`) consults this map before
|
|
71
|
+
* trying to resolve a package from the project's node_modules, so a
|
|
72
|
+
* non-technical author gets the feature instantly instead of a "not installed"
|
|
73
|
+
* error. (attrs/footnote/deflist are NOT here — they are always-on defaults
|
|
74
|
+
* applied unconditionally below.)
|
|
75
|
+
*/
|
|
76
|
+
export declare const BUILTIN_OPTIONAL_PLUGINS: Record<string, GutterpressPlugin>;
|
|
77
|
+
/**
|
|
78
|
+
* Create a fully-configured MarkdownIt instance.
|
|
79
|
+
*
|
|
80
|
+
* Built-in pipeline (runs before any user plugins):
|
|
81
|
+
* markdown-it-attrs → markdown-it-footnote → markdown-it-deflist →
|
|
82
|
+
* markdown-it-source-map → markdown-it-paged
|
|
83
|
+
*
|
|
84
|
+
* markdown-it-deflist adds the standard (PHP Markdown Extra / Pandoc)
|
|
85
|
+
* definition-list syntax — `Term` / `: definition` — emitting plain
|
|
86
|
+
* `<dl><dt><dd>`. It is not in CommonMark/markdown-it core; this is the
|
|
87
|
+
* canonical markdown-it plugin for it.
|
|
88
|
+
*
|
|
89
|
+
* Block container syntax (`:::name ... :::`) was removed 2026-05-17 in favor
|
|
90
|
+
* of the @marker family. See docs/migrations/2026-05-removing-container-syntax.md
|
|
91
|
+
* for the migration mapping.
|
|
92
|
+
*
|
|
93
|
+
* GFM-style `> [!NOTE]` alerts were also moved into the DC plugin on the
|
|
94
|
+
* same date because the emitted classes (dc-alert, dc-vibe-callout, etc.)
|
|
95
|
+
* are DC-branded. Core should not leak DC identifiers.
|
|
96
|
+
*
|
|
97
|
+
* @param customPlugins - Optional array of custom plugins to load
|
|
98
|
+
*/
|
|
99
|
+
export declare function createMarkdownRenderer(customPlugins?: LoadedPlugin[]): MarkdownIt;
|
|
100
|
+
/**
|
|
101
|
+
* Apply loaded plugins to a markdown-it instance.
|
|
102
|
+
*
|
|
103
|
+
* Throws if a plugin's `(md, options) => void` call itself throws — usually
|
|
104
|
+
* a sign that the plugin is incompatible with this markdown-it version or
|
|
105
|
+
* has a bug in its `apply` phase.
|
|
106
|
+
*/
|
|
107
|
+
export declare function applyPlugins(md: MarkdownIt, plugins: LoadedPlugin[]): void;
|
|
108
|
+
/**
|
|
109
|
+
* Collect CSS from all loaded plugins, concatenated in load order.
|
|
110
|
+
*/
|
|
111
|
+
export declare function collectPluginCss(plugins: LoadedPlugin[]): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface NpmPluginInstallLimits {
|
|
2
|
+
metadataBytes: number;
|
|
3
|
+
packageTarballBytes: number;
|
|
4
|
+
totalNetworkBytes: number;
|
|
5
|
+
packageFileBytes: number;
|
|
6
|
+
totalUnpackedBytes: number;
|
|
7
|
+
totalFiles: number;
|
|
8
|
+
totalPackages: number;
|
|
9
|
+
dependencyDepth: number;
|
|
10
|
+
}
|
|
11
|
+
type FetchFn = typeof globalThis.fetch;
|
|
12
|
+
export interface NpmPluginInstallOptions {
|
|
13
|
+
/** Dependency injection for focused tests; production uses global fetch. */
|
|
14
|
+
fetch?: FetchFn;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
/** Test/specialized-host limits; production defaults stay deliberately hard. */
|
|
17
|
+
limits?: Partial<NpmPluginInstallLimits>;
|
|
18
|
+
}
|
|
19
|
+
export interface InstalledNpmPlugin {
|
|
20
|
+
name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
installRoot: string;
|
|
23
|
+
/** Previous same-version directory held until the manifest commits. */
|
|
24
|
+
backupRoot: string | null;
|
|
25
|
+
warnings: string[];
|
|
26
|
+
}
|
|
27
|
+
/** Download and publish a fresh, receipt-backed vendor tree. Never reuses bytes. */
|
|
28
|
+
export declare function installNpmPlugin(projectDirInput: string, packageSpec: string, options?: NpmPluginInstallOptions): Promise<InstalledNpmPlugin>;
|
|
29
|
+
/** Finish a successful vendor+manifest transaction. */
|
|
30
|
+
export declare function finalizeNpmPluginInstall(installed: InstalledNpmPlugin): Promise<void>;
|
|
31
|
+
/** Restore the previous same-version tree (or remove a new one) after failure. */
|
|
32
|
+
export declare function rollbackNpmPluginInstall(installed: InstalledNpmPlugin): Promise<void>;
|
|
33
|
+
export {};
|