gutterpress 0.11.16-alpha.1 → 0.11.16-alpha.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/dist/api/index.js +2 -2
- package/dist/{build-46bb205t.js → build-tse0tq0t.js} +4 -4
- package/dist/{cli-6tfc4ed6.js → cli-14j4aqtc.js} +1 -1
- package/dist/{cli-d55z7rtk.js → cli-8597az31.js} +1 -1
- package/dist/{cli-p8xwsknv.js → cli-w9qc8fem.js} +1 -1
- package/dist/{cli-sq0awkbf.js → cli-x9bb628z.js} +78 -15
- package/dist/cli.js +12 -12
- package/dist/{doctor-tjatz81j.js → doctor-s6npnst2.js} +2 -2
- package/dist/{engine-szx34415.js → engine-5b92gk8n.js} +2 -2
- package/dist/{engine-nv2xddnk.js → engine-6jnxqfsm.js} +1 -1
- package/dist/{ext-ph0770mx.js → ext-tf6x156j.js} +4 -4
- package/dist/{index-azdfgy3t.js → index-ncxfknbv.js} +91 -17
- package/dist/{index-eawjxgkn.js → index-w1qk3tap.js} +1 -1
- package/dist/{index-9ydc9q9q.js → index-zb48zwcq.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/lib/markdown/assemble.d.ts +3 -0
- package/dist/lib/markdown/renderer.d.ts +37 -2
- package/dist/lib/snippets.d.ts +4 -0
- package/dist/{new-daeh9p9p.js → new-n43vrq56.js} +4 -4
- package/dist/{plugin.js-z492w01r.tpl → plugin.js-m4a7m3t4.tpl} +1 -0
- package/dist/{preflight-bfvw2qe5.js → preflight-qnp6rd1d.js} +4 -4
- package/dist/{preview-00298rvf.js → preview-v66m0vff.js} +4 -4
- package/dist/{publish-jn9t18mr.js → publish-xgmbeerq.js} +4 -4
- package/dist/render.js +74 -11
- package/dist/{validate-cm1m5bbf.js → validate-281t5k0g.js} +4 -4
- package/package.json +1 -1
package/dist/api/index.js
CHANGED
|
@@ -128,10 +128,10 @@ import {
|
|
|
128
128
|
testRemoteAccess,
|
|
129
129
|
updateExtensions,
|
|
130
130
|
validateProjectExtensions
|
|
131
|
-
} from "../index-
|
|
131
|
+
} from "../index-ncxfknbv.js";
|
|
132
132
|
import {
|
|
133
133
|
BuildError
|
|
134
|
-
} from "../index-
|
|
134
|
+
} from "../index-w1qk3tap.js";
|
|
135
135
|
import {
|
|
136
136
|
DEFAULT_PRINT_OPTS,
|
|
137
137
|
assertMilestone,
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runBuild,
|
|
3
3
|
splitOutPath
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-x9bb628z.js";
|
|
5
5
|
import {
|
|
6
6
|
log
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-14j4aqtc.js";
|
|
8
8
|
import {
|
|
9
9
|
UsageError,
|
|
10
10
|
parseFormat,
|
|
11
11
|
parsePdfxFlavor,
|
|
12
12
|
rejectExtraPositionals,
|
|
13
13
|
rejectUnknownFlags
|
|
14
|
-
} from "./cli-
|
|
15
|
-
import"./cli-
|
|
14
|
+
} from "./cli-w9qc8fem.js";
|
|
15
|
+
import"./cli-8597az31.js";
|
|
16
16
|
import {
|
|
17
17
|
BuildError
|
|
18
18
|
} from "./cli-46ycxe6r.js";
|
|
@@ -1151,7 +1151,7 @@ var package_default = "./package-9rv69pxm.json";
|
|
|
1151
1151
|
var README_default = "./README-vsnsc1b3.md";
|
|
1152
1152
|
|
|
1153
1153
|
// src/assets/extension-templates/plugin/plugin.js.tpl
|
|
1154
|
-
var plugin_js_default = "./plugin.js-
|
|
1154
|
+
var plugin_js_default = "./plugin.js-m4a7m3t4.tpl";
|
|
1155
1155
|
|
|
1156
1156
|
// src/assets/extension-templates/plugin/styles/plugin.css
|
|
1157
1157
|
var plugin_default = "./plugin-spbcem4j.css";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "gutterpress",
|
|
7
|
-
version: "0.11.16-alpha.
|
|
7
|
+
version: "0.11.16-alpha.3",
|
|
8
8
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
9
9
|
author: "itlackey",
|
|
10
10
|
license: "MPL-2.0",
|
|
@@ -13,17 +13,17 @@ import {
|
|
|
13
13
|
stampCreator,
|
|
14
14
|
stripAnnotations,
|
|
15
15
|
warn
|
|
16
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-14j4aqtc.js";
|
|
17
17
|
import {
|
|
18
18
|
DEBOUNCE,
|
|
19
19
|
UsageError,
|
|
20
20
|
resolvePort
|
|
21
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-w9qc8fem.js";
|
|
22
22
|
import {
|
|
23
23
|
MARGIN_BOX_IGNORED_PROPERTIES,
|
|
24
24
|
getAssetPath,
|
|
25
25
|
getAssetsDir
|
|
26
|
-
} from "./cli-
|
|
26
|
+
} from "./cli-8597az31.js";
|
|
27
27
|
import {
|
|
28
28
|
BuildError
|
|
29
29
|
} from "./cli-46ycxe6r.js";
|
|
@@ -3148,6 +3148,16 @@ function validateDeclaredMarkerName(name, pluginName) {
|
|
|
3148
3148
|
}
|
|
3149
3149
|
var TAG_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
3150
3150
|
function resolveContainerShape(name, pluginName, decl) {
|
|
3151
|
+
if (decl.section !== undefined && typeof decl.section !== "boolean") {
|
|
3152
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`section\` that is not a boolean.`);
|
|
3153
|
+
}
|
|
3154
|
+
if (decl.section) {
|
|
3155
|
+
for (const field of ["tag", "label", "autoCloseAt"]) {
|
|
3156
|
+
if (decl[field] !== undefined) {
|
|
3157
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" sets \`section: true\` and \`${field}\` — a section ` + `marker is a core @section, so \`${field}\` does not apply. Remove one of them.`);
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3151
3161
|
const tag = decl.tag !== undefined ? decl.tag : "div";
|
|
3152
3162
|
if (typeof tag !== "string" || !TAG_NAME_RE.test(tag)) {
|
|
3153
3163
|
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has an invalid \`tag\` (${JSON.stringify(decl.tag)}) — ` + `must be a lower-case HTML tag name.`);
|
|
@@ -3203,7 +3213,7 @@ function resolveContainerShape(name, pluginName, decl) {
|
|
|
3203
3213
|
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`validate\` that is not a function.`);
|
|
3204
3214
|
}
|
|
3205
3215
|
const check20 = decl.validate ? { validate: decl.validate, validateOwner: pluginName } : {};
|
|
3206
|
-
return { tag, classBase, variants, label, autoCloseAtEof, ...check20 };
|
|
3216
|
+
return { tag, classBase, variants, label, autoCloseAtEof, ...decl.section ? { section: true } : {}, ...check20 };
|
|
3207
3217
|
}
|
|
3208
3218
|
function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
|
|
3209
3219
|
const pluginName = originOf.get(name);
|
|
@@ -3279,12 +3289,12 @@ function declaredKindWords(declaredMarkers) {
|
|
|
3279
3289
|
}
|
|
3280
3290
|
return words;
|
|
3281
3291
|
}
|
|
3282
|
-
function nearestDeclaredMarkerName(word,
|
|
3292
|
+
function nearestDeclaredMarkerName(word, names) {
|
|
3283
3293
|
const w = word.toLowerCase();
|
|
3284
3294
|
const threshold = Math.max(2, Math.floor(w.length / 3));
|
|
3285
3295
|
let best = null;
|
|
3286
3296
|
let bestDistance = Infinity;
|
|
3287
|
-
for (const known of
|
|
3297
|
+
for (const known of names) {
|
|
3288
3298
|
const d = editDistance(w, known);
|
|
3289
3299
|
if (d < bestDistance) {
|
|
3290
3300
|
bestDistance = d;
|
|
@@ -3312,13 +3322,23 @@ function scanForUnknownDeclaredMarkers(state, declaredMarkers) {
|
|
|
3312
3322
|
const word = m[1];
|
|
3313
3323
|
if (KNOWN_KINDS.includes(word) || declaredMarkers.has(word))
|
|
3314
3324
|
continue;
|
|
3315
|
-
const suggestion = nearestDeclaredMarkerName(word, declaredMarkers);
|
|
3325
|
+
const suggestion = nearestDeclaredMarkerName(word, declaredMarkers.keys());
|
|
3316
3326
|
if (!suggestion)
|
|
3317
3327
|
continue;
|
|
3318
3328
|
warn2(state.env, tok.map[0] + i + 1, "unknown_marker", `Unknown marker "@${word}". Did you mean "@${suggestion}"?`, null);
|
|
3319
3329
|
}
|
|
3320
3330
|
}
|
|
3321
3331
|
}
|
|
3332
|
+
function warnUnknownVariant(env, meta, decl) {
|
|
3333
|
+
const word = meta.name;
|
|
3334
|
+
if (!word)
|
|
3335
|
+
return;
|
|
3336
|
+
const variants = Object.keys(decl.variants || {});
|
|
3337
|
+
if (variants.includes(word))
|
|
3338
|
+
return;
|
|
3339
|
+
const near = variants.find((v) => v.toLowerCase() === word.toLowerCase()) || (word.length >= 3 ? nearestDeclaredMarkerName(word, variants) : null);
|
|
3340
|
+
warn2(env, meta.__line, "unknown_variant", `"${word}" is not a variant of @${meta.kind}, so it adds no styling. ` + (variants.length ? `Variants: ${variants.join(", ")}.` : `@${meta.kind} has no variants.`) + (near ? ` Did you mean "${near}"?` : ""), meta);
|
|
3341
|
+
}
|
|
3322
3342
|
function plugin(md, pluginOptions = {}) {
|
|
3323
3343
|
const options = {
|
|
3324
3344
|
preferPagesInSpreads: false,
|
|
@@ -3428,7 +3448,15 @@ function plugin(md, pluginOptions = {}) {
|
|
|
3428
3448
|
function openDeclaredMarker(meta, decl) {
|
|
3429
3449
|
const t = new state.Token("layout_component_open", decl.tag, 1);
|
|
3430
3450
|
const variant = meta.name || decl.presetVariant || null;
|
|
3431
|
-
|
|
3451
|
+
warnUnknownVariant(state.env, meta, decl);
|
|
3452
|
+
t.meta = {
|
|
3453
|
+
line: meta.__line,
|
|
3454
|
+
component: meta.kind,
|
|
3455
|
+
kind: decl.baseKind,
|
|
3456
|
+
variant,
|
|
3457
|
+
attrs: meta.attrs || {},
|
|
3458
|
+
labelled: false
|
|
3459
|
+
};
|
|
3432
3460
|
const variantClass = variant && decl.variants && decl.variants[variant] || "";
|
|
3433
3461
|
const baseClass = [decl.classBase, variantClass].filter(Boolean).join(" ");
|
|
3434
3462
|
addClasses(t, baseClass, meta.attrs && meta.attrs.class ? meta.attrs.class : "");
|
|
@@ -3536,16 +3564,34 @@ function plugin(md, pluginOptions = {}) {
|
|
|
3536
3564
|
warn2(state.env, meta.__line || 0, "page_outside_spread", "@page used outside of a spread; allowed, but spreads are recommended for deliberate grouping.", meta);
|
|
3537
3565
|
}
|
|
3538
3566
|
}
|
|
3567
|
+
function sectionMetaFor(meta, decl) {
|
|
3568
|
+
const attrs = meta.attrs || {};
|
|
3569
|
+
const variant = meta.name || decl.presetVariant || null;
|
|
3570
|
+
warnUnknownVariant(state.env, meta, decl);
|
|
3571
|
+
const variantClass = variant && decl.variants && decl.variants[variant] || "";
|
|
3572
|
+
const cls = [decl.classBase, variantClass, attrs.class].filter(Boolean).join(" ");
|
|
3573
|
+
return {
|
|
3574
|
+
kind: "section",
|
|
3575
|
+
name: null,
|
|
3576
|
+
attrs: cls ? { ...attrs, class: cls } : attrs,
|
|
3577
|
+
__line: meta.__line,
|
|
3578
|
+
__component: { component: meta.kind, kind: decl.baseKind, variant, attrs }
|
|
3579
|
+
};
|
|
3580
|
+
}
|
|
3539
3581
|
function openSection(meta) {
|
|
3540
3582
|
const t = new state.Token("layout_section_open", "div", 1);
|
|
3583
|
+
const component = meta.__component || null;
|
|
3541
3584
|
addClasses(t, "section", meta.attrs && meta.attrs.class ? meta.attrs.class : "");
|
|
3542
|
-
|
|
3543
|
-
|
|
3585
|
+
if (component)
|
|
3586
|
+
attachDataAttrs(t, component.kind, component.variant, meta.attrs || {});
|
|
3587
|
+
else
|
|
3588
|
+
attachDataAttrs(t, "section", meta.name, meta.attrs || {});
|
|
3589
|
+
t.meta = component ? { line: meta.__line, ...component, ...meta.__continued ? { continued: true } : {} } : { line: meta.__line };
|
|
3544
3590
|
stack.open({
|
|
3545
3591
|
kind: "section",
|
|
3546
3592
|
classes: meta.attrs && meta.attrs.class || "",
|
|
3547
3593
|
sawContent: false,
|
|
3548
|
-
meta: { name: meta.name || null, attrs: { ...meta.attrs || {} } },
|
|
3594
|
+
meta: { name: meta.name || null, attrs: { ...meta.attrs || {} }, component },
|
|
3549
3595
|
openToken: t
|
|
3550
3596
|
}, t);
|
|
3551
3597
|
}
|
|
@@ -3591,9 +3637,21 @@ function plugin(md, pluginOptions = {}) {
|
|
|
3591
3637
|
out.push(tok);
|
|
3592
3638
|
continue;
|
|
3593
3639
|
}
|
|
3594
|
-
|
|
3595
|
-
|
|
3640
|
+
let meta = tok.meta || {};
|
|
3641
|
+
let kind = meta.kind;
|
|
3596
3642
|
const line = meta.__line || 0;
|
|
3643
|
+
if (declaredMarkers) {
|
|
3644
|
+
const closing = kind.startsWith("end-");
|
|
3645
|
+
const sectionDecl = declaredMarkers.get(closing ? kind.slice(4) : kind);
|
|
3646
|
+
if (sectionDecl && sectionDecl.section) {
|
|
3647
|
+
if (closing) {
|
|
3648
|
+
kind = "end-section";
|
|
3649
|
+
} else {
|
|
3650
|
+
meta = sectionMetaFor(meta, sectionDecl);
|
|
3651
|
+
kind = "section";
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3597
3655
|
if (kind === "chapter") {
|
|
3598
3656
|
drainDeclaredFrames();
|
|
3599
3657
|
stack.close("chapter");
|
|
@@ -3637,6 +3695,10 @@ function plugin(md, pluginOptions = {}) {
|
|
|
3637
3695
|
name: section.meta.name,
|
|
3638
3696
|
attrs: { ...section.meta.attrs || {} }
|
|
3639
3697
|
};
|
|
3698
|
+
if (section.meta.component) {
|
|
3699
|
+
contMeta.__component = section.meta.component;
|
|
3700
|
+
contMeta.__continued = true;
|
|
3701
|
+
}
|
|
3640
3702
|
contMeta.__line = line;
|
|
3641
3703
|
const cls = (contMeta.attrs.class || "").split(/\s+/).filter(Boolean);
|
|
3642
3704
|
if (!cls.includes("gp-continued"))
|
|
@@ -3710,7 +3772,8 @@ function plugin(md, pluginOptions = {}) {
|
|
|
3710
3772
|
const tokens = state.tokens;
|
|
3711
3773
|
for (let i = 0;i < tokens.length; i++) {
|
|
3712
3774
|
const tok = tokens[i];
|
|
3713
|
-
|
|
3775
|
+
const isSection = tok.type === "layout_section_open" && tok.meta && tok.meta.component && !tok.meta.continued;
|
|
3776
|
+
if (tok.type !== "layout_component_open" && !isSection)
|
|
3714
3777
|
continue;
|
|
3715
3778
|
const decl = declaredMarkers.get(tok.meta.component);
|
|
3716
3779
|
if (!decl || !decl.validate)
|
|
@@ -8139,7 +8202,7 @@ class PdfOutput {
|
|
|
8139
8202
|
const rawPdf = pdfxMode ? path8.join(stage, "raw.pdf") : path8.resolve(pdfFile);
|
|
8140
8203
|
await fsp2.mkdir(path8.dirname(path8.resolve(pdfFile)), { recursive: true });
|
|
8141
8204
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
8142
|
-
const { buildNativePdf } = await import("./engine-
|
|
8205
|
+
const { buildNativePdf } = await import("./engine-6jnxqfsm.js");
|
|
8143
8206
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
8144
8207
|
title: config.title,
|
|
8145
8208
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
UsageError,
|
|
7
7
|
package_default,
|
|
8
8
|
rejectUnknownFlags
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-w9qc8fem.js";
|
|
10
10
|
import {
|
|
11
11
|
EXIT_CODES
|
|
12
12
|
} from "./cli-46ycxe6r.js";
|
|
@@ -18,14 +18,14 @@ import {
|
|
|
18
18
|
import { defineCommand, parseArgs, runMain } from "citty";
|
|
19
19
|
import { statSync } from "node:fs";
|
|
20
20
|
var SUBCOMMANDS = {
|
|
21
|
-
new: () => import("./new-
|
|
22
|
-
preview: () => import("./preview-
|
|
23
|
-
build: () => import("./build-
|
|
24
|
-
publish: () => import("./publish-
|
|
25
|
-
validate: () => import("./validate-
|
|
26
|
-
preflight: () => import("./preflight-
|
|
27
|
-
doctor: () => import("./doctor-
|
|
28
|
-
ext: () => import("./ext-
|
|
21
|
+
new: () => import("./new-n43vrq56.js").then((m) => m.default),
|
|
22
|
+
preview: () => import("./preview-v66m0vff.js").then((m) => m.default),
|
|
23
|
+
build: () => import("./build-tse0tq0t.js").then((m) => m.default),
|
|
24
|
+
publish: () => import("./publish-xgmbeerq.js").then((m) => m.default),
|
|
25
|
+
validate: () => import("./validate-281t5k0g.js").then((m) => m.default),
|
|
26
|
+
preflight: () => import("./preflight-qnp6rd1d.js").then((m) => m.default),
|
|
27
|
+
doctor: () => import("./doctor-s6npnst2.js").then((m) => m.default),
|
|
28
|
+
ext: () => import("./ext-tf6x156j.js").then((m) => m.default)
|
|
29
29
|
};
|
|
30
30
|
var VERSION = package_default.version;
|
|
31
31
|
var main = defineCommand({
|
|
@@ -50,7 +50,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
50
50
|
const [command, ...commandArgs] = rawArgs;
|
|
51
51
|
try {
|
|
52
52
|
if (command === "new") {
|
|
53
|
-
const { newArgs } = await import("./new-
|
|
53
|
+
const { newArgs } = await import("./new-n43vrq56.js");
|
|
54
54
|
rejectUnknownFlags(commandArgs, newArgs, "new");
|
|
55
55
|
const parsed = parseArgs(commandArgs, {
|
|
56
56
|
...newArgs,
|
|
@@ -62,7 +62,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
if (command === "preflight") {
|
|
65
|
-
const { preflightArgs } = await import("./preflight-
|
|
65
|
+
const { preflightArgs } = await import("./preflight-qnp6rd1d.js");
|
|
66
66
|
rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
|
|
67
67
|
const parsed = parseArgs(commandArgs, {
|
|
68
68
|
...preflightArgs,
|
|
@@ -82,7 +82,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
82
82
|
}
|
|
83
83
|
if (subcommand.startsWith("-"))
|
|
84
84
|
return;
|
|
85
|
-
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-
|
|
85
|
+
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-tf6x156j.js");
|
|
86
86
|
if (!EXT_SUBCOMMANDS.includes(subcommand)) {
|
|
87
87
|
throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
|
|
88
88
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSystemDiagnostics,
|
|
3
3
|
log
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-14j4aqtc.js";
|
|
5
5
|
import {
|
|
6
6
|
UsageError,
|
|
7
7
|
rejectExtraPositionals,
|
|
8
8
|
rejectUnknownFlags
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-w9qc8fem.js";
|
|
10
10
|
import"./cli-46ycxe6r.js";
|
|
11
11
|
import"./cli-7fkhgtfn.js";
|
|
12
12
|
import"./cli-37x76zdn.js";
|
|
@@ -12,16 +12,16 @@ import {
|
|
|
12
12
|
searchNpmExtensions,
|
|
13
13
|
setExtensionEnabled,
|
|
14
14
|
updateExtensions
|
|
15
|
-
} from "./cli-
|
|
16
|
-
import"./cli-
|
|
15
|
+
} from "./cli-x9bb628z.js";
|
|
16
|
+
import"./cli-14j4aqtc.js";
|
|
17
17
|
import {
|
|
18
18
|
UsageError,
|
|
19
19
|
exitForUsage,
|
|
20
20
|
rejectExtraPositionals,
|
|
21
21
|
rejectUnknownFlags,
|
|
22
22
|
resolveProjectDir
|
|
23
|
-
} from "./cli-
|
|
24
|
-
import"./cli-
|
|
23
|
+
} from "./cli-w9qc8fem.js";
|
|
24
|
+
import"./cli-8597az31.js";
|
|
25
25
|
import {
|
|
26
26
|
EXIT_CODES
|
|
27
27
|
} from "./cli-46ycxe6r.js";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
MARGIN_BOX_IGNORED_PROPERTIES,
|
|
5
5
|
getAssetPath,
|
|
6
6
|
getAssetsDir
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-w1qk3tap.js";
|
|
8
8
|
import {
|
|
9
9
|
INSTALL_HINTS,
|
|
10
10
|
execCapture,
|
|
@@ -1033,6 +1033,16 @@ function validateDeclaredMarkerName(name, pluginName) {
|
|
|
1033
1033
|
}
|
|
1034
1034
|
var TAG_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
1035
1035
|
function resolveContainerShape(name, pluginName, decl) {
|
|
1036
|
+
if (decl.section !== undefined && typeof decl.section !== "boolean") {
|
|
1037
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`section\` that is not a boolean.`);
|
|
1038
|
+
}
|
|
1039
|
+
if (decl.section) {
|
|
1040
|
+
for (const field of ["tag", "label", "autoCloseAt"]) {
|
|
1041
|
+
if (decl[field] !== undefined) {
|
|
1042
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" sets \`section: true\` and \`${field}\` — a section ` + `marker is a core @section, so \`${field}\` does not apply. Remove one of them.`);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1036
1046
|
const tag = decl.tag !== undefined ? decl.tag : "div";
|
|
1037
1047
|
if (typeof tag !== "string" || !TAG_NAME_RE.test(tag)) {
|
|
1038
1048
|
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has an invalid \`tag\` (${JSON.stringify(decl.tag)}) — ` + `must be a lower-case HTML tag name.`);
|
|
@@ -1088,7 +1098,7 @@ function resolveContainerShape(name, pluginName, decl) {
|
|
|
1088
1098
|
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`validate\` that is not a function.`);
|
|
1089
1099
|
}
|
|
1090
1100
|
const check = decl.validate ? { validate: decl.validate, validateOwner: pluginName } : {};
|
|
1091
|
-
return { tag, classBase, variants, label, autoCloseAtEof, ...check };
|
|
1101
|
+
return { tag, classBase, variants, label, autoCloseAtEof, ...decl.section ? { section: true } : {}, ...check };
|
|
1092
1102
|
}
|
|
1093
1103
|
function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
|
|
1094
1104
|
const pluginName = originOf.get(name);
|
|
@@ -1164,12 +1174,12 @@ function declaredKindWords(declaredMarkers) {
|
|
|
1164
1174
|
}
|
|
1165
1175
|
return words;
|
|
1166
1176
|
}
|
|
1167
|
-
function nearestDeclaredMarkerName(word,
|
|
1177
|
+
function nearestDeclaredMarkerName(word, names) {
|
|
1168
1178
|
const w = word.toLowerCase();
|
|
1169
1179
|
const threshold = Math.max(2, Math.floor(w.length / 3));
|
|
1170
1180
|
let best = null;
|
|
1171
1181
|
let bestDistance = Infinity;
|
|
1172
|
-
for (const known of
|
|
1182
|
+
for (const known of names) {
|
|
1173
1183
|
const d = editDistance(w, known);
|
|
1174
1184
|
if (d < bestDistance) {
|
|
1175
1185
|
bestDistance = d;
|
|
@@ -1197,13 +1207,23 @@ function scanForUnknownDeclaredMarkers(state, declaredMarkers) {
|
|
|
1197
1207
|
const word = m[1];
|
|
1198
1208
|
if (KNOWN_KINDS.includes(word) || declaredMarkers.has(word))
|
|
1199
1209
|
continue;
|
|
1200
|
-
const suggestion = nearestDeclaredMarkerName(word, declaredMarkers);
|
|
1210
|
+
const suggestion = nearestDeclaredMarkerName(word, declaredMarkers.keys());
|
|
1201
1211
|
if (!suggestion)
|
|
1202
1212
|
continue;
|
|
1203
1213
|
warn(state.env, tok.map[0] + i + 1, "unknown_marker", `Unknown marker "@${word}". Did you mean "@${suggestion}"?`, null);
|
|
1204
1214
|
}
|
|
1205
1215
|
}
|
|
1206
1216
|
}
|
|
1217
|
+
function warnUnknownVariant(env, meta, decl) {
|
|
1218
|
+
const word = meta.name;
|
|
1219
|
+
if (!word)
|
|
1220
|
+
return;
|
|
1221
|
+
const variants = Object.keys(decl.variants || {});
|
|
1222
|
+
if (variants.includes(word))
|
|
1223
|
+
return;
|
|
1224
|
+
const near = variants.find((v) => v.toLowerCase() === word.toLowerCase()) || (word.length >= 3 ? nearestDeclaredMarkerName(word, variants) : null);
|
|
1225
|
+
warn(env, meta.__line, "unknown_variant", `"${word}" is not a variant of @${meta.kind}, so it adds no styling. ` + (variants.length ? `Variants: ${variants.join(", ")}.` : `@${meta.kind} has no variants.`) + (near ? ` Did you mean "${near}"?` : ""), meta);
|
|
1226
|
+
}
|
|
1207
1227
|
function plugin(md, pluginOptions = {}) {
|
|
1208
1228
|
const options = {
|
|
1209
1229
|
preferPagesInSpreads: false,
|
|
@@ -1313,7 +1333,15 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1313
1333
|
function openDeclaredMarker(meta, decl) {
|
|
1314
1334
|
const t = new state.Token("layout_component_open", decl.tag, 1);
|
|
1315
1335
|
const variant = meta.name || decl.presetVariant || null;
|
|
1316
|
-
|
|
1336
|
+
warnUnknownVariant(state.env, meta, decl);
|
|
1337
|
+
t.meta = {
|
|
1338
|
+
line: meta.__line,
|
|
1339
|
+
component: meta.kind,
|
|
1340
|
+
kind: decl.baseKind,
|
|
1341
|
+
variant,
|
|
1342
|
+
attrs: meta.attrs || {},
|
|
1343
|
+
labelled: false
|
|
1344
|
+
};
|
|
1317
1345
|
const variantClass = variant && decl.variants && decl.variants[variant] || "";
|
|
1318
1346
|
const baseClass = [decl.classBase, variantClass].filter(Boolean).join(" ");
|
|
1319
1347
|
addClasses(t, baseClass, meta.attrs && meta.attrs.class ? meta.attrs.class : "");
|
|
@@ -1421,16 +1449,34 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1421
1449
|
warn(state.env, meta.__line || 0, "page_outside_spread", "@page used outside of a spread; allowed, but spreads are recommended for deliberate grouping.", meta);
|
|
1422
1450
|
}
|
|
1423
1451
|
}
|
|
1452
|
+
function sectionMetaFor(meta, decl) {
|
|
1453
|
+
const attrs = meta.attrs || {};
|
|
1454
|
+
const variant = meta.name || decl.presetVariant || null;
|
|
1455
|
+
warnUnknownVariant(state.env, meta, decl);
|
|
1456
|
+
const variantClass = variant && decl.variants && decl.variants[variant] || "";
|
|
1457
|
+
const cls = [decl.classBase, variantClass, attrs.class].filter(Boolean).join(" ");
|
|
1458
|
+
return {
|
|
1459
|
+
kind: "section",
|
|
1460
|
+
name: null,
|
|
1461
|
+
attrs: cls ? { ...attrs, class: cls } : attrs,
|
|
1462
|
+
__line: meta.__line,
|
|
1463
|
+
__component: { component: meta.kind, kind: decl.baseKind, variant, attrs }
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1424
1466
|
function openSection(meta) {
|
|
1425
1467
|
const t = new state.Token("layout_section_open", "div", 1);
|
|
1468
|
+
const component = meta.__component || null;
|
|
1426
1469
|
addClasses(t, "section", meta.attrs && meta.attrs.class ? meta.attrs.class : "");
|
|
1427
|
-
|
|
1428
|
-
|
|
1470
|
+
if (component)
|
|
1471
|
+
attachDataAttrs(t, component.kind, component.variant, meta.attrs || {});
|
|
1472
|
+
else
|
|
1473
|
+
attachDataAttrs(t, "section", meta.name, meta.attrs || {});
|
|
1474
|
+
t.meta = component ? { line: meta.__line, ...component, ...meta.__continued ? { continued: true } : {} } : { line: meta.__line };
|
|
1429
1475
|
stack.open({
|
|
1430
1476
|
kind: "section",
|
|
1431
1477
|
classes: meta.attrs && meta.attrs.class || "",
|
|
1432
1478
|
sawContent: false,
|
|
1433
|
-
meta: { name: meta.name || null, attrs: { ...meta.attrs || {} } },
|
|
1479
|
+
meta: { name: meta.name || null, attrs: { ...meta.attrs || {} }, component },
|
|
1434
1480
|
openToken: t
|
|
1435
1481
|
}, t);
|
|
1436
1482
|
}
|
|
@@ -1476,9 +1522,21 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1476
1522
|
out.push(tok);
|
|
1477
1523
|
continue;
|
|
1478
1524
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1525
|
+
let meta = tok.meta || {};
|
|
1526
|
+
let kind = meta.kind;
|
|
1481
1527
|
const line = meta.__line || 0;
|
|
1528
|
+
if (declaredMarkers) {
|
|
1529
|
+
const closing = kind.startsWith("end-");
|
|
1530
|
+
const sectionDecl = declaredMarkers.get(closing ? kind.slice(4) : kind);
|
|
1531
|
+
if (sectionDecl && sectionDecl.section) {
|
|
1532
|
+
if (closing) {
|
|
1533
|
+
kind = "end-section";
|
|
1534
|
+
} else {
|
|
1535
|
+
meta = sectionMetaFor(meta, sectionDecl);
|
|
1536
|
+
kind = "section";
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1482
1540
|
if (kind === "chapter") {
|
|
1483
1541
|
drainDeclaredFrames();
|
|
1484
1542
|
stack.close("chapter");
|
|
@@ -1522,6 +1580,10 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1522
1580
|
name: section.meta.name,
|
|
1523
1581
|
attrs: { ...section.meta.attrs || {} }
|
|
1524
1582
|
};
|
|
1583
|
+
if (section.meta.component) {
|
|
1584
|
+
contMeta.__component = section.meta.component;
|
|
1585
|
+
contMeta.__continued = true;
|
|
1586
|
+
}
|
|
1525
1587
|
contMeta.__line = line;
|
|
1526
1588
|
const cls = (contMeta.attrs.class || "").split(/\s+/).filter(Boolean);
|
|
1527
1589
|
if (!cls.includes("gp-continued"))
|
|
@@ -1595,7 +1657,8 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1595
1657
|
const tokens = state.tokens;
|
|
1596
1658
|
for (let i = 0;i < tokens.length; i++) {
|
|
1597
1659
|
const tok = tokens[i];
|
|
1598
|
-
|
|
1660
|
+
const isSection = tok.type === "layout_section_open" && tok.meta && tok.meta.component && !tok.meta.continued;
|
|
1661
|
+
if (tok.type !== "layout_component_open" && !isSection)
|
|
1599
1662
|
continue;
|
|
1600
1663
|
const decl = declaredMarkers.get(tok.meta.component);
|
|
1601
1664
|
if (!decl || !decl.validate)
|
|
@@ -4014,7 +4077,7 @@ import git from "isomorphic-git";
|
|
|
4014
4077
|
// package.json
|
|
4015
4078
|
var package_default = {
|
|
4016
4079
|
name: "gutterpress",
|
|
4017
|
-
version: "0.11.16-alpha.
|
|
4080
|
+
version: "0.11.16-alpha.3",
|
|
4018
4081
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
4019
4082
|
author: "itlackey",
|
|
4020
4083
|
license: "MPL-2.0",
|
|
@@ -8629,7 +8692,7 @@ class PdfOutput {
|
|
|
8629
8692
|
const rawPdf = pdfxMode ? path8.join(stage, "raw.pdf") : path8.resolve(pdfFile);
|
|
8630
8693
|
await fsp2.mkdir(path8.dirname(path8.resolve(pdfFile)), { recursive: true });
|
|
8631
8694
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
8632
|
-
const { buildNativePdf } = await import("./engine-
|
|
8695
|
+
const { buildNativePdf } = await import("./engine-5b92gk8n.js");
|
|
8633
8696
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
8634
8697
|
title: config.title,
|
|
8635
8698
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -12123,16 +12186,27 @@ async function declaredMarkers(entry, projectDir) {
|
|
|
12123
12186
|
async function collectLibrary(projectDir) {
|
|
12124
12187
|
const groups = [];
|
|
12125
12188
|
const components = [];
|
|
12189
|
+
const loaded = [];
|
|
12126
12190
|
for (const entry of await listProjectExtensions(projectDir)) {
|
|
12127
12191
|
if (!entry.enabled)
|
|
12128
12192
|
continue;
|
|
12129
12193
|
const source = { kind: "extension", ref: entry.use, name: entry.label };
|
|
12130
12194
|
const folder = await declaredSnippetsFolder(entry);
|
|
12131
12195
|
const snippets2 = folder ? (await scanSnippetFiles(path20.join(entry.dir, folder))).map((file) => ({ ...file, source })) : [];
|
|
12132
|
-
|
|
12133
|
-
|
|
12196
|
+
loaded.push({ entry, source, folder, snippets: snippets2, markers: await declaredMarkers(entry, projectDir) });
|
|
12197
|
+
}
|
|
12198
|
+
let registry;
|
|
12199
|
+
try {
|
|
12200
|
+
registry = buildDeclaredMarkerRegistry(loaded.flatMap((l) => l.markers ? [{ pluginName: l.entry.label, markers: l.markers }] : []));
|
|
12201
|
+
} catch {
|
|
12202
|
+
registry = undefined;
|
|
12203
|
+
}
|
|
12204
|
+
for (const { entry, source, folder, snippets: snippets2, markers } of loaded) {
|
|
12205
|
+
for (const [name, decl] of Object.entries(registry ? markers ?? {} : {})) {
|
|
12206
|
+
const resolved = registry.get(name);
|
|
12207
|
+
if (!resolved || resolved.deprecated !== undefined)
|
|
12134
12208
|
continue;
|
|
12135
|
-
components.push({ name, source });
|
|
12209
|
+
components.push({ name, source, variants: Object.keys(resolved.variants ?? {}) });
|
|
12136
12210
|
if (!entry.dir)
|
|
12137
12211
|
continue;
|
|
12138
12212
|
const own = typeof decl.snippet === "string" && decl.snippet.trim() ? decl.snippet.trim() : null;
|
|
@@ -71,7 +71,7 @@ var package_default = "./package-9rv69pxm.json";
|
|
|
71
71
|
var README_default = "./README-vsnsc1b3.md";
|
|
72
72
|
|
|
73
73
|
// src/assets/extension-templates/plugin/plugin.js.tpl
|
|
74
|
-
var plugin_js_default = "./plugin.js-
|
|
74
|
+
var plugin_js_default = "./plugin.js-m4a7m3t4.tpl";
|
|
75
75
|
|
|
76
76
|
// src/assets/extension-templates/plugin/styles/plugin.css
|
|
77
77
|
var plugin_default = "./plugin-spbcem4j.css";
|
package/dist/index.js
CHANGED
|
@@ -145,13 +145,13 @@ import {
|
|
|
145
145
|
testRemoteAccess,
|
|
146
146
|
updateExtensions,
|
|
147
147
|
validateProjectExtensions
|
|
148
|
-
} from "./index-
|
|
148
|
+
} from "./index-ncxfknbv.js";
|
|
149
149
|
import {
|
|
150
150
|
BUILD_DIAGNOSTIC_CODES
|
|
151
|
-
} from "./index-
|
|
151
|
+
} from "./index-zb48zwcq.js";
|
|
152
152
|
import {
|
|
153
153
|
BuildError
|
|
154
|
-
} from "./index-
|
|
154
|
+
} from "./index-w1qk3tap.js";
|
|
155
155
|
import {
|
|
156
156
|
DEFAULT_PRINT_OPTS,
|
|
157
157
|
assertMilestone,
|
|
@@ -29,6 +29,9 @@ export type ReadText = (relPath: string) => Promise<string>;
|
|
|
29
29
|
* `severity`) and `component_validate_failed` (the validator threw or
|
|
30
30
|
* returned something unusable).
|
|
31
31
|
*
|
|
32
|
+
* `unknown_variant` is emitted for a declared marker (container or
|
|
33
|
+
* `section: true`) whose bare word is not one of its declared `variants`.
|
|
34
|
+
*
|
|
32
35
|
* There is deliberately no `section_without_page`: a @section with no open
|
|
33
36
|
* @page is valid authoring (17/17 false positives across two real books).
|
|
34
37
|
*/
|
|
@@ -62,13 +62,36 @@ export interface GutterpressMarkerLabel {
|
|
|
62
62
|
* One entry in a plugin's declared `markers` table (#240 — "declarative
|
|
63
63
|
* container components in core"). Exactly one of three shapes:
|
|
64
64
|
*
|
|
65
|
-
* - a CONTAINER: `tag`/`class`/`variants`/`label`/`autoCloseAt`, any/all
|
|
65
|
+
* - a CONTAINER: `section`/`tag`/`class`/`variants`/`label`/`autoCloseAt`, any/all
|
|
66
66
|
* optional (a bare `{}` is a valid, if pointless, `<div>` wrapper);
|
|
67
67
|
* - an ALIAS: `alias` (another declared name) + optional `preset`;
|
|
68
68
|
* - a DEPRECATION: `deprecated` (a human-readable retirement message) —
|
|
69
69
|
* wins over every other field on the same entry, per
|
|
70
70
|
* `markers.js`'s `resolveMarkerDeclaration`.
|
|
71
71
|
*
|
|
72
|
+
* A container may instead set `section: true` (below) to be a core `@section`.
|
|
73
|
+
*
|
|
74
|
+
* TOKEN CONTRACT (public and stable). A declared container renders as a
|
|
75
|
+
* `layout_component_open` / `layout_component_close` token pair, so a plugin
|
|
76
|
+
* can "declare, then transform": declare the marker so core parses it
|
|
77
|
+
* (autocomplete, closing, warnings, source lines), then rewrite the tokens
|
|
78
|
+
* between the pair with an ordinary markdown-it core rule. The open token's
|
|
79
|
+
* `meta` is
|
|
80
|
+
*
|
|
81
|
+
* { line, component, kind, variant, attrs, labelled }
|
|
82
|
+
*
|
|
83
|
+
* - `line` the marker's 1-based line
|
|
84
|
+
* - `component` the marker name as typed (an alias's own name)
|
|
85
|
+
* - `kind` the resolved base marker name (an alias's target)
|
|
86
|
+
* - `variant` the bare word after the marker (or an alias's preset), or null
|
|
87
|
+
* - `attrs` the marker's attributes, as authored
|
|
88
|
+
* - `labelled` true when core injected a label `html_block` right after the open token
|
|
89
|
+
*
|
|
90
|
+
* The close token has no meta. A `section: true` marker produces the core
|
|
91
|
+
* `layout_section_open` / `layout_section_close` pair instead; its open token
|
|
92
|
+
* carries `{ line, component, kind, variant, attrs }` (plus `continued: true`
|
|
93
|
+
* on a `@continue` reopening) and a plain `@section`'s carries only `{ line }`.
|
|
94
|
+
*
|
|
72
95
|
* See `markers.js`'s header comment for a worked example and
|
|
73
96
|
* `buildDeclaredMarkerRegistry` for the full validation/resolution contract
|
|
74
97
|
* (collision rules, alias indirection, the auto-derived `@end-<name>`
|
|
@@ -78,6 +101,17 @@ export interface GutterpressMarkerLabel {
|
|
|
78
101
|
* plugin input.
|
|
79
102
|
*/
|
|
80
103
|
export interface GutterpressMarkerDeclaration {
|
|
104
|
+
/**
|
|
105
|
+
* This marker IS a core `@section`: `@npc-stat wirephreak .extra` renders
|
|
106
|
+
* exactly like `@section .<class> .<variants.wirephreak> .extra` (same
|
|
107
|
+
* classes, same order), closes like one (at the next `@section` / `@page` /
|
|
108
|
+
* `@chapter` / `@spread`, or `@end-<name>`, which acts as `@end-section`),
|
|
109
|
+
* and `@continue` reopens it with the same classes. The variant word is a
|
|
110
|
+
* variant, not a section name: it emits `data-<name>="<variant>"` (the
|
|
111
|
+
* alias target's name for an alias), never `data-section`. Cannot be combined
|
|
112
|
+
* with `tag`, `label` or `autoCloseAt`. Aliases of a section marker inherit it.
|
|
113
|
+
*/
|
|
114
|
+
section?: boolean;
|
|
81
115
|
/** Wrapper element tag. Defaults to `"div"`. */
|
|
82
116
|
tag?: string;
|
|
83
117
|
/** Base class(es) on the wrapper, e.g. `"dc-alert"`. */
|
|
@@ -118,7 +152,8 @@ export interface GutterpressMarkerDeclaration {
|
|
|
118
152
|
* (validate, Problems panel, build, preview). Receives a plain description
|
|
119
153
|
* of the component's content — see {@link GutterpressComponent} — and
|
|
120
154
|
* returns its problems. Must be synchronous; ignored on an alias (which
|
|
121
|
-
* uses its target's) and on a deprecated entry.
|
|
155
|
+
* uses its target's) and on a deprecated entry. Works on `section: true`
|
|
156
|
+
* markers too (a `@continue` continuation is not validated on its own).
|
|
122
157
|
*/
|
|
123
158
|
validate?: (component: GutterpressComponent) => GutterpressComponentProblems;
|
|
124
159
|
}
|
package/dist/lib/snippets.d.ts
CHANGED
|
@@ -83,6 +83,10 @@ export interface MarkerComponent {
|
|
|
83
83
|
source: Extract<SnippetSource, {
|
|
84
84
|
kind: "extension";
|
|
85
85
|
}>;
|
|
86
|
+
/** The variant names the marker accepts as its bare word (`@name <variant>`),
|
|
87
|
+
* as the renderer resolves them — an alias lists its target's. A variant
|
|
88
|
+
* only adds a class, so one snippet serves them all. */
|
|
89
|
+
variants: string[];
|
|
86
90
|
/** The winning example snippet's body (book, then extension, then core). */
|
|
87
91
|
snippet?: string;
|
|
88
92
|
}
|
|
@@ -7,16 +7,16 @@ import {
|
|
|
7
7
|
TARGET_IDS,
|
|
8
8
|
scaffoldExtension,
|
|
9
9
|
scaffoldProject
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-x9bb628z.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveGhostscript
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-14j4aqtc.js";
|
|
14
14
|
import {
|
|
15
15
|
UsageError,
|
|
16
16
|
rejectExtraPositionals,
|
|
17
17
|
rejectUnknownFlags
|
|
18
|
-
} from "./cli-
|
|
19
|
-
import"./cli-
|
|
18
|
+
} from "./cli-w9qc8fem.js";
|
|
19
|
+
import"./cli-8597az31.js";
|
|
20
20
|
import {
|
|
21
21
|
EXIT_CODES
|
|
22
22
|
} from "./cli-46ycxe6r.js";
|
|
@@ -62,6 +62,7 @@ const PREFIX = "{{PREFIX}}";
|
|
|
62
62
|
* @end-term-box
|
|
63
63
|
*
|
|
64
64
|
* Fields, all optional:
|
|
65
|
+
* section true makes the marker a core @section (no tag/label/autoCloseAt)
|
|
65
66
|
* tag wrapper element (default "div")
|
|
66
67
|
* class base class on the wrapper
|
|
67
68
|
* variants extra classes keyed by the marker's bare word
|
|
@@ -2,16 +2,16 @@ import {
|
|
|
2
2
|
executeValidation,
|
|
3
3
|
publishTargetFor,
|
|
4
4
|
reportMissingTools
|
|
5
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-x9bb628z.js";
|
|
6
6
|
import {
|
|
7
7
|
log
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-14j4aqtc.js";
|
|
9
9
|
import {
|
|
10
10
|
UsageError,
|
|
11
11
|
rejectExtraPositionals,
|
|
12
12
|
rejectUnknownFlags
|
|
13
|
-
} from "./cli-
|
|
14
|
-
import"./cli-
|
|
13
|
+
} from "./cli-w9qc8fem.js";
|
|
14
|
+
import"./cli-8597az31.js";
|
|
15
15
|
import {
|
|
16
16
|
EXIT_CODES
|
|
17
17
|
} from "./cli-46ycxe6r.js";
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
runBuild,
|
|
7
7
|
splitOutPath,
|
|
8
8
|
startPreviewServer
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-x9bb628z.js";
|
|
10
10
|
import {
|
|
11
11
|
log
|
|
12
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-14j4aqtc.js";
|
|
13
13
|
import {
|
|
14
14
|
UsageError,
|
|
15
15
|
parseFormat,
|
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
rejectExtraPositionals,
|
|
18
18
|
rejectUnknownFlags,
|
|
19
19
|
resolvePort
|
|
20
|
-
} from "./cli-
|
|
21
|
-
import"./cli-
|
|
20
|
+
} from "./cli-w9qc8fem.js";
|
|
21
|
+
import"./cli-8597az31.js";
|
|
22
22
|
import {
|
|
23
23
|
BuildError
|
|
24
24
|
} from "./cli-46ycxe6r.js";
|
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
publishProviderFor,
|
|
12
12
|
resolvePublishFormat,
|
|
13
13
|
runPublish
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-x9bb628z.js";
|
|
15
15
|
import {
|
|
16
16
|
FileTokenStore,
|
|
17
17
|
log
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-14j4aqtc.js";
|
|
19
19
|
import {
|
|
20
20
|
UsageError,
|
|
21
21
|
rejectExtraPositionals,
|
|
22
22
|
rejectUnknownFlags
|
|
23
|
-
} from "./cli-
|
|
24
|
-
import"./cli-
|
|
23
|
+
} from "./cli-w9qc8fem.js";
|
|
24
|
+
import"./cli-8597az31.js";
|
|
25
25
|
import {
|
|
26
26
|
EXIT_CODES
|
|
27
27
|
} from "./cli-46ycxe6r.js";
|
package/dist/render.js
CHANGED
|
@@ -350,6 +350,16 @@ function validateDeclaredMarkerName(name, pluginName) {
|
|
|
350
350
|
}
|
|
351
351
|
var TAG_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
352
352
|
function resolveContainerShape(name, pluginName, decl) {
|
|
353
|
+
if (decl.section !== undefined && typeof decl.section !== "boolean") {
|
|
354
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`section\` that is not a boolean.`);
|
|
355
|
+
}
|
|
356
|
+
if (decl.section) {
|
|
357
|
+
for (const field of ["tag", "label", "autoCloseAt"]) {
|
|
358
|
+
if (decl[field] !== undefined) {
|
|
359
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" sets \`section: true\` and \`${field}\` — a section ` + `marker is a core @section, so \`${field}\` does not apply. Remove one of them.`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
353
363
|
const tag = decl.tag !== undefined ? decl.tag : "div";
|
|
354
364
|
if (typeof tag !== "string" || !TAG_NAME_RE.test(tag)) {
|
|
355
365
|
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has an invalid \`tag\` (${JSON.stringify(decl.tag)}) — ` + `must be a lower-case HTML tag name.`);
|
|
@@ -405,7 +415,7 @@ function resolveContainerShape(name, pluginName, decl) {
|
|
|
405
415
|
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`validate\` that is not a function.`);
|
|
406
416
|
}
|
|
407
417
|
const check = decl.validate ? { validate: decl.validate, validateOwner: pluginName } : {};
|
|
408
|
-
return { tag, classBase, variants, label, autoCloseAtEof, ...check };
|
|
418
|
+
return { tag, classBase, variants, label, autoCloseAtEof, ...decl.section ? { section: true } : {}, ...check };
|
|
409
419
|
}
|
|
410
420
|
function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
|
|
411
421
|
const pluginName = originOf.get(name);
|
|
@@ -481,12 +491,12 @@ function declaredKindWords(declaredMarkers) {
|
|
|
481
491
|
}
|
|
482
492
|
return words;
|
|
483
493
|
}
|
|
484
|
-
function nearestDeclaredMarkerName(word,
|
|
494
|
+
function nearestDeclaredMarkerName(word, names) {
|
|
485
495
|
const w = word.toLowerCase();
|
|
486
496
|
const threshold = Math.max(2, Math.floor(w.length / 3));
|
|
487
497
|
let best = null;
|
|
488
498
|
let bestDistance = Infinity;
|
|
489
|
-
for (const known of
|
|
499
|
+
for (const known of names) {
|
|
490
500
|
const d = editDistance(w, known);
|
|
491
501
|
if (d < bestDistance) {
|
|
492
502
|
bestDistance = d;
|
|
@@ -514,13 +524,23 @@ function scanForUnknownDeclaredMarkers(state, declaredMarkers) {
|
|
|
514
524
|
const word = m[1];
|
|
515
525
|
if (KNOWN_KINDS.includes(word) || declaredMarkers.has(word))
|
|
516
526
|
continue;
|
|
517
|
-
const suggestion = nearestDeclaredMarkerName(word, declaredMarkers);
|
|
527
|
+
const suggestion = nearestDeclaredMarkerName(word, declaredMarkers.keys());
|
|
518
528
|
if (!suggestion)
|
|
519
529
|
continue;
|
|
520
530
|
warn(state.env, tok.map[0] + i + 1, "unknown_marker", `Unknown marker "@${word}". Did you mean "@${suggestion}"?`, null);
|
|
521
531
|
}
|
|
522
532
|
}
|
|
523
533
|
}
|
|
534
|
+
function warnUnknownVariant(env, meta, decl) {
|
|
535
|
+
const word = meta.name;
|
|
536
|
+
if (!word)
|
|
537
|
+
return;
|
|
538
|
+
const variants = Object.keys(decl.variants || {});
|
|
539
|
+
if (variants.includes(word))
|
|
540
|
+
return;
|
|
541
|
+
const near = variants.find((v) => v.toLowerCase() === word.toLowerCase()) || (word.length >= 3 ? nearestDeclaredMarkerName(word, variants) : null);
|
|
542
|
+
warn(env, meta.__line, "unknown_variant", `"${word}" is not a variant of @${meta.kind}, so it adds no styling. ` + (variants.length ? `Variants: ${variants.join(", ")}.` : `@${meta.kind} has no variants.`) + (near ? ` Did you mean "${near}"?` : ""), meta);
|
|
543
|
+
}
|
|
524
544
|
function plugin(md, pluginOptions = {}) {
|
|
525
545
|
const options = {
|
|
526
546
|
preferPagesInSpreads: false,
|
|
@@ -630,7 +650,15 @@ function plugin(md, pluginOptions = {}) {
|
|
|
630
650
|
function openDeclaredMarker(meta, decl) {
|
|
631
651
|
const t = new state.Token("layout_component_open", decl.tag, 1);
|
|
632
652
|
const variant = meta.name || decl.presetVariant || null;
|
|
633
|
-
|
|
653
|
+
warnUnknownVariant(state.env, meta, decl);
|
|
654
|
+
t.meta = {
|
|
655
|
+
line: meta.__line,
|
|
656
|
+
component: meta.kind,
|
|
657
|
+
kind: decl.baseKind,
|
|
658
|
+
variant,
|
|
659
|
+
attrs: meta.attrs || {},
|
|
660
|
+
labelled: false
|
|
661
|
+
};
|
|
634
662
|
const variantClass = variant && decl.variants && decl.variants[variant] || "";
|
|
635
663
|
const baseClass = [decl.classBase, variantClass].filter(Boolean).join(" ");
|
|
636
664
|
addClasses(t, baseClass, meta.attrs && meta.attrs.class ? meta.attrs.class : "");
|
|
@@ -738,16 +766,34 @@ function plugin(md, pluginOptions = {}) {
|
|
|
738
766
|
warn(state.env, meta.__line || 0, "page_outside_spread", "@page used outside of a spread; allowed, but spreads are recommended for deliberate grouping.", meta);
|
|
739
767
|
}
|
|
740
768
|
}
|
|
769
|
+
function sectionMetaFor(meta, decl) {
|
|
770
|
+
const attrs = meta.attrs || {};
|
|
771
|
+
const variant = meta.name || decl.presetVariant || null;
|
|
772
|
+
warnUnknownVariant(state.env, meta, decl);
|
|
773
|
+
const variantClass = variant && decl.variants && decl.variants[variant] || "";
|
|
774
|
+
const cls = [decl.classBase, variantClass, attrs.class].filter(Boolean).join(" ");
|
|
775
|
+
return {
|
|
776
|
+
kind: "section",
|
|
777
|
+
name: null,
|
|
778
|
+
attrs: cls ? { ...attrs, class: cls } : attrs,
|
|
779
|
+
__line: meta.__line,
|
|
780
|
+
__component: { component: meta.kind, kind: decl.baseKind, variant, attrs }
|
|
781
|
+
};
|
|
782
|
+
}
|
|
741
783
|
function openSection(meta) {
|
|
742
784
|
const t = new state.Token("layout_section_open", "div", 1);
|
|
785
|
+
const component = meta.__component || null;
|
|
743
786
|
addClasses(t, "section", meta.attrs && meta.attrs.class ? meta.attrs.class : "");
|
|
744
|
-
|
|
745
|
-
|
|
787
|
+
if (component)
|
|
788
|
+
attachDataAttrs(t, component.kind, component.variant, meta.attrs || {});
|
|
789
|
+
else
|
|
790
|
+
attachDataAttrs(t, "section", meta.name, meta.attrs || {});
|
|
791
|
+
t.meta = component ? { line: meta.__line, ...component, ...meta.__continued ? { continued: true } : {} } : { line: meta.__line };
|
|
746
792
|
stack.open({
|
|
747
793
|
kind: "section",
|
|
748
794
|
classes: meta.attrs && meta.attrs.class || "",
|
|
749
795
|
sawContent: false,
|
|
750
|
-
meta: { name: meta.name || null, attrs: { ...meta.attrs || {} } },
|
|
796
|
+
meta: { name: meta.name || null, attrs: { ...meta.attrs || {} }, component },
|
|
751
797
|
openToken: t
|
|
752
798
|
}, t);
|
|
753
799
|
}
|
|
@@ -793,9 +839,21 @@ function plugin(md, pluginOptions = {}) {
|
|
|
793
839
|
out.push(tok);
|
|
794
840
|
continue;
|
|
795
841
|
}
|
|
796
|
-
|
|
797
|
-
|
|
842
|
+
let meta = tok.meta || {};
|
|
843
|
+
let kind = meta.kind;
|
|
798
844
|
const line = meta.__line || 0;
|
|
845
|
+
if (declaredMarkers) {
|
|
846
|
+
const closing = kind.startsWith("end-");
|
|
847
|
+
const sectionDecl = declaredMarkers.get(closing ? kind.slice(4) : kind);
|
|
848
|
+
if (sectionDecl && sectionDecl.section) {
|
|
849
|
+
if (closing) {
|
|
850
|
+
kind = "end-section";
|
|
851
|
+
} else {
|
|
852
|
+
meta = sectionMetaFor(meta, sectionDecl);
|
|
853
|
+
kind = "section";
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
799
857
|
if (kind === "chapter") {
|
|
800
858
|
drainDeclaredFrames();
|
|
801
859
|
stack.close("chapter");
|
|
@@ -839,6 +897,10 @@ function plugin(md, pluginOptions = {}) {
|
|
|
839
897
|
name: section.meta.name,
|
|
840
898
|
attrs: { ...section.meta.attrs || {} }
|
|
841
899
|
};
|
|
900
|
+
if (section.meta.component) {
|
|
901
|
+
contMeta.__component = section.meta.component;
|
|
902
|
+
contMeta.__continued = true;
|
|
903
|
+
}
|
|
842
904
|
contMeta.__line = line;
|
|
843
905
|
const cls = (contMeta.attrs.class || "").split(/\s+/).filter(Boolean);
|
|
844
906
|
if (!cls.includes("gp-continued"))
|
|
@@ -912,7 +974,8 @@ function plugin(md, pluginOptions = {}) {
|
|
|
912
974
|
const tokens = state.tokens;
|
|
913
975
|
for (let i = 0;i < tokens.length; i++) {
|
|
914
976
|
const tok = tokens[i];
|
|
915
|
-
|
|
977
|
+
const isSection = tok.type === "layout_section_open" && tok.meta && tok.meta.component && !tok.meta.continued;
|
|
978
|
+
if (tok.type !== "layout_component_open" && !isSection)
|
|
916
979
|
continue;
|
|
917
980
|
const decl = declaredMarkers.get(tok.meta.component);
|
|
918
981
|
if (!decl || !decl.validate)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeAndReport
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-x9bb628z.js";
|
|
4
4
|
import {
|
|
5
5
|
log
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-14j4aqtc.js";
|
|
7
7
|
import {
|
|
8
8
|
UsageError,
|
|
9
9
|
rejectExtraPositionals,
|
|
10
10
|
rejectUnknownFlags
|
|
11
|
-
} from "./cli-
|
|
12
|
-
import"./cli-
|
|
11
|
+
} from "./cli-w9qc8fem.js";
|
|
12
|
+
import"./cli-8597az31.js";
|
|
13
13
|
import {
|
|
14
14
|
EXIT_CODES
|
|
15
15
|
} from "./cli-46ycxe6r.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gutterpress",
|
|
3
|
-
"version": "0.11.16-alpha.
|
|
3
|
+
"version": "0.11.16-alpha.3",
|
|
4
4
|
"description": "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
5
5
|
"author": "itlackey",
|
|
6
6
|
"license": "MPL-2.0",
|