gutterpress 0.11.23-beta.1 → 0.11.23-beta.3
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 +13 -3
- package/dist/api/index.d.ts +5 -5
- package/dist/api/index.js +19 -7
- package/dist/{build-dg8a566j.js → build-fq3mexhy.js} +9 -9
- package/dist/checks/asset/approved-fonts.d.ts +8 -0
- package/dist/checks/asset/extensions.d.ts +1 -1
- package/dist/checks/asset/index.d.ts +1 -0
- package/dist/{cli-e31jshz6.js → cli-5zbdb6mt.js} +296 -65
- package/dist/{cli-ttj95aex.js → cli-7mt0dftw.js} +47 -18
- package/dist/{cli-989eg8jz.js → cli-ah93yyzb.js} +163 -55
- package/dist/{cli-31anr0r9.js → cli-eymdsefg.js} +69 -29
- package/dist/{cli-1fy1pm9d.js → cli-fh685nqs.js} +1 -1
- package/dist/{cli-k087gj0p.js → cli-fsjre61x.js} +123 -12
- package/dist/{cli-s1zt779w.js → cli-q7t04gjt.js} +1 -1
- package/dist/{cli-vhav8g82.js → cli-rybz2dfs.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-g4a42tcz.js → doctor-tg9ht1n3.js} +3 -3
- package/dist/engine/compiler/postprocess.d.ts +3 -0
- package/dist/engine/shared/pdf-inspect.d.ts +33 -0
- package/dist/{engine-jvkcahr1.js → engine-17v87vq5.js} +1 -1
- package/dist/{engine-wgkaqjsc.js → engine-y9fnarfa.js} +2 -2
- package/dist/{ext-w9d5ftcg.js → ext-esz03jz4.js} +27 -10
- package/dist/{extension-restore-5x4mj79d.js → extension-restore-91gy1e28.js} +3 -3
- package/dist/{extension-restore-as0g38p1.js → extension-restore-q70wqah5.js} +5 -5
- package/dist/{gutterpress-agent-d29ry3ak.js → gutterpress-agent-wyryqehx.js} +13 -4
- package/dist/{gutterpress-viewer-ze691rrd.js → gutterpress-viewer-ywkf49q5.js} +38 -153
- package/dist/{index-a4j3xcfp.js → index-67g8f7r4.js} +47 -18
- package/dist/{index-798jt0qc.js → index-d9w3r89w.js} +3 -3
- package/dist/{index-rj5vrhz6.js → index-fntpr44x.js} +321 -66
- package/dist/{index-5x42amh8.js → index-g3te5ey1.js} +2 -1
- package/dist/{index-cw03e9p4.js → index-kw4tbthz.js} +69 -29
- package/dist/{index-fk2kpf2t.js → index-santcs4q.js} +121 -10
- package/dist/{index-c6y0p7jy.js → index-z6vzj3s5.js} +243 -73
- package/dist/index.js +35 -8
- package/dist/lib/check-options.d.ts +70 -0
- package/dist/lib/extension-manager.d.ts +16 -1
- package/dist/lib/extension-scaffold.d.ts +15 -2
- package/dist/lib/extension-specifier.d.ts +8 -1
- package/dist/lib/manifest-config.d.ts +3 -1
- package/dist/lib/manifest-old-spellings.d.ts +32 -9
- package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
- package/dist/lib/markdown/math.d.ts +1 -1
- package/dist/lib/markdown/typography.d.ts +1 -0
- package/dist/lib/page-size.d.ts +12 -4
- package/dist/lib/plugin-vendor.d.ts +6 -0
- package/dist/lib/presets.d.ts +2 -2
- package/dist/lib/root-tokens.d.ts +2 -1
- package/dist/lib/source-provider.d.ts +27 -0
- package/dist/lib/style-resolver.d.ts +2 -1
- package/dist/lib/version-changes.d.ts +22 -6
- package/dist/{manifest.schema-0jgj0jt1.json → manifest.schema-5cm13vr3.json} +215 -5
- package/dist/{new-jtk028rf.js → new-rmfyb7va.js} +22 -15
- package/dist/{plugins-bcbe7xs8.js → plugins-gs21xz5s.js} +2 -2
- package/dist/{plugins-zsm6wv79.js → plugins-tqv1s16f.js} +4 -4
- package/dist/{preflight-cs6mj1d6.js → preflight-bjyeeq0d.js} +9 -9
- package/dist/{preview-d1j1g4qf.js → preview-ke03fk5d.js} +9 -9
- package/dist/{publish-7yw4jyrt.js → publish-wpnz0qng.js} +9 -9
- package/dist/render.js +55 -13
- package/dist/schema/manifest.types.d.ts +45 -7
- package/dist/{source-provider-n7vehh6t.js → source-provider-3g3yrn1f.js} +6 -2
- package/dist/{source-provider-tgzet3j5.js → source-provider-azg9ywhb.js} +6 -2
- package/dist/test-helpers/vocabulary.d.ts +12 -0
- package/dist/{validate-rkcdnzhw.js → validate-zcwykb43.js} +9 -9
- package/package.json +1 -1
- /package/dist/{cli-y28j019d.js → cli-1dha1nxk.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
AUTO_SYNC_PUSH_INTERVAL_MINUTES,
|
|
7
7
|
BUILT_IN_TEMPLATE_IDS,
|
|
8
8
|
EXTENSION_KINDS,
|
|
9
|
+
EXTENSION_KIND_ALIASES,
|
|
9
10
|
FileTokenStore,
|
|
10
11
|
GDRIVE_HOST,
|
|
11
12
|
GITHUB_HOST,
|
|
@@ -42,6 +43,7 @@ import {
|
|
|
42
43
|
executeAndReport,
|
|
43
44
|
executeValidation,
|
|
44
45
|
exportVersionTree,
|
|
46
|
+
extensionKindFor,
|
|
45
47
|
extractUrlCredential,
|
|
46
48
|
extractVariables,
|
|
47
49
|
forgeKindForHost,
|
|
@@ -122,14 +124,16 @@ import {
|
|
|
122
124
|
substituteVariables,
|
|
123
125
|
syncProject,
|
|
124
126
|
testRemoteAccess
|
|
125
|
-
} from "./index-
|
|
127
|
+
} from "./index-z6vzj3s5.js";
|
|
126
128
|
import {
|
|
129
|
+
BUILT_IN_LOOKS,
|
|
127
130
|
DEFAULT_NPM_REGISTRY,
|
|
128
131
|
MANIFEST_FILENAMES,
|
|
129
132
|
PRESETS,
|
|
130
133
|
PRESET_IDS,
|
|
131
134
|
TARGETS,
|
|
132
135
|
TARGET_IDS,
|
|
136
|
+
addBuiltInStyleSet,
|
|
133
137
|
addExtension,
|
|
134
138
|
checkExtensionUpdates,
|
|
135
139
|
describeExtension,
|
|
@@ -152,9 +156,10 @@ import {
|
|
|
152
156
|
setExtensionEnabled,
|
|
153
157
|
updateExtensions,
|
|
154
158
|
validateProjectExtensions
|
|
155
|
-
} from "./index-
|
|
159
|
+
} from "./index-fntpr44x.js";
|
|
156
160
|
import {
|
|
157
161
|
BUNDLED_EXTENSIONS,
|
|
162
|
+
BUNDLED_EXTENSION_DETAILS,
|
|
158
163
|
EXTENSION_MANIFEST_FILENAME,
|
|
159
164
|
assertExtensionContained,
|
|
160
165
|
bundledExtension,
|
|
@@ -169,12 +174,12 @@ import {
|
|
|
169
174
|
pathEscapesFolder,
|
|
170
175
|
readExtensionMeta,
|
|
171
176
|
resolveExtension
|
|
172
|
-
} from "./index-
|
|
177
|
+
} from "./index-67g8f7r4.js";
|
|
173
178
|
import"./index-ht1bcqdd.js";
|
|
174
179
|
import {
|
|
175
180
|
BUILD_DIAGNOSTIC_CODES
|
|
176
|
-
} from "./index-
|
|
177
|
-
import"./index-
|
|
181
|
+
} from "./index-santcs4q.js";
|
|
182
|
+
import"./index-d9w3r89w.js";
|
|
178
183
|
import {
|
|
179
184
|
BuildError
|
|
180
185
|
} from "./index-tayzfr9c.js";
|
|
@@ -199,10 +204,11 @@ import {
|
|
|
199
204
|
revisionNameFrom,
|
|
200
205
|
switchBranch,
|
|
201
206
|
whenGitIdle
|
|
202
|
-
} from "./index-
|
|
207
|
+
} from "./index-kw4tbthz.js";
|
|
203
208
|
import {
|
|
204
|
-
EXTENSIONS_DIR
|
|
205
|
-
|
|
209
|
+
EXTENSIONS_DIR,
|
|
210
|
+
PLUGINS_DIR
|
|
211
|
+
} from "./index-g3te5ey1.js";
|
|
206
212
|
import {
|
|
207
213
|
capabilitiesFor,
|
|
208
214
|
detectProjectSource,
|
|
@@ -327,7 +333,22 @@ function insertDeclaration(root, name, value) {
|
|
|
327
333
|
root.raws.after = `
|
|
328
334
|
`;
|
|
329
335
|
}
|
|
336
|
+
function assertDeclarationValue(name, value) {
|
|
337
|
+
let single = false;
|
|
338
|
+
try {
|
|
339
|
+
const nodes = postcss.parse(`:root{${name}:${value}}`).nodes;
|
|
340
|
+
const rule = nodes[0];
|
|
341
|
+
single = nodes.length === 1 && rule?.type === "rule" && rule.nodes.length === 1 && rule.nodes[0].type === "decl";
|
|
342
|
+
} catch {
|
|
343
|
+
single = false;
|
|
344
|
+
}
|
|
345
|
+
if (!single)
|
|
346
|
+
throw new Error(`"${value}" can't be saved as ${name}: it is not one CSS value.`);
|
|
347
|
+
}
|
|
330
348
|
function applyTokenUpdates(sheets, target, updates) {
|
|
349
|
+
for (const { name, value } of updates)
|
|
350
|
+
if (value !== null)
|
|
351
|
+
assertDeclarationValue(name, value);
|
|
331
352
|
const roots = sheets.map((css) => postcss.parse(css));
|
|
332
353
|
const changed = new Set;
|
|
333
354
|
for (const { name, value } of updates) {
|
|
@@ -550,6 +571,7 @@ export {
|
|
|
550
571
|
extractVariables,
|
|
551
572
|
extractUrlCredential,
|
|
552
573
|
extensionStyleList,
|
|
574
|
+
extensionKindFor,
|
|
553
575
|
extensionEntry,
|
|
554
576
|
extensionCarries,
|
|
555
577
|
exportVersionTree,
|
|
@@ -585,6 +607,7 @@ export {
|
|
|
585
607
|
assertExtensionContained,
|
|
586
608
|
adoptFolder,
|
|
587
609
|
addExtension,
|
|
610
|
+
addBuiltInStyleSet,
|
|
588
611
|
VERSION_CHANGES_SHOWN,
|
|
589
612
|
TARGET_IDS,
|
|
590
613
|
TARGETS,
|
|
@@ -598,6 +621,7 @@ export {
|
|
|
598
621
|
PublishSelectionsStore,
|
|
599
622
|
PRESET_IDS,
|
|
600
623
|
PRESETS,
|
|
624
|
+
PLUGINS_DIR,
|
|
601
625
|
MAX_SEARCH_BYTES,
|
|
602
626
|
MANIFEST_FILENAMES,
|
|
603
627
|
HISTORY_PAGE_LIMIT,
|
|
@@ -608,13 +632,16 @@ export {
|
|
|
608
632
|
GDRIVE_HOST,
|
|
609
633
|
FileTokenStore,
|
|
610
634
|
EXTENSION_MANIFEST_FILENAME,
|
|
635
|
+
EXTENSION_KIND_ALIASES,
|
|
611
636
|
EXTENSION_KINDS,
|
|
612
637
|
EXTENSIONS_DIR,
|
|
613
638
|
DEFAULT_PRINT_OPTS,
|
|
614
639
|
DEFAULT_NPM_REGISTRY,
|
|
615
640
|
BuildError,
|
|
641
|
+
BUNDLED_EXTENSION_DETAILS,
|
|
616
642
|
BUNDLED_EXTENSIONS,
|
|
617
643
|
BUILT_IN_TEMPLATE_IDS,
|
|
644
|
+
BUILT_IN_LOOKS,
|
|
618
645
|
BUILD_DIAGNOSTIC_CODES,
|
|
619
646
|
AUTO_SYNC_PUSH_INTERVAL_MINUTES,
|
|
620
647
|
AUTO_SYNC_MIN_MINUTES,
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The options a check takes in its `checks:` entry (#443, #483): the numbers
|
|
3
|
+
* and the list it measures against. The preset and the publish target set
|
|
4
|
+
* them; a book overrides one in the same entry that sets the check's level.
|
|
5
|
+
*
|
|
6
|
+
* checks:
|
|
7
|
+
* pdf.print.ink-coverage: { maxTac: 300 }
|
|
8
|
+
* pdf.print.image-resolution: { level: error, minImageResolution: 200 }
|
|
9
|
+
*
|
|
10
|
+
* Each option lands at ONE place in the resolved config, `at`, which is what
|
|
11
|
+
* the check reads (and, for `maxTac`, what the PDF/X conversion holds the ink
|
|
12
|
+
* to). `at` is also how a 0.11.22 manifest spelled the option
|
|
13
|
+
* (`ink.maxTac`, `validate.pdf.minImageResolution`, `page.tolerance`), so
|
|
14
|
+
* manifest-old-spellings.ts translates the old keys from this same table.
|
|
15
|
+
*
|
|
16
|
+
* No filesystem or check-registry imports: manifest.ts resolves with it, and
|
|
17
|
+
* the Book setup writers use {@link setCheckOption}.
|
|
18
|
+
*/
|
|
19
|
+
import { type Document } from "yaml";
|
|
20
|
+
import type { CheckLevelInput, ResolvedConfig } from "../schema/manifest.types";
|
|
21
|
+
/** What an option's value is: points/bytes/DPI/a count, a `{ min, max }` range, or a list of file patterns. */
|
|
22
|
+
type OptionKind = "number" | "range" | "patterns";
|
|
23
|
+
interface CheckOption {
|
|
24
|
+
/** Where the value lands in the resolved config, and the 0.11.22 manifest spelling. */
|
|
25
|
+
at: string;
|
|
26
|
+
kind: OptionKind;
|
|
27
|
+
}
|
|
28
|
+
/** Check id -> option name -> where it lands. */
|
|
29
|
+
export declare const CHECK_OPTIONS: Readonly<Record<string, Readonly<Record<string, CheckOption>>>>;
|
|
30
|
+
/** The check id and option name a 0.11.22 spelling (`ink.maxTac`) moved to, if it is one. */
|
|
31
|
+
export declare function optionForOldSpelling(at: string): {
|
|
32
|
+
id: string;
|
|
33
|
+
option: string;
|
|
34
|
+
} | undefined;
|
|
35
|
+
/** A `checks:` level as a manifest may write it: `off`, `on`, `info`, `warn` (`warning`), `error`, or a boolean. */
|
|
36
|
+
export declare function isCheckLevelInput(value: unknown): value is CheckLevelInput;
|
|
37
|
+
/**
|
|
38
|
+
* A 0.11.22 threshold (`validate.heuristics.maxDecorativeLayers`) read as
|
|
39
|
+
* the option it became, or undefined when the key was never a threshold.
|
|
40
|
+
* 0.11.22 passed any value through, and a check given one it could not use
|
|
41
|
+
* measured nothing, so a value the option cannot take is NOT an error here:
|
|
42
|
+
* `mustBe` says what it should have been and the caller reports it and
|
|
43
|
+
* ignores it, and a book that built in 0.11.22 still builds. A range keeps
|
|
44
|
+
* whichever of `min` and `max` are numbers, as 0.11.22's merge did.
|
|
45
|
+
*/
|
|
46
|
+
export declare function readOldThreshold(at: string, value: unknown): {
|
|
47
|
+
id: string;
|
|
48
|
+
option: string;
|
|
49
|
+
value?: unknown;
|
|
50
|
+
mustBe?: string;
|
|
51
|
+
} | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Read the options of one `checks:` entry (every key but `level`). A key the
|
|
54
|
+
* check does not take is a usage error naming the ones it does, so a typo
|
|
55
|
+
* never silently keeps the preset's number. A `null` value is left unset.
|
|
56
|
+
*/
|
|
57
|
+
export declare function readCheckOptions(id: string, entry: Record<string, unknown>): Record<string, unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Write read options into a resolved config, over the preset's and the
|
|
60
|
+
* target's values. A range merges key by key, so `{ max: 4000 }` keeps the
|
|
61
|
+
* preset's `min`; a list replaces the preset's whole.
|
|
62
|
+
*/
|
|
63
|
+
export declare function applyCheckOptions(config: ResolvedConfig, options: Record<string, Record<string, unknown>>): void;
|
|
64
|
+
/**
|
|
65
|
+
* Set one option in a manifest Document, keeping the entry's level: a bare
|
|
66
|
+
* level (`warn`) becomes `{ level: warn, <option>: value }`. Used where Book
|
|
67
|
+
* setup and `gutterpress new` write a check's option.
|
|
68
|
+
*/
|
|
69
|
+
export declare function setCheckOption(doc: Document, id: string, option: string, value: unknown): void;
|
|
70
|
+
export {};
|
|
@@ -4,7 +4,7 @@ import type { ResolvedExtensionConfig } from "../schema/manifest.types.ts";
|
|
|
4
4
|
/** The folder (relative to the project root) a book's extensions live under:
|
|
5
5
|
* vendored npm copies in `extensions/npm/`, zip and URL imports beside them
|
|
6
6
|
* (extension-import.ts). Path entries elsewhere are never moved. */
|
|
7
|
-
export { EXTENSIONS_DIR } from "./plugin-vendor.ts";
|
|
7
|
+
export { EXTENSIONS_DIR, PLUGINS_DIR } from "./plugin-vendor.ts";
|
|
8
8
|
/** How an `extensions:` entry resolves — the form of its specifier decides. */
|
|
9
9
|
export type ExtensionSourceKind = "bundled" | "path" | "npm";
|
|
10
10
|
/** One configured extension, as surfaced to the CLI and the desktop. */
|
|
@@ -194,6 +194,21 @@ export interface BundledExtensionInfo {
|
|
|
194
194
|
}
|
|
195
195
|
/** The bundled extensions, in table order. */
|
|
196
196
|
export declare function listBundledExtensions(): BundledExtensionInfo[];
|
|
197
|
+
/** The built-in looks' names (the bundled extensions that carry a stylesheet), in table order. */
|
|
198
|
+
export declare const BUILT_IN_LOOKS: readonly string[];
|
|
199
|
+
/**
|
|
200
|
+
* Make an editable copy of a built-in look (0.11.22's, restored in #482): its
|
|
201
|
+
* stylesheet and a package.json land in `extensions/<id>/`, the author's own
|
|
202
|
+
* files from then on, and the book lists the copy as `./extensions/<id>` — a
|
|
203
|
+
* plain path extension, loaded and built like any folder the author owns.
|
|
204
|
+
*
|
|
205
|
+
* A book that lists the built-in by name gets the copy in that entry's place
|
|
206
|
+
* (on or off as it was), so the look is not listed twice and the cascade
|
|
207
|
+
* order holds; otherwise the copy is added at the end. Idempotent: a folder
|
|
208
|
+
* already there is kept as it is — the author's edits survive — and only
|
|
209
|
+
* (re-)referenced.
|
|
210
|
+
*/
|
|
211
|
+
export declare function addBuiltInStyleSet(projectDir: string, id: string): Promise<ProjectExtensionEntry>;
|
|
197
212
|
/** A folder name under `extensions/` not yet taken: `<slug>`, `<slug>-2`, … */
|
|
198
213
|
export declare function uniqueExtensionId(projectDir: string, base: string): Promise<string>;
|
|
199
214
|
/**
|
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
export type ExtensionKind = "plugin" | "look";
|
|
3
3
|
/** The kinds `--kind` accepts, for CLI help text and pickers. */
|
|
4
4
|
export declare const EXTENSION_KINDS: readonly ["plugin", "look"];
|
|
5
|
+
/**
|
|
6
|
+
* Older names for a kind, read wherever a kind is given (`scaffoldExtension`,
|
|
7
|
+
* `gutterpress new --kind`) and never offered: 0.11.22 called a look a
|
|
8
|
+
* `theme` (#483). Kept apart from {@link EXTENSION_KINDS} so help text and
|
|
9
|
+
* pickers keep showing one word per kind.
|
|
10
|
+
*/
|
|
11
|
+
export declare const EXTENSION_KIND_ALIASES: {
|
|
12
|
+
readonly theme: "look";
|
|
13
|
+
};
|
|
14
|
+
/** An older name {@link EXTENSION_KIND_ALIASES} reads. */
|
|
15
|
+
export type ExtensionKindAlias = keyof typeof EXTENSION_KIND_ALIASES;
|
|
16
|
+
/** The kind a word names — a kind, or an older name for one — or undefined. */
|
|
17
|
+
export declare function extensionKindFor(word: string): ExtensionKind | undefined;
|
|
5
18
|
/**
|
|
6
19
|
* The class/property prefix a scaffolded extension is FORBIDDEN to take.
|
|
7
20
|
* `gp-` is Gutterpress core's own vocabulary (CLAUDE.md §6); an extension
|
|
@@ -13,8 +26,8 @@ export declare const RESERVED_PREFIX = "gp-";
|
|
|
13
26
|
export interface ScaffoldExtensionOptions {
|
|
14
27
|
/** Human-friendly package name, e.g. "Field Notes". Required. */
|
|
15
28
|
name: string;
|
|
16
|
-
/** Which starter to create. Required. */
|
|
17
|
-
kind: ExtensionKind;
|
|
29
|
+
/** Which starter to create. Required. `theme` (0.11.22's word) makes a look. */
|
|
30
|
+
kind: ExtensionKind | ExtensionKindAlias;
|
|
18
31
|
/** Absolute path to the PARENT directory the folder is created in. */
|
|
19
32
|
parentDir: string;
|
|
20
33
|
/** Folder name under `parentDir`. Defaults to a slug of `name`. */
|
|
@@ -20,7 +20,14 @@ export interface BundledExtension {
|
|
|
20
20
|
/** A look's stylesheet. Absent for a markdown feature. */
|
|
21
21
|
css?: string;
|
|
22
22
|
}
|
|
23
|
-
export declare const
|
|
23
|
+
export declare const BUNDLED_EXTENSION_DETAILS: readonly BundledExtension[];
|
|
24
|
+
/**
|
|
25
|
+
* The bundled names, in table order: the shape this export had in 0.11.22,
|
|
26
|
+
* so `BUNDLED_EXTENSIONS.includes(name)` still answers "is this bundled?".
|
|
27
|
+
* Each one's label, description and stylesheet are in
|
|
28
|
+
* {@link BUNDLED_EXTENSION_DETAILS}.
|
|
29
|
+
*/
|
|
30
|
+
export declare const BUNDLED_EXTENSIONS: readonly string[];
|
|
24
31
|
export declare function bundledExtension(name: string): BundledExtension | undefined;
|
|
25
32
|
export declare function isBundledExtension(name: string): boolean;
|
|
26
33
|
/** `./x`, `../x`, `/x`, or a Windows drive path (`C:\x`). Nothing else is a path. */
|
|
@@ -17,7 +17,9 @@ export interface ProjectConfigFields {
|
|
|
17
17
|
* Only the keys present in `updates` are written; everything else is left
|
|
18
18
|
* untouched (so unrelated comments + sections survive). `sourceFiles: null`
|
|
19
19
|
* deletes the `chapters` entry (back to "all chapter files"). Either way an
|
|
20
|
-
* older book's `source.files` is taken out, so the list has one spelling
|
|
20
|
+
* older book's `source.files` is taken out, so the list has one spelling, and
|
|
21
|
+
* the thresholds it spells the 0.11.22 way are written as their checks'
|
|
22
|
+
* options (`rewriteOldThresholds`).
|
|
21
23
|
*/
|
|
22
24
|
export declare function setManifestFields(projectDir: string, updates: ProjectConfigFields): Promise<ProjectConfigFields>;
|
|
23
25
|
/**
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* The manifest spellings 0.11.23 replaced, read for this release only so a
|
|
3
3
|
* book written for 0.11.22 still builds. Every old key found is translated
|
|
4
4
|
* to its new spelling (or dropped, when nothing replaces it) and named in ONE
|
|
5
|
-
* notice.
|
|
6
|
-
*
|
|
5
|
+
* notice. Book setup writes the new spelling of a threshold when it saves
|
|
6
|
+
* (`rewriteOldThresholds`). Delete this module, its call in
|
|
7
|
+
* `loadManifestWithPath` and the two calls of `rewriteOldThresholds`
|
|
8
|
+
* (manifest-config.ts, page-size.ts) in the release after 0.11.23.
|
|
7
9
|
*
|
|
8
10
|
* source.files -> chapters
|
|
9
11
|
* validate.checks, lint.rules -> checks (off | on | info | warn | error)
|
|
@@ -14,17 +16,27 @@
|
|
|
14
16
|
* validate.pdf.requireBookmarks,
|
|
15
17
|
* validate.pdf.requireTocLinks,
|
|
16
18
|
* validate.pdf.requireBleed,
|
|
17
|
-
* validate.pdf.forbidTransparency -> the matching check, on or off
|
|
19
|
+
* validate.pdf.forbidTransparency -> the matching check, on or off; a level
|
|
20
|
+
* the same book set for it is kept
|
|
21
|
+
* ink.*, page.tolerance and the
|
|
22
|
+
* validate.assets / pdf /
|
|
23
|
+
* heuristics thresholds -> an option of their check:
|
|
24
|
+
* checks: { <id>: { <option>: value } }
|
|
25
|
+
* (lib/check-options.ts)
|
|
18
26
|
* validate.source.<tool>: <path> -> dropped: the config file is found by
|
|
19
27
|
* its usual name in the book's folder
|
|
20
28
|
* or a folder above it
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
29
|
+
* validate.enabled, lint.configPath
|
|
30
|
+
* and the keys 0.11.22 already
|
|
31
|
+
* ignored -> dropped
|
|
32
|
+
*
|
|
33
|
+
* Nothing read from an old spelling can stop a book from building: 0.11.22
|
|
34
|
+
* passed any value through, so a threshold, a severity or a rule level it
|
|
35
|
+
* could not have used (`maxDecorativeLayers: many`, `severity: critical`) is
|
|
36
|
+
* named in the notice and ignored. The new spelling, written directly, is
|
|
37
|
+
* checked strictly (`resolveConfig`).
|
|
27
38
|
*/
|
|
39
|
+
import { type Document } from "yaml";
|
|
28
40
|
import type { CheckLevelInput, GutterpressManifest } from "../schema/manifest.types";
|
|
29
41
|
type OldCheckEntry = boolean | {
|
|
30
42
|
enabled?: boolean;
|
|
@@ -61,4 +73,15 @@ export interface OldSpellings {
|
|
|
61
73
|
* removed before 0.11.23 with an actionable error.
|
|
62
74
|
*/
|
|
63
75
|
export declare function readOldSpellings(raw: GutterpressManifest & OldSpellings): GutterpressManifest;
|
|
76
|
+
/**
|
|
77
|
+
* Book setup's save: move every 0.11.22 threshold key in a manifest Document
|
|
78
|
+
* (`ink.maxTac`, `validate.pdf.minImageResolution`, `page.tolerance`, …) to
|
|
79
|
+
* its check's option, the way `setManifestFields` moves `source.files` to
|
|
80
|
+
* `chapters`. An option the new spelling already sets keeps its value; a
|
|
81
|
+
* block left empty goes. A value the option cannot take stays where it is,
|
|
82
|
+
* as written: moved, the new spelling's strict check would stop the book
|
|
83
|
+
* from building, and left, it is named and ignored at load. Every other key
|
|
84
|
+
* stays as written.
|
|
85
|
+
*/
|
|
86
|
+
export declare function rewriteOldThresholds(doc: Document): void;
|
|
64
87
|
export {};
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
* carrying gp-left could start shifting; that is standards-tracking per
|
|
152
152
|
* CLAUDE.md ("Chrome wins once it ships"), not a bug in the author's book.
|
|
153
153
|
*/
|
|
154
|
-
export declare const GUTTERPRESS_CSS = "\n/* gp-* author image/block vocabulary. One vocabulary, gp-* only \u2014 the\n pre-vocabulary utility names (.center/.float-left/.float-right/\n .full-width/.full-bleed) were REMOVED when gp-* shipped; books rename\n the classes in their markdown (see the migration note). Source ORDER is\n the contract \u2014 see the doctrine comment above. */\n\n/* flow positions */\n.gp-left {\n float: left;\n margin: 0 var(--gp-gap, 1em) var(--gp-gap, 1em) 0;\n max-width: 50%;\n}\n.gp-right {\n float: right;\n margin: 0 0 var(--gp-gap, 1em) var(--gp-gap, 1em);\n max-width: 50%;\n}\n.gp-center {\n display: block;\n float: none;\n margin-left: auto;\n margin-right: auto;\n max-width: 100%;\n}\n.gp-full {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n@page gp-full-bleed { margin-left: 0; margin-right: 0; }\n.gp-bleed {\n display: block;\n float: none;\n break-before: page;\n page: gp-full-bleed;\n max-width: none;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n/* sizes \u2014 AFTER the flow positions so max-width:100% lifts the floats' 50%\n cap at equal specificity */\n.gp-size-10 { width: 10%; max-width: 100%; }\n.gp-size-20 { width: 20%; max-width: 100%; }\n.gp-size-30 { width: 30%; max-width: 100%; }\n.gp-size-40 { width: 40%; max-width: 100%; }\n.gp-size-50 { width: 50%; max-width: 100%; }\n.gp-size-60 { width: 60%; max-width: 100%; }\n.gp-size-70 { width: 70%; max-width: 100%; }\n.gp-size-80 { width: 80%; max-width: 100%; }\n.gp-size-90 { width: 90%; max-width: 100%; }\n\n/* float clearance presets \u2014 consumed by var(--gp-gap) in the float rules\n above and by .gp-shape's shape-margin below; --gp-gap itself is\n author-settable CSS */\n.gp-tight { --gp-gap: 0.5em; }\n.gp-loose { --gp-gap: 2em; }\n\n/* column runs \u2014 plain CSS Multi-column, emitted by the core @columns marker\n (markers.js): @columns [1-5] ... @end-columns is the ONE way to lay\n content out in columns, and @column-break moves to the next column.\n The classes below are the CSS that marker emits, not author vocabulary.\n\n Permanent vocabulary, not a shim: Chromium implements multicol natively\n and these rules are the standard properties verbatim, so there is no\n spec gap here to remove later. Deliberately minimal \u2014 column-fill is\n NOT set (the CSS initial balance applies).\n Themes style a run through two tokens instead of writing column rules:\n --gp-column-gap default 1.5em\n --gp-column-rule default none (any column-rule shorthand value)\n Both hooks sit at zero specificity (:where), so any author rule wins.\n .gp-columns is two columns on its own; a count class (bare @columns\n emits gp-columns-2) wins because it comes later at the same specificity. */\n:where(.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5) {\n column-gap: var(--gp-column-gap, 1.5em);\n column-rule: var(--gp-column-rule, none);\n}\n.gp-columns { columns: 2; }\n.gp-columns-1 { columns: 1; }\n.gp-columns-2 { columns: 2; }\n.gp-columns-3 { columns: 3; }\n.gp-columns-4 { columns: 4; }\n.gp-columns-5 { columns: 5; }\n\n/* fragmentation controls \u2014 generic pagination utilities for any element,\n independent of the column vocabulary above (a book reached for\n these just as often outside a multicol run: keeping a card whole,\n forcing a section to start a fresh page). Standard properties only \u2014\n this project is Chromium-only (CLAUDE.md), so there are no legacy\n page-break-* twins to also emit. One name each. */\n.gp-no-break { break-inside: avoid; }\n.gp-break-before { break-before: page; }\n\n/* shape wrap \u2014 text follows the image's alpha silhouette instead of its\n rectangular box. shape-outside only applies to floats, so this is inert\n without .gp-left/.gp-right (and under .gp-pin, which un-floats). The\n shape URL cannot be written in CSS (url() contexts can't read attr()),\n so the image renderer rule (images.ts) mirrors the src into an inline\n --gp-shape:url(...) custom property whenever it sees this class --\n authors only ever type the class. threshold 0.2 ignores near-transparent\n anti-aliasing halos; shape-margin shares the float-gap vocabulary. */\nimg.gp-shape {\n shape-outside: var(--gp-shape);\n shape-image-threshold: 0.2;\n shape-margin: var(--gp-gap, 1em);\n}\n\n/* pin \u2014 within the nearest positioned ancestor (.page/.spread, rule above).\n The four insets are the pin box: 0 (the text block's edge) unless an\n engine set --gp-pin-<edge> on the page root for an edge a pin uses (the\n art-safe line). Non-auto insets and the explicit centers are\n load-bearing; see doctrine comment. */\n.gp-pin {\n position: absolute;\n top: var(--gp-pin-top, 0px);\n right: var(--gp-pin-right, 0px);\n bottom: var(--gp-pin-bottom, 0px);\n left: var(--gp-pin-left, 0px);\n align-self: center;\n justify-self: center;\n margin: 0;\n max-width: 100%;\n}\n\n/* pin edge modifiers \u2014 AFTER .gp-pin to beat its center defaults;\n justify-self is inert on in-flow floats, so gp-left/gp-right safely do\n double duty as flow float + pin edge */\n.gp-top { align-self: start; }\n.gp-bottom { align-self: end; }\n.gp-left { justify-self: start; }\n.gp-right { justify-self: end; }\n\n/* the escape hatch \u2014 the paper's edge, past the printer's safe area: the\n pin box loses its art-safe insets. Set on the pin itself, so it beats the\n values the page root hands down. */\n.gp-pin.gp-flush {\n --gp-pin-top: 0px;\n --gp-pin-right: 0px;\n --gp-pin-bottom: 0px;\n --gp-pin-left: 0px;\n}\n\n/* wrapper-margin neutralization (same pattern and rationale as the\n .gp-bleed paragraph-margin note in the doctrine comment; for pin, the\n emptied paragraph would otherwise leave a phantom margin gap in flow) */\n:where(p:has(> img.gp-bleed:only-child)) { margin: 0; }\n:where(p:has(> img.gp-pin:only-child)) { margin: 0; }\n\n/* depth \u2014 a named ladder for z-index, so books stop hand-tuning bare\n integers. A real book measured 21 z-index declarations using only four\n distinct values (-1, 0, 1, 2), each written literally at its use site.\n The custom properties are the author-settable surface (a book needing a\n deeper stack raises them once); the classes are the shorthand.\n\n NOT named \"layer\": CSS Paged Media 3 \u00A73.1 already defines \"page layers\"\n (page background, canvas, borders, contents, margin boxes) and those are\n parts of the PAGE BOX, not a z-ladder for content. Reusing the word for a\n different concept would collide with the spec vocabulary this project\n tracks. The pin EDGE modifiers already own .gp-top/.gp-bottom, so the\n ladder avoids those words too.\n\n .gp-behind is the one that earns its place: it puts a pinned image UNDER\n the page's text, which is otherwise impossible to express without a bare\n negative z-index. \"Above\" needs no class \u2014 an out-of-flow pin already\n paints above in-flow content.\n\n Two things silently defeat .gp-behind, neither visible at the use site:\n - a stacking context on the .page/.spread ancestor (z-index, isolation,\n opacity, filter, transform on it traps the negative layer inside).\n Core keeps .page/.spread at 'position: relative; z-index: auto'\n precisely so they are not stacking contexts.\n - a clipping ancestor (overflow other than visible) \u2014 but only where\n the art actually overhangs that ancestor's clip box on a clipped\n axis: the overhang is cut off, the same mechanism that clips a\n .gp-bleed plate back to the wrapper's width. Clipping never reorders\n layers \u2014 within-bounds art under a clipping .page prints whole and\n still behind (measured; see the build audit's comment in\n engine/compiler/build.ts), and a static wrapper's overflow never\n binds an abspos .gp-pin at all.\n The build-time engine.layer.trapped audit reports both against the live\n ancestor chain. printsafe/page-containment is only an early source hint for\n declarations written directly on .page/.spread. */\n:root {\n --gp-z-behind: -1;\n --gp-z-base: 0;\n --gp-z-raised: 1;\n --gp-z-front: 2;\n}\n.gp-behind { z-index: var(--gp-z-behind); }\n.gp-base { z-index: var(--gp-z-base); }\n.gp-raised { z-index: var(--gp-z-raised); }\n.gp-front { z-index: var(--gp-z-front); }\n\n/* GFM-style alert/callout boxes (#237) \u2014 the DOM gfm-alerts.ts emits from\n \"> [!TYPE]\" blockquote syntax when a project opts into the bundled\n gutterpress-gfm-alerts feature (BUILTIN_OPTIONAL_PLUGINS, renderer.ts).\n The plugin is optional and inert by default; these rules are equally\n inert wherever the classes never appear, exactly like every other\n utility above, so shipping them costs nothing to a book that has not\n turned the feature on.\n\n This is authored-COMPONENT vocabulary, not the @marker structural family\n (markers.js/MARKER_CSS) \u2014 CLAUDE.md \u00A76 splits the two core CSS blocks by\n ROLE, and an author-facing box an author invokes via inline syntax is the\n same role as every other gp-* utility here, not page/chapter/section DOM.\n\n Deliberately minimal (CLAUDE.md \"thin over capable\" / the issue's own\n \"a rule and a label\"): a left border plus a bold label, :where()'d to\n zero specificity so a theme's own (unlayered) rule for any of these\n classes wins outright regardless of selector weight \u2014 see the\n cascade-layers note atop this file. Five semantic accent colors (the same\n NOTE/TIP/IMPORTANT/WARNING/CAUTION hues GitHub's own alerts use \u2014 a\n long-established, non-proprietary convention, not DC branding) are\n exposed as :root custom properties, the same author-settable-surface\n pattern as the --gp-z-* ladder above: a book retints every alert of one\n type by overriding a single property, no specificity fight required.\n --gp-alert-color cascades from the type modifier down to .gp-alert-title\n through ordinary CSS inheritance (the title is always a DOM descendant of\n the box), so it is set in exactly five places, not ten. */\n:root {\n --gp-alert-note-color: #0969da;\n --gp-alert-tip-color: #1a7f37;\n --gp-alert-important-color: #8250df;\n --gp-alert-warning-color: #9a6700;\n --gp-alert-caution-color: #cf222e;\n}\n:where(.gp-alert) {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 0.25em solid var(--gp-alert-color, currentColor);\n}\n:where(.gp-alert-title) {\n margin: 0 0 0.5em;\n font-weight: bold;\n color: var(--gp-alert-color, inherit);\n}\n:where(.gp-alert-note) { --gp-alert-color: var(--gp-alert-note-color); }\n:where(.gp-alert-tip) { --gp-alert-color: var(--gp-alert-tip-color); }\n:where(.gp-alert-important) { --gp-alert-color: var(--gp-alert-important-color); }\n:where(.gp-alert-warning) { --gp-alert-color: var(--gp-alert-warning-color); }\n:where(.gp-alert-caution) { --gp-alert-color: var(--gp-alert-caution-color); }\n\n/* Math (the bundled gutterpress-math feature, math.ts): MathJax's own rules\n for the <mjx-container> SVG output it emits, from its SVG output jax's\n stylesheet, less the ones for its interactive menu and tooltips. Inert in\n a book without formulas. */\nmjx-container[jax=\"SVG\"] { direction: ltr; }\nmjx-container[jax=\"SVG\"] > svg { overflow: visible; min-height: 1px; min-width: 1px; }\nmjx-container[jax=\"SVG\"] > svg a { fill: blue; stroke: blue; }\nmjx-container[jax=\"SVG\"][display=\"true\"] { display: block; text-align: center; margin: 1em 0; }\nmjx-container[jax=\"SVG\"][display=\"true\"][width=\"full\"] { display: flex; }\nmjx-container[jax=\"SVG\"][justify=\"left\"] { text-align: left; }\nmjx-container[jax=\"SVG\"][justify=\"right\"] { text-align: right; }\nmjx-container[jax=\"SVG\"] path[data-c], mjx-container[jax=\"SVG\"] use[data-c] { stroke-width: 3; }\nmjx-assistive-mml {\n position: absolute !important;\n top: 0px; left: 0px;\n clip: rect(1px, 1px, 1px, 1px);\n padding: 1px 0px 0px 0px !important;\n border: 0px !important;\n display: block !important;\n width: auto !important;\n overflow: hidden !important;\n user-select: none;\n}\nmjx-assistive-mml[display=\"block\"] { width: 100% !important; }\ng[data-mml-node=\"merror\"] > g { fill: red; stroke: red; }\ng[data-mml-node=\"merror\"] > rect[data-background] { fill: yellow; stroke: none; }\ng[data-mml-node=\"mtable\"] > line[data-line], svg[data-table] > g > line[data-line] { stroke-width: 70px; fill: none; }\ng[data-mml-node=\"mtable\"] > rect[data-frame], svg[data-table] > g > rect[data-frame] { stroke-width: 70px; fill: none; }\ng[data-mml-node=\"mtable\"] > .mjx-dashed, svg[data-table] > g > .mjx-dashed { stroke-dasharray: 140; }\ng[data-mml-node=\"mtable\"] > .mjx-dotted, svg[data-table] > g > .mjx-dotted { stroke-linecap: round; stroke-dasharray: 0,140; }\ng[data-mml-node=\"mtable\"] > g > svg { overflow: visible; }\n";
|
|
154
|
+
export declare const GUTTERPRESS_CSS = "\n/* gp-* author image/block vocabulary. One vocabulary, gp-* only \u2014 the\n pre-vocabulary utility names (.center/.float-left/.float-right/\n .full-width/.full-bleed) were REMOVED when gp-* shipped; books rename\n the classes in their markdown (see the migration note). Source ORDER is\n the contract \u2014 see the doctrine comment above. */\n\n/* flow positions */\n.gp-left {\n float: left;\n margin: 0 var(--gp-gap, 1em) var(--gp-gap, 1em) 0;\n max-width: 50%;\n}\n.gp-right {\n float: right;\n margin: 0 0 var(--gp-gap, 1em) var(--gp-gap, 1em);\n max-width: 50%;\n}\n.gp-center {\n display: block;\n float: none;\n margin-left: auto;\n margin-right: auto;\n max-width: 100%;\n}\n.gp-full {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n@page gp-full-bleed { margin-left: 0; margin-right: 0; }\n.gp-bleed {\n display: block;\n float: none;\n break-before: page;\n page: gp-full-bleed;\n max-width: none;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n/* sizes \u2014 AFTER the flow positions so max-width:100% lifts the floats' 50%\n cap at equal specificity */\n.gp-size-10 { width: 10%; max-width: 100%; }\n.gp-size-20 { width: 20%; max-width: 100%; }\n.gp-size-30 { width: 30%; max-width: 100%; }\n.gp-size-40 { width: 40%; max-width: 100%; }\n.gp-size-50 { width: 50%; max-width: 100%; }\n.gp-size-60 { width: 60%; max-width: 100%; }\n.gp-size-70 { width: 70%; max-width: 100%; }\n.gp-size-80 { width: 80%; max-width: 100%; }\n.gp-size-90 { width: 90%; max-width: 100%; }\n\n/* float clearance presets \u2014 consumed by var(--gp-gap) in the float rules\n above and by .gp-shape's shape-margin below; --gp-gap itself is\n author-settable CSS */\n.gp-tight { --gp-gap: 0.5em; }\n.gp-loose { --gp-gap: 2em; }\n\n/* column runs \u2014 plain CSS Multi-column, emitted by the core @columns marker\n (markers.js): @columns [1-5] ... @end-columns is the ONE way to lay\n content out in columns, and @column-break moves to the next column.\n The classes below are the CSS that marker emits, not author vocabulary.\n\n Permanent vocabulary, not a shim: Chromium implements multicol natively\n and these rules are the standard properties verbatim, so there is no\n spec gap here to remove later. Deliberately minimal \u2014 column-fill is\n NOT set (the CSS initial balance applies).\n Themes style a run through two tokens instead of writing column rules:\n --gp-column-gap default 1.5em\n --gp-column-rule default none (any column-rule shorthand value)\n Both hooks sit at zero specificity (:where), so any author rule wins.\n .gp-columns is two columns on its own; a count class (bare @columns\n emits gp-columns-2) wins because it comes later at the same specificity. */\n:where(.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5) {\n column-gap: var(--gp-column-gap, 1.5em);\n column-rule: var(--gp-column-rule, none);\n}\n.gp-columns { columns: 2; }\n.gp-columns-1 { columns: 1; }\n.gp-columns-2 { columns: 2; }\n.gp-columns-3 { columns: 3; }\n.gp-columns-4 { columns: 4; }\n.gp-columns-5 { columns: 5; }\n\n/* fragmentation controls \u2014 generic pagination utilities for any element,\n independent of the column vocabulary above (a book reached for\n these just as often outside a multicol run: keeping a card whole,\n forcing a section to start a fresh page). Standard properties only \u2014\n this project is Chromium-only (CLAUDE.md), so there are no legacy\n page-break-* twins to also emit. One name each. */\n.gp-no-break { break-inside: avoid; }\n.gp-break-before { break-before: page; }\n\n/* shape wrap \u2014 text follows the image's alpha silhouette instead of its\n rectangular box. shape-outside only applies to floats, so this is inert\n without .gp-left/.gp-right (and under .gp-pin, which un-floats). The\n shape URL cannot be written in CSS (url() contexts can't read attr()),\n so the image renderer rule (images.ts) mirrors the src into an inline\n --gp-shape:url(...) custom property whenever it sees this class --\n authors only ever type the class. threshold 0.2 ignores near-transparent\n anti-aliasing halos; shape-margin shares the float-gap vocabulary. */\nimg.gp-shape {\n shape-outside: var(--gp-shape);\n shape-image-threshold: 0.2;\n shape-margin: var(--gp-gap, 1em);\n}\n\n/* pin \u2014 within the nearest positioned ancestor (.page/.spread, rule above).\n The four insets are the pin box: 0 (the text block's edge) unless an\n engine set --gp-pin-<edge> on the page root for an edge a pin uses (the\n art-safe line). Non-auto insets and the explicit centers are\n load-bearing; see doctrine comment. */\n.gp-pin {\n position: absolute;\n top: var(--gp-pin-top, 0px);\n right: var(--gp-pin-right, 0px);\n bottom: var(--gp-pin-bottom, 0px);\n left: var(--gp-pin-left, 0px);\n align-self: center;\n justify-self: center;\n margin: 0;\n max-width: 100%;\n}\n\n/* pin edge modifiers \u2014 AFTER .gp-pin to beat its center defaults;\n justify-self is inert on in-flow floats, so gp-left/gp-right safely do\n double duty as flow float + pin edge */\n.gp-top { align-self: start; }\n.gp-bottom { align-self: end; }\n.gp-left { justify-self: start; }\n.gp-right { justify-self: end; }\n\n/* the escape hatch \u2014 the paper's edge, past the printer's safe area: the\n pin box loses its art-safe insets. Set on the pin itself, so it beats the\n values the page root hands down. */\n.gp-pin.gp-flush {\n --gp-pin-top: 0px;\n --gp-pin-right: 0px;\n --gp-pin-bottom: 0px;\n --gp-pin-left: 0px;\n}\n\n/* wrapper-margin neutralization (same pattern and rationale as the\n .gp-bleed paragraph-margin note in the doctrine comment; for pin, the\n emptied paragraph would otherwise leave a phantom margin gap in flow) */\n:where(p:has(> img.gp-bleed:only-child)) { margin: 0; }\n:where(p:has(> img.gp-pin:only-child)) { margin: 0; }\n\n/* depth \u2014 a named ladder for z-index, so books stop hand-tuning bare\n integers. A real book measured 21 z-index declarations using only four\n distinct values (-1, 0, 1, 2), each written literally at its use site.\n The custom properties are the author-settable surface (a book needing a\n deeper stack raises them once); the classes are the shorthand.\n\n NOT named \"layer\": CSS Paged Media 3 \u00A73.1 already defines \"page layers\"\n (page background, canvas, borders, contents, margin boxes) and those are\n parts of the PAGE BOX, not a z-ladder for content. Reusing the word for a\n different concept would collide with the spec vocabulary this project\n tracks. The pin EDGE modifiers already own .gp-top/.gp-bottom, so the\n ladder avoids those words too.\n\n .gp-behind is the one that earns its place: it puts a pinned image UNDER\n the page's text, which is otherwise impossible to express without a bare\n negative z-index. \"Above\" needs no class \u2014 an out-of-flow pin already\n paints above in-flow content.\n\n Two things silently defeat .gp-behind, neither visible at the use site:\n - a stacking context on the .page/.spread ancestor (z-index, isolation,\n opacity, filter, transform on it traps the negative layer inside).\n Core keeps .page/.spread at 'position: relative; z-index: auto'\n precisely so they are not stacking contexts.\n - a clipping ancestor (overflow other than visible) \u2014 but only where\n the art actually overhangs that ancestor's clip box on a clipped\n axis: the overhang is cut off, the same mechanism that clips a\n .gp-bleed plate back to the wrapper's width. Clipping never reorders\n layers \u2014 within-bounds art under a clipping .page prints whole and\n still behind (measured; see the build audit's comment in\n engine/compiler/build.ts), and a static wrapper's overflow never\n binds an abspos .gp-pin at all.\n The build-time engine.layer.trapped audit reports both against the live\n ancestor chain. printsafe/page-containment is only an early source hint for\n declarations written directly on .page/.spread. */\n:root {\n --gp-z-behind: -1;\n --gp-z-base: 0;\n --gp-z-raised: 1;\n --gp-z-front: 2;\n}\n.gp-behind { z-index: var(--gp-z-behind); }\n.gp-base { z-index: var(--gp-z-base); }\n.gp-raised { z-index: var(--gp-z-raised); }\n.gp-front { z-index: var(--gp-z-front); }\n\n/* GFM-style alert/callout boxes (#237) \u2014 the DOM gfm-alerts.ts emits from\n \"> [!TYPE]\" blockquote syntax when a project opts into the bundled\n gutterpress-gfm-alerts feature (BUILTIN_OPTIONAL_PLUGINS, renderer.ts).\n The plugin is optional and inert by default; these rules are equally\n inert wherever the classes never appear, exactly like every other\n utility above, so shipping them costs nothing to a book that has not\n turned the feature on.\n\n This is authored-COMPONENT vocabulary, not the @marker structural family\n (markers.js/MARKER_CSS) \u2014 CLAUDE.md \u00A76 splits the two core CSS blocks by\n ROLE, and an author-facing box an author invokes via inline syntax is the\n same role as every other gp-* utility here, not page/chapter/section DOM.\n\n Deliberately minimal (CLAUDE.md \"thin over capable\" / the issue's own\n \"a rule and a label\"): a left border plus a bold label, :where()'d to\n zero specificity so a theme's own (unlayered) rule for any of these\n classes wins outright regardless of selector weight \u2014 see the\n cascade-layers note atop this file. Five semantic accent colors (the same\n NOTE/TIP/IMPORTANT/WARNING/CAUTION hues GitHub's own alerts use \u2014 a\n long-established, non-proprietary convention, not DC branding) are\n exposed as :root custom properties, the same author-settable-surface\n pattern as the --gp-z-* ladder above: a book retints every alert of one\n type by overriding a single property, no specificity fight required.\n --gp-alert-color cascades from the type modifier down to .gp-alert-title\n through ordinary CSS inheritance (the title is always a DOM descendant of\n the box), so it is set in exactly five places, not ten. */\n:root {\n --gp-alert-note-color: #0969da;\n --gp-alert-tip-color: #1a7f37;\n --gp-alert-important-color: #8250df;\n --gp-alert-warning-color: #9a6700;\n --gp-alert-caution-color: #cf222e;\n}\n:where(.gp-alert) {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 0.25em solid var(--gp-alert-color, currentColor);\n}\n:where(.gp-alert-title) {\n margin: 0 0 0.5em;\n font-weight: bold;\n color: var(--gp-alert-color, inherit);\n}\n:where(.gp-alert-note) { --gp-alert-color: var(--gp-alert-note-color); }\n:where(.gp-alert-tip) { --gp-alert-color: var(--gp-alert-tip-color); }\n:where(.gp-alert-important) { --gp-alert-color: var(--gp-alert-important-color); }\n:where(.gp-alert-warning) { --gp-alert-color: var(--gp-alert-warning-color); }\n:where(.gp-alert-caution) { --gp-alert-color: var(--gp-alert-caution-color); }\n\n/* Math (the bundled gutterpress-math feature, math.ts): MathJax's own rules\n for the <mjx-container> SVG output it emits, from its SVG output jax's\n stylesheet, less the ones for its interactive menu and tooltips, plus one\n bound of ours on the hidden MathML copy (#469, below). Inert in a book\n without formulas. */\nmjx-container[jax=\"SVG\"] { direction: ltr; }\nmjx-container[jax=\"SVG\"] > svg { overflow: visible; min-height: 1px; min-width: 1px; }\nmjx-container[jax=\"SVG\"] > svg a { fill: blue; stroke: blue; }\nmjx-container[jax=\"SVG\"][display=\"true\"] { display: block; text-align: center; margin: 1em 0; }\nmjx-container[jax=\"SVG\"][display=\"true\"][width=\"full\"] { display: flex; }\nmjx-container[jax=\"SVG\"][justify=\"left\"] { text-align: left; }\nmjx-container[jax=\"SVG\"][justify=\"right\"] { text-align: right; }\nmjx-container[jax=\"SVG\"] path[data-c], mjx-container[jax=\"SVG\"] use[data-c] { stroke-width: 3; }\nmjx-assistive-mml {\n position: absolute !important;\n top: 0px; left: 0px;\n clip: rect(1px, 1px, 1px, 1px);\n padding: 1px 0px 0px 0px !important;\n border: 0px !important;\n display: block !important;\n width: auto !important;\n /* Ours (#469). The browser lays the copy out in whatever math font it has,\n so it can be wider than the formula's SVG; ending a line, it crossed the\n column edge and Chromium shrank the whole print to fit. MathJax makes the\n container position: relative with the copy at its top left, so 100% is\n the formula's width. Clip and overflow still hide the copy and its MathML\n still reaches screen readers; only its box changes. Not the 1px\n visually-hidden box MathJax 2 used: its docs note VoiceOver on iOS could\n not reach a formula by touch in it. */\n max-width: 100% !important;\n overflow: hidden !important;\n user-select: none;\n}\nmjx-assistive-mml[display=\"block\"] { width: 100% !important; }\ng[data-mml-node=\"merror\"] > g { fill: red; stroke: red; }\ng[data-mml-node=\"merror\"] > rect[data-background] { fill: yellow; stroke: none; }\ng[data-mml-node=\"mtable\"] > line[data-line], svg[data-table] > g > line[data-line] { stroke-width: 70px; fill: none; }\ng[data-mml-node=\"mtable\"] > rect[data-frame], svg[data-table] > g > rect[data-frame] { stroke-width: 70px; fill: none; }\ng[data-mml-node=\"mtable\"] > .mjx-dashed, svg[data-table] > g > .mjx-dashed { stroke-dasharray: 140; }\ng[data-mml-node=\"mtable\"] > .mjx-dotted, svg[data-table] > g > .mjx-dotted { stroke-linecap: round; stroke-dasharray: 0,140; }\ng[data-mml-node=\"mtable\"] > g > svg { overflow: visible; }\n";
|
|
155
155
|
/**
|
|
156
156
|
* GP_CLASSES — every class an author may legitimately write with a `gp-`
|
|
157
157
|
* prefix: the `.gp-*` selectors in `GUTTERPRESS_CSS` above, the two
|
|
@@ -5,7 +5,7 @@ import type MarkdownIt from "markdown-it";
|
|
|
5
5
|
*
|
|
6
6
|
* Bundled, OPT-IN markdown feature (`gutterpress-math` in
|
|
7
7
|
* `BUILTIN_OPTIONAL_PLUGINS`, renderer.ts; "Math" in
|
|
8
|
-
* `
|
|
8
|
+
* `BUNDLED_EXTENSION_DETAILS`, extension-specifier.ts), exactly like the Callouts
|
|
9
9
|
* feature: a book that never lists it renders `$` as the character it is.
|
|
10
10
|
*
|
|
11
11
|
* WHY SVG. Each formula is written as a drawing of its own glyphs, so the
|
|
@@ -9,4 +9,5 @@ import type MarkdownIt from "markdown-it";
|
|
|
9
9
|
*/
|
|
10
10
|
export declare const QUOTES: Record<string, string | string[]>;
|
|
11
11
|
export declare function quotesFor(language?: string): string | string[];
|
|
12
|
+
/** Replaces markdown-it's `replacements` rule, at its place in the core chain. */
|
|
12
13
|
export declare function gpTypography(md: MarkdownIt): void;
|
package/dist/lib/page-size.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface CustomPageOptions {
|
|
|
10
10
|
width: number;
|
|
11
11
|
/** Trim height in points (72pt = 1in). */
|
|
12
12
|
height: number;
|
|
13
|
+
/** How far (pt) the built PDF may differ from it, written as the page-size check's option. Default: the preset's 0.5. */
|
|
14
|
+
tolerance?: number;
|
|
13
15
|
}
|
|
14
16
|
/** A page size in points. */
|
|
15
17
|
export interface PageSizePoints {
|
|
@@ -50,9 +52,10 @@ export interface PageSetup {
|
|
|
50
52
|
presetSizeOverridden: boolean;
|
|
51
53
|
}
|
|
52
54
|
/**
|
|
53
|
-
* Write the manifest's `page:` bounds
|
|
54
|
-
*
|
|
55
|
-
* `page:` that is not a
|
|
55
|
+
* Write the manifest's `page:` bounds, and a `tolerance` given with them as
|
|
56
|
+
* the page-size check's option (one already recorded stays when none is
|
|
57
|
+
* given). The block's other keys stay as written; a `page:` that is not a
|
|
58
|
+
* map is replaced.
|
|
56
59
|
*/
|
|
57
60
|
export declare function writePageBounds(doc: Document, page: CustomPageOptions): void;
|
|
58
61
|
/** Remove the bounds a preset owns and nothing else; a `page:` left empty goes too. */
|
|
@@ -67,6 +70,8 @@ export declare function numberAt(doc: Document, keyPath: string[]): number | und
|
|
|
67
70
|
export declare function pageSizeForChoice(choice: PageSizeChoice): PageSizePoints;
|
|
68
71
|
/** Read a book's page geometry back from its manifest (and, for margins it does not set, its stylesheets). */
|
|
69
72
|
export declare function readPageSetup(projectDir: string): Promise<PageSetup>;
|
|
73
|
+
/** @deprecated 0.11.22's call shape: pass `{ size: { preset, page } }`. */
|
|
74
|
+
export declare function setPageSetup(projectDir: string, choice: PageSizeChoice): Promise<PageSetup>;
|
|
70
75
|
/**
|
|
71
76
|
* Change a book's page geometry in the manifest. The size mirrors what the
|
|
72
77
|
* wizard records — `dtrpg` / `book` carry their own bounds (the `page:` block's
|
|
@@ -74,6 +79,9 @@ export declare function readPageSetup(projectDir: string): Promise<PageSetup>;
|
|
|
74
79
|
* other keys stay), `custom` records the typed trim. The margins go to
|
|
75
80
|
* `page.margin`, validated against the size being written, else the recorded
|
|
76
81
|
* one; `margins: null` removes `page.margin`. Nothing is written unless the
|
|
77
|
-
* whole change validates.
|
|
82
|
+
* whole change validates. A 0.11.22 caller's `{ preset, page? }` (a size
|
|
83
|
+
* choice, before margins joined it) is read as `{ size: { preset, page } }`.
|
|
84
|
+
* The thresholds a 0.11.22 manifest spells the old way are written the new
|
|
85
|
+
* way (`rewriteOldThresholds`).
|
|
78
86
|
*/
|
|
79
87
|
export declare function setPageSetup(projectDir: string, change: PageSetupChange): Promise<PageSetup>;
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/** Project-relative folder every extension a book carries lives under: vendored npm copies in `npm/`, imports beside them. */
|
|
2
2
|
export declare const EXTENSIONS_DIR = "extensions";
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated 0.11.22's name for the folder vendored npm extensions go in;
|
|
5
|
+
* the same folder as {@link EXTENSIONS_DIR}, kept so a caller of the lib keeps
|
|
6
|
+
* working. Books vendored before 0.11.23 keep theirs in {@link LEGACY_PLUGINS_DIR}.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PLUGINS_DIR = "extensions";
|
|
3
9
|
/** Where books vendored before 0.11.23 keep their npm copies. Read, never written. */
|
|
4
10
|
export declare const LEGACY_PLUGINS_DIR = "plugins";
|
|
5
11
|
export declare const VENDORED_NPM_DIR = "npm";
|
package/dist/lib/presets.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ import type { ResolvedConfig } from "../schema/manifest.types";
|
|
|
7
7
|
*
|
|
8
8
|
* Geometry, build and print values are overridable from the manifest, leaf
|
|
9
9
|
* by leaf (resolveConfig's mergeShape; precedence cli > manifest > target >
|
|
10
|
-
* preset). The check thresholds (`ink`, `validate`) are
|
|
11
|
-
*
|
|
10
|
+
* preset). The check thresholds (`ink`, `validate`, `page.tolerance`) are
|
|
11
|
+
* overridden in the check's own `checks:` entry (lib/check-options.ts).
|
|
12
12
|
*/
|
|
13
13
|
export interface VendorPreset extends Omit<ResolvedConfig, "title" | "authors" | "language" | "preset" | "targets" | "page"> {
|
|
14
14
|
/** This preset's id: what the manifest's `preset:` names and a resolved config reports. */
|
|
@@ -71,6 +71,7 @@ export declare function rootTokens(css: string): RootToken[];
|
|
|
71
71
|
* added to `sheets[target]`. A null value removes the token from every
|
|
72
72
|
* sheet, so what the looks set shows through. Returns the sheets' new text;
|
|
73
73
|
* a sheet nothing changed comes back as it was given. Throws postcss's
|
|
74
|
-
* `CssSyntaxError` for a sheet it cannot parse
|
|
74
|
+
* `CssSyntaxError` for a sheet it cannot parse, and refuses the whole batch,
|
|
75
|
+
* writing nothing, when a value is not one declaration's value.
|
|
75
76
|
*/
|
|
76
77
|
export declare function applyTokenUpdates(sheets: readonly string[], target: number, updates: readonly TokenUpdate[]): string[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ReadCommitResult } from "isomorphic-git";
|
|
1
2
|
import type { ProjectCapabilities, ProjectSource } from "./project-source.ts";
|
|
2
3
|
/**
|
|
3
4
|
* isomorphic-git object cache scoped to ONE operation and released with it.
|
|
@@ -182,6 +183,32 @@ export declare function hasPendingChanges(dir: string, cache?: GitCache): Promis
|
|
|
182
183
|
* as dirty (the WORKDIR-vs-STAGE-only check silently drops it).
|
|
183
184
|
*/
|
|
184
185
|
export declare function hasUncommittedChanges(dir: string, cache?: GitCache): Promise<boolean>;
|
|
186
|
+
/**
|
|
187
|
+
* A walk back through a repo's history in the order `git.log` lists it (the
|
|
188
|
+
* newest commit time first), visiting each commit once (#472). `git.log` has
|
|
189
|
+
* no visited set: after a merge it lists a commit again, with everything older,
|
|
190
|
+
* and the repeats used up a page. Starting the next page's log at the last id
|
|
191
|
+
* also dropped the side of a merge that id does not descend from. Shared with
|
|
192
|
+
* the online-only versions (`commitsAhead`, #477), which walks two tips at once.
|
|
193
|
+
*/
|
|
194
|
+
export interface HistoryWalk {
|
|
195
|
+
/** Commits read but not listed yet, sorted so the newest is last. */
|
|
196
|
+
tips: ReadCommitResult[];
|
|
197
|
+
/** Every commit ever put in `tips`. */
|
|
198
|
+
queued: Set<string>;
|
|
199
|
+
/** `.git/shallow`: commits whose parents a shallow clone does not have. */
|
|
200
|
+
shallow: Set<string>;
|
|
201
|
+
/** Commits read ahead (see {@link nextInHistory}), not queued yet. */
|
|
202
|
+
readAhead: Map<string, ReadCommitResult>;
|
|
203
|
+
}
|
|
204
|
+
/** A walk back from `heads` (the history of each of them, together). */
|
|
205
|
+
export declare function startHistoryWalk(dir: string, cache: GitCache, heads: string[]): Promise<HistoryWalk>;
|
|
206
|
+
/**
|
|
207
|
+
* The walk's next commit, newest first; undefined once the history is done.
|
|
208
|
+
* `needed` is how many more commits the page needs, to bound a read-ahead
|
|
209
|
+
* (none for 1: a caller that cannot tell how far it will go reads one by one).
|
|
210
|
+
*/
|
|
211
|
+
export declare function nextInHistory(dir: string, walk: HistoryWalk, cache: GitCache, needed: number): Promise<ReadCommitResult | undefined>;
|
|
185
212
|
/**
|
|
186
213
|
* Lock-free snapshot of the full working tree (stage everything + commit).
|
|
187
214
|
*
|
|
@@ -14,7 +14,8 @@ export declare function relDisplay(projectDir: string, absPath: string): string;
|
|
|
14
14
|
* BOTH the renderer (to `<link>` them) and the editor (to edit them), so they
|
|
15
15
|
* can never disagree. Returns project-relative paths:
|
|
16
16
|
* 1. the manifest `styles:` list, if it has any entries; else
|
|
17
|
-
* 2.
|
|
17
|
+
* 2. the first conventional stylesheet the project actually has
|
|
18
|
+
* (`FALLBACK_PRIORITY`); else
|
|
18
19
|
* 3. the first discovered `.css` anywhere we scan (deterministic); else
|
|
19
20
|
* 4. `[]` — the project has no stylesheet (an honest empty, never a phantom
|
|
20
21
|
* link to a missing file).
|
|
@@ -22,6 +22,12 @@ export interface VersionEntry extends SnapshotEntry {
|
|
|
22
22
|
/** True = online too; false = on this computer only; null = no online copy to compare with. */
|
|
23
23
|
backedUp: boolean | null;
|
|
24
24
|
}
|
|
25
|
+
/** A version in the online copy that this computer has not got, with the files it changed. */
|
|
26
|
+
export interface OnlineVersionEntry extends VersionEntry {
|
|
27
|
+
changes: VersionFileChange[];
|
|
28
|
+
/** Changed files beyond the ones listed. */
|
|
29
|
+
moreChanges: number;
|
|
30
|
+
}
|
|
25
31
|
/** How many changed files a version card lists before "and N more". */
|
|
26
32
|
export declare const VERSION_CHANGES_SHOWN = 8;
|
|
27
33
|
/** The size hint for a text file that changed between two versions. */
|
|
@@ -45,15 +51,25 @@ export declare function listVersionChanges(projectDir: string, oid: string): Pro
|
|
|
45
51
|
export declare function describeVersions(projectDir: string, entries: SnapshotEntry[]): Promise<VersionEntry[]>;
|
|
46
52
|
/**
|
|
47
53
|
* The commits reachable from `fromOid` that `baseOid`'s history does not
|
|
48
|
-
* have
|
|
49
|
-
*
|
|
54
|
+
* have (`git rev-list fromOid ^baseOid`), each once, newest first in the
|
|
55
|
+
* order Version history lists versions, up to `limit`. None when the two
|
|
56
|
+
* share no history: that is another book's online copy, which Sync refuses.
|
|
57
|
+
*
|
|
58
|
+
* One walk back from both tips, newest commit time first (#477). What
|
|
59
|
+
* `baseOid` reaches is marked, and a marked commit marks its parents, even
|
|
60
|
+
* ones already walked: a commit both tips reach is never listed, by whatever
|
|
61
|
+
* path `fromOid` reaches it (a criss-cross merge has two merge bases). The
|
|
62
|
+
* walk goes on while an unmarked commit is queued, so a version dated before
|
|
63
|
+
* the commits it builds on (a collaborator's clock behind) is still found;
|
|
64
|
+
* then until every marked commit queued is {@link CLOCK_SKEW_SECONDS} older
|
|
65
|
+
* than the oldest version listed.
|
|
50
66
|
*/
|
|
51
|
-
export declare function commitsAhead(dir: string, fromOid: string, baseOid: string, cache?:
|
|
67
|
+
export declare function commitsAhead(dir: string, fromOid: string, baseOid: string, cache?: Record<string, unknown>, limit?: number): Promise<SnapshotEntry[]>;
|
|
52
68
|
/**
|
|
53
69
|
* What is online that this computer has not got: fetch the book's branch
|
|
54
70
|
* (remote-tracking ref only — no merge, no checkout, safe on a dirty tree)
|
|
55
|
-
* and describe the commits
|
|
56
|
-
* reporting why, like `checkRemoteUpdates`.
|
|
71
|
+
* and describe the commits this computer has not got, each with the files it
|
|
72
|
+
* changed. Quiet on every failure, reporting why, like `checkRemoteUpdates`.
|
|
57
73
|
*/
|
|
58
74
|
export declare function listOnlineVersions(options: {
|
|
59
75
|
projectDir: string;
|
|
@@ -61,7 +77,7 @@ export declare function listOnlineVersions(options: {
|
|
|
61
77
|
tokenStore?: TokenStore;
|
|
62
78
|
httpClient?: typeof defaultGitHttp;
|
|
63
79
|
}): Promise<{
|
|
64
|
-
entries:
|
|
80
|
+
entries: OnlineVersionEntry[];
|
|
65
81
|
reason?: "no-remote" | "auth" | "offline";
|
|
66
82
|
}>;
|
|
67
83
|
/**
|