gutterpress 0.11.23-alpha.2 → 0.11.23-alpha.4
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 +10 -13
- package/dist/{README-8ef336pp.md → README-syg2hn83.md} +13 -19
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +5 -5
- package/dist/{build-encgnv0c.js → build-c48eer6f.js} +8 -8
- package/dist/checks/asset/extensions.d.ts +1 -1
- package/dist/checks/asset/index.d.ts +0 -1
- package/dist/checks/policy.d.ts +5 -4
- package/dist/checks/source/config-file.d.ts +9 -6
- package/dist/checks/source/dangling-links.d.ts +1 -1
- package/dist/checks/types.d.ts +2 -2
- package/dist/{cli-pz4bn98t.js → cli-54xt7pjg.js} +19 -13
- package/dist/{index-2ppw6q9v.js → cli-5crpmz42.js} +80 -1
- package/dist/{cli-xq6djqbj.js → cli-93mkaw6v.js} +166 -308
- package/dist/{cli-evg8sbht.js → cli-d9mm3vvh.js} +7 -2
- package/dist/{cli-kh8v4vvw.js → cli-gnpea9dx.js} +1 -1
- package/dist/{cli-aqh6brew.js → cli-pspjxnc8.js} +1 -1
- package/dist/{cli-pwwfxdgb.js → cli-rqh295j9.js} +15 -21
- package/dist/{index-x3ema2w3.js → cli-y6d1arem.js} +321 -272
- package/dist/cli.js +12 -12
- package/dist/{doctor-5gtpgpd1.js → doctor-ptb346k8.js} +4 -3
- package/dist/engine/shared/gcpm-extract.d.ts +8 -0
- package/dist/engine/shared/print-area.d.ts +16 -4
- package/dist/{engine-mc5br8g8.js → engine-4rzdx6af.js} +1 -1
- package/dist/{engine-tn13gk0b.js → engine-6txhxmmv.js} +2 -2
- package/dist/{ext-wn2a5afq.js → ext-gy8szg3x.js} +8 -8
- package/dist/{extension-restore-s3x1618g.js → extension-restore-dymzcasz.js} +2 -2
- package/dist/{extension-restore-g8jnmmzq.js → extension-restore-m8tj43e7.js} +4 -4
- package/dist/{gutterpress-viewer-701vf4qp.js → gutterpress-viewer-mafsby5k.js} +9 -2
- package/dist/{cli-2ppw6q9v.js → index-5crpmz42.js} +80 -1
- package/dist/{index-0skhjx3e.js → index-5kh4c78h.js} +19 -13
- package/dist/{index-2bjcghze.js → index-8ywkd2sv.js} +15 -21
- package/dist/{index-j5z86r4a.js → index-ea94zbq4.js} +329 -488
- package/dist/{cli-sdmv4bba.js → index-kaks3mm2.js} +448 -156
- package/dist/{index-4x6y8krm.js → index-yc3xj266.js} +1 -1
- package/dist/index.js +6 -6
- package/dist/lib/build-preflight.d.ts +4 -10
- package/dist/lib/build-runner.d.ts +1 -1
- package/dist/lib/extension-manager.d.ts +8 -7
- package/dist/lib/extension-manifest.d.ts +1 -13
- package/dist/lib/ghostscript.d.ts +5 -2
- package/dist/lib/lint-rules.d.ts +5 -1
- package/dist/lib/manifest-config.d.ts +3 -2
- package/dist/lib/manifest-old-spellings.d.ts +64 -0
- package/dist/lib/manifest.d.ts +15 -1
- package/dist/lib/markdown/assemble.d.ts +4 -3
- package/dist/lib/markdown/chapter-id.d.ts +1 -1
- package/dist/lib/markdown/index.d.ts +1 -1
- package/dist/lib/markdown/table.d.ts +5 -3
- package/dist/lib/page-size.d.ts +45 -33
- package/dist/lib/pdf-inspect.d.ts +27 -0
- package/dist/lib/presets.d.ts +10 -8
- package/dist/lib/printsafe.d.ts +2 -1
- package/dist/lib/project-scaffold.d.ts +1 -1
- package/dist/lib/project-templates.d.ts +9 -0
- package/dist/lib/remote-auth/sync-messages.d.ts +2 -2
- package/dist/lib/targets.d.ts +4 -4
- package/dist/lib/validation-exec.d.ts +4 -4
- package/dist/manifest-2kc56wvw.yaml +22 -0
- package/dist/manifest-41ddzm13.yaml +18 -0
- package/dist/manifest-79zsgkpn.yaml +26 -0
- package/dist/manifest-sqzm4681.yaml +22 -0
- package/dist/{manifest.schema-t7nx2stg.json → manifest.schema-w86c1xw1.json} +30 -308
- package/dist/{new-mhs46pw3.js → new-t2t28ccb.js} +9 -15
- package/dist/{package-aenwjew3.json → package-awwkt7sa.json} +0 -1
- package/dist/{page-rules-nsj3aw42.css → page-rules-ytj9p04v.css} +12 -40
- package/dist/{pdf-inspect-wnw4za71.js → pdf-inspect-b3mf81ex.js} +3 -1
- package/dist/{plugin.test.js-xgxrd8hf.tpl → plugin.test.js-gxzqqfdh.tpl} +0 -1
- package/dist/{plugins-2cek4mz1.js → plugins-fec8t2bh.js} +1 -1
- package/dist/{plugins-1sxe0dkz.js → plugins-sqa4msdk.js} +3 -3
- package/dist/{preflight-3k2b1x8e.js → preflight-srq8fktp.js} +8 -8
- package/dist/preview/file-watcher.d.ts +1 -3
- package/dist/{preview-6p9v6rht.js → preview-zsp9hstd.js} +8 -8
- package/dist/{publish-qgsngy8s.js → publish-hhy31gr9.js} +8 -8
- package/dist/render.js +30 -562
- package/dist/schema/manifest.types.d.ts +60 -105
- package/dist/{tokens-7984461t.css → tokens-n82t4k9h.css} +12 -12
- package/dist/{validate-0v7xw6wa.js → validate-r9jdz85h.js} +8 -8
- package/package.json +1 -1
- package/dist/checks/asset/approved-fonts.d.ts +0 -3
- package/dist/manifest-eagfhba6.yaml +0 -19
- package/dist/manifest-n1gh3qw5.yaml +0 -9
package/dist/render.js
CHANGED
|
@@ -1997,7 +1997,12 @@ function splitCells(str, spans) {
|
|
|
1997
1997
|
lastPos = pos;
|
|
1998
1998
|
}
|
|
1999
1999
|
} else if (!isEscaped && spans[ch]) {
|
|
2000
|
-
|
|
2000
|
+
const end = spans[ch](str, pos, max);
|
|
2001
|
+
if (ch === 96) {
|
|
2002
|
+
current += str.substring(lastPos, pos) + str.substring(pos, end).replace(/\\\|/g, "|");
|
|
2003
|
+
lastPos = end;
|
|
2004
|
+
}
|
|
2005
|
+
pos = end;
|
|
2001
2006
|
continue;
|
|
2002
2007
|
}
|
|
2003
2008
|
isEscaped = ch === 92;
|
|
@@ -2991,458 +2996,6 @@ function printAreaMeta(page) {
|
|
|
2991
2996
|
}
|
|
2992
2997
|
|
|
2993
2998
|
// src/engine/shared/gcpm-extract.ts
|
|
2994
|
-
var NESTED_AT_RULES = /^@(media|supports|layer|scope|container|document)\b/i;
|
|
2995
|
-
function scanRules(css) {
|
|
2996
|
-
const out = [];
|
|
2997
|
-
let i = 0;
|
|
2998
|
-
let start = 0;
|
|
2999
|
-
let depth = 0;
|
|
3000
|
-
let bodyStart = -1;
|
|
3001
|
-
while (i < css.length) {
|
|
3002
|
-
const c = css[i];
|
|
3003
|
-
if (c === "/" && css[i + 1] === "*") {
|
|
3004
|
-
const end = css.indexOf("*/", i + 2);
|
|
3005
|
-
i = end === -1 ? css.length : end + 2;
|
|
3006
|
-
continue;
|
|
3007
|
-
}
|
|
3008
|
-
if (c === '"' || c === "'") {
|
|
3009
|
-
i = skipString(css, i);
|
|
3010
|
-
continue;
|
|
3011
|
-
}
|
|
3012
|
-
if (c === "{") {
|
|
3013
|
-
if (depth === 0)
|
|
3014
|
-
bodyStart = i;
|
|
3015
|
-
depth++;
|
|
3016
|
-
i++;
|
|
3017
|
-
continue;
|
|
3018
|
-
}
|
|
3019
|
-
if (c === "}") {
|
|
3020
|
-
depth--;
|
|
3021
|
-
if (depth === 0) {
|
|
3022
|
-
out.push({
|
|
3023
|
-
prelude: stripComments(css.slice(start, bodyStart)).trim(),
|
|
3024
|
-
body: css.slice(bodyStart + 1, i)
|
|
3025
|
-
});
|
|
3026
|
-
start = i + 1;
|
|
3027
|
-
}
|
|
3028
|
-
i++;
|
|
3029
|
-
continue;
|
|
3030
|
-
}
|
|
3031
|
-
if (c === ";" && depth === 0) {
|
|
3032
|
-
const stmt = stripComments(css.slice(start, i)).trim();
|
|
3033
|
-
if (stmt)
|
|
3034
|
-
out.push({ statement: stmt });
|
|
3035
|
-
start = i + 1;
|
|
3036
|
-
i++;
|
|
3037
|
-
continue;
|
|
3038
|
-
}
|
|
3039
|
-
i++;
|
|
3040
|
-
}
|
|
3041
|
-
return out;
|
|
3042
|
-
}
|
|
3043
|
-
function stripComments(s) {
|
|
3044
|
-
let out = "";
|
|
3045
|
-
let i = 0;
|
|
3046
|
-
while (i < s.length) {
|
|
3047
|
-
if (s[i] === "/" && s[i + 1] === "*") {
|
|
3048
|
-
const end = s.indexOf("*/", i + 2);
|
|
3049
|
-
i = end === -1 ? s.length : end + 2;
|
|
3050
|
-
continue;
|
|
3051
|
-
}
|
|
3052
|
-
if (s[i] === '"' || s[i] === "'") {
|
|
3053
|
-
const end = skipString(s, i);
|
|
3054
|
-
out += s.slice(i, end);
|
|
3055
|
-
i = end;
|
|
3056
|
-
continue;
|
|
3057
|
-
}
|
|
3058
|
-
out += s[i++];
|
|
3059
|
-
}
|
|
3060
|
-
return out;
|
|
3061
|
-
}
|
|
3062
|
-
function skipString(css, i) {
|
|
3063
|
-
const quote = css[i];
|
|
3064
|
-
i++;
|
|
3065
|
-
while (i < css.length) {
|
|
3066
|
-
if (css[i] === "\\")
|
|
3067
|
-
i += 2;
|
|
3068
|
-
else if (css[i] === quote)
|
|
3069
|
-
return i + 1;
|
|
3070
|
-
else
|
|
3071
|
-
i++;
|
|
3072
|
-
}
|
|
3073
|
-
return i;
|
|
3074
|
-
}
|
|
3075
|
-
function parseDeclarations(body) {
|
|
3076
|
-
const decls = {};
|
|
3077
|
-
let i = 0;
|
|
3078
|
-
let start = 0;
|
|
3079
|
-
let depth = 0;
|
|
3080
|
-
const push = (chunk) => {
|
|
3081
|
-
const s = stripComments(chunk).trim();
|
|
3082
|
-
if (!s)
|
|
3083
|
-
return;
|
|
3084
|
-
const colon = indexOfTopLevel(s, ":");
|
|
3085
|
-
if (colon <= 0)
|
|
3086
|
-
return;
|
|
3087
|
-
const rawProp = s.slice(0, colon).trim();
|
|
3088
|
-
const prop = rawProp.startsWith("--") ? rawProp : rawProp.toLowerCase();
|
|
3089
|
-
const value = s.slice(colon + 1).trim().replace(/\s*!important$/i, "");
|
|
3090
|
-
if (prop)
|
|
3091
|
-
decls[prop] = value;
|
|
3092
|
-
};
|
|
3093
|
-
while (i < body.length) {
|
|
3094
|
-
const c = body[i];
|
|
3095
|
-
if (c === "/" && body[i + 1] === "*") {
|
|
3096
|
-
const end = body.indexOf("*/", i + 2);
|
|
3097
|
-
i = end === -1 ? body.length : end + 2;
|
|
3098
|
-
continue;
|
|
3099
|
-
}
|
|
3100
|
-
if (c === '"' || c === "'") {
|
|
3101
|
-
i = skipString(body, i);
|
|
3102
|
-
continue;
|
|
3103
|
-
}
|
|
3104
|
-
if (c === "(" || c === "{" || c === "[")
|
|
3105
|
-
depth++;
|
|
3106
|
-
else if (c === ")" || c === "}" || c === "]")
|
|
3107
|
-
depth--;
|
|
3108
|
-
else if (c === ";" && depth === 0) {
|
|
3109
|
-
push(body.slice(start, i));
|
|
3110
|
-
start = i + 1;
|
|
3111
|
-
}
|
|
3112
|
-
i++;
|
|
3113
|
-
}
|
|
3114
|
-
push(body.slice(start));
|
|
3115
|
-
return decls;
|
|
3116
|
-
}
|
|
3117
|
-
function indexOfTopLevel(s, ch) {
|
|
3118
|
-
let depth = 0;
|
|
3119
|
-
for (let i = 0;i < s.length; i++) {
|
|
3120
|
-
const c = s[i];
|
|
3121
|
-
if (c === '"' || c === "'") {
|
|
3122
|
-
i = skipString(s, i) - 1;
|
|
3123
|
-
continue;
|
|
3124
|
-
}
|
|
3125
|
-
if (c === "(")
|
|
3126
|
-
depth++;
|
|
3127
|
-
else if (c === ")")
|
|
3128
|
-
depth--;
|
|
3129
|
-
else if (c === ch && depth === 0)
|
|
3130
|
-
return i;
|
|
3131
|
-
}
|
|
3132
|
-
return -1;
|
|
3133
|
-
}
|
|
3134
|
-
function extract(css) {
|
|
3135
|
-
const model = {
|
|
3136
|
-
pageRules: [],
|
|
3137
|
-
stringSets: [],
|
|
3138
|
-
pageAssignments: [],
|
|
3139
|
-
breaks: [],
|
|
3140
|
-
xrefs: [],
|
|
3141
|
-
counterResets: [],
|
|
3142
|
-
pageNames: [],
|
|
3143
|
-
warnings: []
|
|
3144
|
-
};
|
|
3145
|
-
walk(css, model);
|
|
3146
|
-
resolveGeometryVars(model, collectRootCustomProperties(css));
|
|
3147
|
-
const names = new Set;
|
|
3148
|
-
for (const r of model.pageRules)
|
|
3149
|
-
if (r.name)
|
|
3150
|
-
names.add(r.name);
|
|
3151
|
-
for (const a of model.pageAssignments)
|
|
3152
|
-
names.add(a.page);
|
|
3153
|
-
model.pageNames = [...names];
|
|
3154
|
-
return model;
|
|
3155
|
-
}
|
|
3156
|
-
var GEOMETRY_PROPS = [
|
|
3157
|
-
"size",
|
|
3158
|
-
"margin",
|
|
3159
|
-
"margin-top",
|
|
3160
|
-
"margin-right",
|
|
3161
|
-
"margin-bottom",
|
|
3162
|
-
"margin-left",
|
|
3163
|
-
"bleed",
|
|
3164
|
-
"marks"
|
|
3165
|
-
];
|
|
3166
|
-
function collectRootCustomProperties(css) {
|
|
3167
|
-
const props = new Map;
|
|
3168
|
-
const walkForRoot = (body) => {
|
|
3169
|
-
for (const rule of scanRules(body)) {
|
|
3170
|
-
if ("statement" in rule)
|
|
3171
|
-
continue;
|
|
3172
|
-
const { prelude, body: ruleBody } = rule;
|
|
3173
|
-
if (NESTED_AT_RULES.test(prelude)) {
|
|
3174
|
-
walkForRoot(ruleBody);
|
|
3175
|
-
continue;
|
|
3176
|
-
}
|
|
3177
|
-
if (!prelude.startsWith("@")) {
|
|
3178
|
-
const selectors = splitTopLevel(prelude, ",");
|
|
3179
|
-
if (selectors.some((s) => s.trim() === ":root")) {
|
|
3180
|
-
const decls = parseDeclarations(ruleBody);
|
|
3181
|
-
for (const [k, v] of Object.entries(decls)) {
|
|
3182
|
-
if (k.startsWith("--"))
|
|
3183
|
-
props.set(k, v);
|
|
3184
|
-
}
|
|
3185
|
-
}
|
|
3186
|
-
}
|
|
3187
|
-
}
|
|
3188
|
-
};
|
|
3189
|
-
walkForRoot(css);
|
|
3190
|
-
return props;
|
|
3191
|
-
}
|
|
3192
|
-
function matchParen(s, open) {
|
|
3193
|
-
let depth = 0;
|
|
3194
|
-
let i = open;
|
|
3195
|
-
while (i < s.length) {
|
|
3196
|
-
const c = s[i];
|
|
3197
|
-
if (c === '"' || c === "'") {
|
|
3198
|
-
i = skipString(s, i);
|
|
3199
|
-
continue;
|
|
3200
|
-
}
|
|
3201
|
-
if (c === "(")
|
|
3202
|
-
depth++;
|
|
3203
|
-
else if (c === ")") {
|
|
3204
|
-
depth--;
|
|
3205
|
-
if (depth === 0)
|
|
3206
|
-
return i;
|
|
3207
|
-
}
|
|
3208
|
-
i++;
|
|
3209
|
-
}
|
|
3210
|
-
return -1;
|
|
3211
|
-
}
|
|
3212
|
-
function resolveVarsInValue(value, customProps, stack = new Set) {
|
|
3213
|
-
let out = "";
|
|
3214
|
-
let i = 0;
|
|
3215
|
-
while (i < value.length) {
|
|
3216
|
-
const isVarStart = /^var\(/i.test(value.slice(i, i + 4)) && (i === 0 || !/[\w-]/.test(value[i - 1]));
|
|
3217
|
-
if (!isVarStart) {
|
|
3218
|
-
out += value[i];
|
|
3219
|
-
i++;
|
|
3220
|
-
continue;
|
|
3221
|
-
}
|
|
3222
|
-
const open = i + 3;
|
|
3223
|
-
const close = matchParen(value, open);
|
|
3224
|
-
if (close === -1) {
|
|
3225
|
-
out += value.slice(i);
|
|
3226
|
-
break;
|
|
3227
|
-
}
|
|
3228
|
-
const inner = value.slice(open + 1, close);
|
|
3229
|
-
const commaIdx = indexOfTopLevel(inner, ",");
|
|
3230
|
-
const name = (commaIdx === -1 ? inner : inner.slice(0, commaIdx)).trim();
|
|
3231
|
-
const fallback = commaIdx === -1 ? undefined : inner.slice(commaIdx + 1).trim();
|
|
3232
|
-
if (!/^--[\w-]+$/.test(name)) {
|
|
3233
|
-
return { text: out, unresolved: `var(${inner}) is not a valid custom property reference` };
|
|
3234
|
-
}
|
|
3235
|
-
if (stack.has(name)) {
|
|
3236
|
-
return { text: out, unresolved: `var(${name}) is circular` };
|
|
3237
|
-
}
|
|
3238
|
-
const rootValue = customProps.get(name);
|
|
3239
|
-
if (rootValue !== undefined) {
|
|
3240
|
-
const nested = resolveVarsInValue(rootValue, customProps, new Set(stack).add(name));
|
|
3241
|
-
if (nested.unresolved)
|
|
3242
|
-
return { text: out, unresolved: nested.unresolved };
|
|
3243
|
-
out += nested.text;
|
|
3244
|
-
} else if (fallback !== undefined) {
|
|
3245
|
-
if (/\bvar\(/i.test(fallback)) {
|
|
3246
|
-
return {
|
|
3247
|
-
text: out,
|
|
3248
|
-
unresolved: `var(${name}, ${fallback}) — a fallback containing another var() is not resolved`
|
|
3249
|
-
};
|
|
3250
|
-
}
|
|
3251
|
-
out += fallback;
|
|
3252
|
-
} else {
|
|
3253
|
-
return {
|
|
3254
|
-
text: out,
|
|
3255
|
-
unresolved: `${name} is not defined at :root and var() has no fallback`
|
|
3256
|
-
};
|
|
3257
|
-
}
|
|
3258
|
-
i = close + 1;
|
|
3259
|
-
}
|
|
3260
|
-
return { text: out };
|
|
3261
|
-
}
|
|
3262
|
-
function resolveGeometryVars(model, customProps) {
|
|
3263
|
-
for (const rule of model.pageRules) {
|
|
3264
|
-
for (const prop of GEOMETRY_PROPS) {
|
|
3265
|
-
const value = rule.decls[prop];
|
|
3266
|
-
if (!value || !/\bvar\(/i.test(value))
|
|
3267
|
-
continue;
|
|
3268
|
-
const { text, unresolved } = resolveVarsInValue(value, customProps);
|
|
3269
|
-
if (unresolved) {
|
|
3270
|
-
throw new Error(`${rule.raw} { ${prop}: ${value} } — cannot resolve ${unresolved}. ` + `Define the custom property at :root, add a literal var(--x, fallback) fallback, or use a literal value.`);
|
|
3271
|
-
}
|
|
3272
|
-
const unparsable = unparsableGeometry(prop, text);
|
|
3273
|
-
if (unparsable) {
|
|
3274
|
-
throw new Error(`${rule.raw} { ${prop}: ${value} } — resolves to \`${text.trim()}\`, ${unparsable}. ` + `Use a value this engine can read (a length like 0.75in/12pt/10mm, or a named page size for \`size\`).`);
|
|
3275
|
-
}
|
|
3276
|
-
rule.decls[prop] = text;
|
|
3277
|
-
}
|
|
3278
|
-
}
|
|
3279
|
-
}
|
|
3280
|
-
function unparsableGeometry(prop, text) {
|
|
3281
|
-
const t = text.trim();
|
|
3282
|
-
if (prop === "size") {
|
|
3283
|
-
if (!t)
|
|
3284
|
-
return "which is empty";
|
|
3285
|
-
return parseSize(t) ? undefined : "which is not a page size";
|
|
3286
|
-
}
|
|
3287
|
-
if (prop === "margin" || prop.startsWith("margin-")) {
|
|
3288
|
-
if (!t)
|
|
3289
|
-
return "which is empty";
|
|
3290
|
-
const parts = t.split(/\s+/);
|
|
3291
|
-
if (prop !== "margin" && parts.length !== 1)
|
|
3292
|
-
return "which is not a single length";
|
|
3293
|
-
if (parts.length > 4)
|
|
3294
|
-
return "which is not a valid margin";
|
|
3295
|
-
const bad = parts.filter((p) => toPt(p) === undefined);
|
|
3296
|
-
if (bad.length)
|
|
3297
|
-
return `which this engine cannot read as a length (\`${bad[0]}\`)`;
|
|
3298
|
-
return;
|
|
3299
|
-
}
|
|
3300
|
-
if (prop === "bleed") {
|
|
3301
|
-
if (!t)
|
|
3302
|
-
return "which is empty";
|
|
3303
|
-
if (/^(auto|none)$/i.test(t))
|
|
3304
|
-
return;
|
|
3305
|
-
return toPt(t) === undefined ? "which this engine cannot read as a length" : undefined;
|
|
3306
|
-
}
|
|
3307
|
-
return;
|
|
3308
|
-
}
|
|
3309
|
-
function walk(css, model) {
|
|
3310
|
-
for (const rule of scanRules(css)) {
|
|
3311
|
-
if ("statement" in rule)
|
|
3312
|
-
continue;
|
|
3313
|
-
const { prelude, body } = rule;
|
|
3314
|
-
if (NESTED_AT_RULES.test(prelude)) {
|
|
3315
|
-
walk(body, model);
|
|
3316
|
-
continue;
|
|
3317
|
-
}
|
|
3318
|
-
if (/^@page\b/i.test(prelude)) {
|
|
3319
|
-
model.pageRules.push(parsePageRule(prelude, body));
|
|
3320
|
-
continue;
|
|
3321
|
-
}
|
|
3322
|
-
if (prelude.startsWith("@"))
|
|
3323
|
-
continue;
|
|
3324
|
-
parseQualifiedRule(prelude, body, model);
|
|
3325
|
-
}
|
|
3326
|
-
}
|
|
3327
|
-
function parsePageRule(prelude, body) {
|
|
3328
|
-
const sel = prelude.replace(/^@page\s*/i, "").trim();
|
|
3329
|
-
const nameMatch = /^([A-Za-z_][\w-]*)/.exec(sel);
|
|
3330
|
-
const pseudos = [...sel.matchAll(/:([A-Za-z-]+)(\([^)]*\))?/g)].map((m) => m[1] + (m[2] ?? ""));
|
|
3331
|
-
const rule = {
|
|
3332
|
-
name: nameMatch?.[1],
|
|
3333
|
-
pseudos,
|
|
3334
|
-
decls: {},
|
|
3335
|
-
marginBoxes: {},
|
|
3336
|
-
raw: `@page ${sel}`.trim()
|
|
3337
|
-
};
|
|
3338
|
-
let rest = "";
|
|
3339
|
-
let i = 0;
|
|
3340
|
-
while (i < body.length) {
|
|
3341
|
-
const at = findNextAtRule(body, i);
|
|
3342
|
-
if (at === -1) {
|
|
3343
|
-
rest += body.slice(i);
|
|
3344
|
-
break;
|
|
3345
|
-
}
|
|
3346
|
-
rest += body.slice(i, at);
|
|
3347
|
-
const open = body.indexOf("{", at);
|
|
3348
|
-
if (open === -1) {
|
|
3349
|
-
rest += body.slice(at);
|
|
3350
|
-
break;
|
|
3351
|
-
}
|
|
3352
|
-
const name = body.slice(at + 1, open).trim().toLowerCase();
|
|
3353
|
-
let depth = 1;
|
|
3354
|
-
let j = open + 1;
|
|
3355
|
-
while (j < body.length && depth > 0) {
|
|
3356
|
-
const c = body[j];
|
|
3357
|
-
if (c === "/" && body[j + 1] === "*") {
|
|
3358
|
-
const end = body.indexOf("*/", j + 2);
|
|
3359
|
-
j = end === -1 ? body.length : end + 2;
|
|
3360
|
-
continue;
|
|
3361
|
-
}
|
|
3362
|
-
if (c === '"' || c === "'") {
|
|
3363
|
-
j = skipString(body, j);
|
|
3364
|
-
continue;
|
|
3365
|
-
}
|
|
3366
|
-
if (c === "{")
|
|
3367
|
-
depth++;
|
|
3368
|
-
else if (c === "}")
|
|
3369
|
-
depth--;
|
|
3370
|
-
j++;
|
|
3371
|
-
}
|
|
3372
|
-
rule.marginBoxes[`@${name}`] = parseDeclarations(body.slice(open + 1, j - 1));
|
|
3373
|
-
i = j;
|
|
3374
|
-
}
|
|
3375
|
-
rule.decls = parseDeclarations(rest);
|
|
3376
|
-
return rule;
|
|
3377
|
-
}
|
|
3378
|
-
function findNextAtRule(body, start) {
|
|
3379
|
-
let i = start;
|
|
3380
|
-
while (i < body.length) {
|
|
3381
|
-
const c = body[i];
|
|
3382
|
-
if (c === "/" && body[i + 1] === "*") {
|
|
3383
|
-
const end = body.indexOf("*/", i + 2);
|
|
3384
|
-
i = end === -1 ? body.length : end + 2;
|
|
3385
|
-
continue;
|
|
3386
|
-
}
|
|
3387
|
-
if (c === '"' || c === "'") {
|
|
3388
|
-
i = skipString(body, i);
|
|
3389
|
-
continue;
|
|
3390
|
-
}
|
|
3391
|
-
if (c === "@")
|
|
3392
|
-
return i;
|
|
3393
|
-
i++;
|
|
3394
|
-
}
|
|
3395
|
-
return -1;
|
|
3396
|
-
}
|
|
3397
|
-
function parseQualifiedRule(selector, body, model) {
|
|
3398
|
-
const decls = parseDeclarations(body);
|
|
3399
|
-
for (const [prop, value] of Object.entries(decls)) {
|
|
3400
|
-
if (prop === "string-set") {
|
|
3401
|
-
for (const entry of splitTopLevel(value, ",")) {
|
|
3402
|
-
const m = /^\s*([A-Za-z_][\w-]*)\s+(.+)$/.exec(entry);
|
|
3403
|
-
if (m && m[1] !== undefined && m[2] !== undefined)
|
|
3404
|
-
model.stringSets.push({ selector, name: m[1], value: m[2].trim() });
|
|
3405
|
-
}
|
|
3406
|
-
} else if (prop === "page") {
|
|
3407
|
-
if (value && value !== "auto")
|
|
3408
|
-
model.pageAssignments.push({ selector, page: value.trim() });
|
|
3409
|
-
} else if (prop === "break-before" || prop === "break-after" || prop === "break-inside") {
|
|
3410
|
-
model.breaks.push({ selector, prop, value });
|
|
3411
|
-
} else if (prop === "counter-reset") {
|
|
3412
|
-
const m = /\bpage\s+(-?\d+)/.exec(value);
|
|
3413
|
-
if (m)
|
|
3414
|
-
model.counterResets.push({ selector, start: Number(m[1]) });
|
|
3415
|
-
} else if (prop === "content") {
|
|
3416
|
-
for (const fn of ["target-counter", "target-text", "leader", "string"]) {
|
|
3417
|
-
if (new RegExp(`\\b${fn}\\s*\\(`).test(value)) {
|
|
3418
|
-
model.xrefs.push({ selector, content: value, fn });
|
|
3419
|
-
}
|
|
3420
|
-
}
|
|
3421
|
-
}
|
|
3422
|
-
}
|
|
3423
|
-
}
|
|
3424
|
-
function splitTopLevel(s, sep) {
|
|
3425
|
-
const out = [];
|
|
3426
|
-
let depth = 0;
|
|
3427
|
-
let start = 0;
|
|
3428
|
-
for (let i = 0;i < s.length; i++) {
|
|
3429
|
-
const c = s[i];
|
|
3430
|
-
if (c === '"' || c === "'") {
|
|
3431
|
-
i = skipString(s, i) - 1;
|
|
3432
|
-
continue;
|
|
3433
|
-
}
|
|
3434
|
-
if (c === "(")
|
|
3435
|
-
depth++;
|
|
3436
|
-
else if (c === ")")
|
|
3437
|
-
depth--;
|
|
3438
|
-
else if (c === sep && depth === 0) {
|
|
3439
|
-
out.push(s.slice(start, i));
|
|
3440
|
-
start = i + 1;
|
|
3441
|
-
}
|
|
3442
|
-
}
|
|
3443
|
-
out.push(s.slice(start));
|
|
3444
|
-
return out.map((x) => x.trim()).filter(Boolean);
|
|
3445
|
-
}
|
|
3446
2999
|
var UNITS_PER_PT = {
|
|
3447
3000
|
pt: 1,
|
|
3448
3001
|
px: 0.75,
|
|
@@ -3452,115 +3005,28 @@ var UNITS_PER_PT = {
|
|
|
3452
3005
|
mm: 72 / 25.4,
|
|
3453
3006
|
q: 72 / 101.6
|
|
3454
3007
|
};
|
|
3455
|
-
|
|
3456
|
-
const m = /^(-?[\d.]+)([a-z%]*)$/i.exec(value.trim());
|
|
3457
|
-
if (!m)
|
|
3458
|
-
return;
|
|
3459
|
-
const n = Number(m[1]);
|
|
3460
|
-
const unit = (m[2] || "px").toLowerCase();
|
|
3461
|
-
const factor = UNITS_PER_PT[unit];
|
|
3462
|
-
return factor === undefined ? undefined : n * factor;
|
|
3463
|
-
}
|
|
3464
|
-
var PAGE_SIZES = {
|
|
3465
|
-
a5: [419.53, 595.28],
|
|
3466
|
-
a4: [595.28, 841.89],
|
|
3467
|
-
a3: [841.89, 1190.55],
|
|
3468
|
-
b5: [498.9, 708.66],
|
|
3469
|
-
b4: [708.66, 1000.63],
|
|
3470
|
-
"jis-b5": [515.91, 728.5],
|
|
3471
|
-
"jis-b4": [728.5, 1031.81],
|
|
3472
|
-
letter: [612, 792],
|
|
3473
|
-
legal: [612, 1008],
|
|
3474
|
-
ledger: [1224, 792]
|
|
3475
|
-
};
|
|
3476
|
-
function parseSize(value) {
|
|
3477
|
-
const parts = value.trim().split(/\s+/);
|
|
3478
|
-
let landscape = false;
|
|
3479
|
-
const lens = [];
|
|
3480
|
-
let named;
|
|
3481
|
-
for (const p of parts) {
|
|
3482
|
-
const key = p.toLowerCase();
|
|
3483
|
-
if (key === "landscape")
|
|
3484
|
-
landscape = true;
|
|
3485
|
-
else if (key === "portrait")
|
|
3486
|
-
continue;
|
|
3487
|
-
else if (PAGE_SIZES[key])
|
|
3488
|
-
named = PAGE_SIZES[key];
|
|
3489
|
-
else {
|
|
3490
|
-
const pt = toPt(p);
|
|
3491
|
-
if (pt !== undefined)
|
|
3492
|
-
lens.push(pt);
|
|
3493
|
-
}
|
|
3494
|
-
}
|
|
3495
|
-
let w, h;
|
|
3496
|
-
if (named)
|
|
3497
|
-
[w, h] = named;
|
|
3498
|
-
else if (lens.length === 1)
|
|
3499
|
-
[w, h] = [lens[0], lens[0]];
|
|
3500
|
-
else if (lens.length >= 2)
|
|
3501
|
-
[w, h] = [lens[0], lens[1]];
|
|
3502
|
-
else
|
|
3503
|
-
return;
|
|
3504
|
-
if (landscape && h > w)
|
|
3505
|
-
[w, h] = [h, w];
|
|
3506
|
-
return { width: w, height: h };
|
|
3507
|
-
}
|
|
3508
|
-
function parseMargin(value) {
|
|
3509
|
-
const parts = value.trim().split(/\s+/).map((p) => toPt(p) ?? 0);
|
|
3510
|
-
const a = parts[0] ?? 0;
|
|
3511
|
-
const b = parts[1] ?? a;
|
|
3512
|
-
const c = parts[2] ?? a;
|
|
3513
|
-
const d = parts[3] ?? b;
|
|
3514
|
-
return { top: a, right: b, bottom: c, left: d };
|
|
3515
|
-
}
|
|
3516
|
-
function resolvePage(model, ctx = {}) {
|
|
3517
|
-
const wanted = new Set(ctx.pseudos ?? []);
|
|
3518
|
-
const applicable = model.pageRules.filter((r) => r.name ? r.name === ctx.name : true).filter((r) => r.pseudos.every((p) => wanted.has(p))).sort((a, b) => specificity(a) - specificity(b));
|
|
3519
|
-
const decls = {};
|
|
3520
|
-
const marginBoxes = {};
|
|
3521
|
-
const margin = { top: 72, right: 72, bottom: 72, left: 72 };
|
|
3522
|
-
for (const rule of applicable) {
|
|
3523
|
-
for (const [prop, value] of Object.entries(rule.decls)) {
|
|
3524
|
-
if (prop === "margin")
|
|
3525
|
-
Object.assign(margin, parseMargin(value));
|
|
3526
|
-
else if (prop === "margin-top" || prop === "margin-right" || prop === "margin-bottom" || prop === "margin-left") {
|
|
3527
|
-
const side = prop.slice(7);
|
|
3528
|
-
margin[side] = toPt(value) ?? margin[side];
|
|
3529
|
-
}
|
|
3530
|
-
}
|
|
3531
|
-
Object.assign(decls, rule.decls);
|
|
3532
|
-
for (const [box, d] of Object.entries(rule.marginBoxes)) {
|
|
3533
|
-
marginBoxes[box] = { ...marginBoxes[box] ?? {}, ...d };
|
|
3534
|
-
}
|
|
3535
|
-
}
|
|
3536
|
-
const size = parseSize(decls.size ?? "letter") ?? { width: 612, height: 792 };
|
|
3537
|
-
return {
|
|
3538
|
-
decls,
|
|
3539
|
-
marginBoxes,
|
|
3540
|
-
geometry: {
|
|
3541
|
-
width: size.width,
|
|
3542
|
-
height: size.height,
|
|
3543
|
-
margin,
|
|
3544
|
-
bleed: decls.bleed ? toPt(decls.bleed) ?? 0 : 0,
|
|
3545
|
-
marks: (decls.marks ?? "none").split(/\s+/).filter((m) => m && m !== "none")
|
|
3546
|
-
}
|
|
3547
|
-
};
|
|
3548
|
-
}
|
|
3549
|
-
function specificity(r) {
|
|
3550
|
-
return (r.name ? 2 : 0) + r.pseudos.length;
|
|
3551
|
-
}
|
|
3008
|
+
var DEFAULT_PAGE_MARGIN_PT = 72;
|
|
3552
3009
|
|
|
3553
3010
|
// src/lib/markdown/assemble.ts
|
|
3554
|
-
function
|
|
3011
|
+
function pageGeometryCss(page) {
|
|
3555
3012
|
if (!page || !isPositivePoints(page.width) || !isPositivePoints(page.height))
|
|
3556
3013
|
return null;
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3014
|
+
const size = `size: ${formatPageSize(page)};`;
|
|
3015
|
+
const m = page.margin;
|
|
3016
|
+
if (!m)
|
|
3017
|
+
return `@page { ${size} }`;
|
|
3018
|
+
const [top, bottom, inside, outside] = [m.top, m.bottom, m.inside, m.outside].map(cssLength);
|
|
3019
|
+
const recto = `margin: ${top} ${outside} ${bottom} ${inside};`;
|
|
3020
|
+
const verso = `margin: ${top} ${inside} ${bottom} ${outside};`;
|
|
3021
|
+
return [`@page { ${size} ${recto} }`, `@page :left { ${verso} }`, `@page :right { ${recto} }`].join(`
|
|
3022
|
+
`);
|
|
3023
|
+
}
|
|
3024
|
+
function defaultPageMarginCss(page) {
|
|
3025
|
+
if (!page || page.margin)
|
|
3561
3026
|
return null;
|
|
3562
|
-
|
|
3563
|
-
|
|
3027
|
+
return `@layer gp.vocab {
|
|
3028
|
+
@page { margin: ${cssLength(DEFAULT_PAGE_MARGIN_PT)}; }
|
|
3029
|
+
}`;
|
|
3564
3030
|
}
|
|
3565
3031
|
async function assembleBookHtml(opts) {
|
|
3566
3032
|
const title = opts.title ?? "Document";
|
|
@@ -3600,8 +3066,8 @@ async function assembleBookHtml(opts) {
|
|
|
3600
3066
|
imageRefs.add(ref);
|
|
3601
3067
|
opts.onImageRefs([...imageRefs]);
|
|
3602
3068
|
}
|
|
3603
|
-
const
|
|
3604
|
-
|
|
3069
|
+
const pageGeometry = pageGeometryCss(opts.printArea);
|
|
3070
|
+
const defaultMargin = defaultPageMarginCss(opts.printArea);
|
|
3605
3071
|
const inlineCss = [
|
|
3606
3072
|
"@layer gp.marker, gp.vocab;",
|
|
3607
3073
|
`/* gutterpress markers */
|
|
@@ -3613,14 +3079,16 @@ ${TWO_VERSIONS_CSS.trim()}
|
|
|
3613
3079
|
@layer gp.vocab {
|
|
3614
3080
|
${GUTTERPRESS_CSS.trim()}
|
|
3615
3081
|
}`,
|
|
3616
|
-
|
|
3617
|
-
${
|
|
3082
|
+
defaultMargin ? `/* page margins (default) */
|
|
3083
|
+
${defaultMargin}` : null,
|
|
3618
3084
|
pluginCss ? `/* extension css */
|
|
3619
3085
|
${pluginCss.trim()}` : null,
|
|
3620
3086
|
`/* column alignment */
|
|
3621
3087
|
${TABLE_ALIGN_CSS.trim()}`,
|
|
3622
3088
|
projectCss ? `/* project css */
|
|
3623
|
-
${projectCss.trim()}` : null
|
|
3089
|
+
${projectCss.trim()}` : null,
|
|
3090
|
+
pageGeometry ? `/* page geometry (manifest) */
|
|
3091
|
+
${pageGeometry}` : null
|
|
3624
3092
|
].filter(Boolean).join(`
|
|
3625
3093
|
|
|
3626
3094
|
`);
|