gutterpress 0.11.17-alpha.2 → 0.11.17-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.d.ts +4 -0
- package/dist/api/index.js +10 -2
- package/dist/{build-1p999cmg.js → build-394c1ee1.js} +4 -4
- package/dist/checks/pdf/index.d.ts +1 -0
- package/dist/checks/pdf/signature.d.ts +3 -0
- package/dist/{cli-70xgehq2.js → cli-3p1e95zc.js} +1 -1
- package/dist/{cli-6z5zthzt.js → cli-9nba5ve6.js} +562 -211
- package/dist/{cli-ppc0vz4b.js → cli-d57bsfpb.js} +1 -1
- package/dist/{cli-gymfg04q.js → cli-jyy9pqf3.js} +15 -10
- package/dist/cli.js +12 -12
- package/dist/{doctor-reqpnn3h.js → doctor-c459qv5j.js} +2 -2
- package/dist/engine/compiler/build.d.ts +3 -2
- package/dist/engine/compiler/postprocess.d.ts +6 -4
- package/dist/engine/shared/synthesis.d.ts +29 -5
- package/dist/{engine-5jzhjjvv.js → engine-3xqgm82d.js} +2 -2
- package/dist/{engine-078ggczp.js → engine-zdb41ay1.js} +1 -1
- package/dist/{ext-dsbfejt3.js → ext-ha7gg8h9.js} +4 -4
- package/dist/{gutterpress-viewer-zkv2stfy.js → gutterpress-viewer-1n793gwd.js} +5 -3
- package/dist/{index-c275p061.js → index-bscfmg5r.js} +1714 -1054
- package/dist/{index-5dcj1vts.js → index-hrx0gfkj.js} +23 -684
- package/dist/index-q1xqxrh9.js +949 -0
- package/dist/index.js +11 -3
- package/dist/lib/black-text-gray.d.ts +38 -8
- package/dist/lib/build-fingerprint.d.ts +2 -0
- package/dist/lib/engine.d.ts +2 -1
- package/dist/lib/lint-rules.d.ts +9 -0
- package/dist/lib/markdown/assemble.d.ts +3 -5
- package/dist/lib/markdown/index.d.ts +3 -8
- package/dist/lib/markdown/renderer.d.ts +9 -1
- package/dist/lib/page-size.d.ts +66 -0
- package/dist/lib/pdf-inspect.d.ts +6 -0
- package/dist/lib/printsafe.d.ts +8 -1
- package/dist/lib/project-scaffold.d.ts +3 -9
- package/dist/lib/remote-auth/github-repos.d.ts +7 -0
- package/dist/lib/remote-auth/online-backup.d.ts +51 -0
- package/dist/lib/snippets.d.ts +3 -0
- package/dist/{manifest.schema-40sfq49z.json → manifest.schema-gh0jjve9.json} +14 -2
- package/dist/{new-m5y2wepr.js → new-kky3z7kv.js} +4 -4
- package/dist/{plugin.js-m4a7m3t4.tpl → plugin.js-cswq7wvd.tpl} +4 -1
- package/dist/{plugin.test.js-6n8ct5e3.tpl → plugin.test.js-xgxrd8hf.tpl} +4 -1
- package/dist/{preflight-bwpqwwny.js → preflight-t8v6szq6.js} +4 -4
- package/dist/preview/file-watcher.d.ts +2 -4
- package/dist/{preview-62y7qhkp.js → preview-cxab4y5x.js} +4 -4
- package/dist/{publish-k2zyt3x6.js → publish-s2mtenb5.js} +4 -4
- package/dist/render.js +30 -5
- package/dist/schema/manifest.types.d.ts +17 -0
- package/dist/{validate-fgwwxtbn.js → validate-xaajdw4x.js} +4 -4
- package/package.json +1 -1
- package/dist/index-eyaj6nkc.js +0 -267
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
+
counterStyleName,
|
|
3
|
+
cssQuote,
|
|
4
|
+
extract,
|
|
5
|
+
generatedContentCss,
|
|
2
6
|
getAssetPath,
|
|
3
7
|
isIgnoredMarginBoxProperty,
|
|
8
|
+
isRectoVersoBreak,
|
|
9
|
+
leaderMarker,
|
|
4
10
|
marginBoxAlign,
|
|
5
|
-
marginBoxRectPt
|
|
6
|
-
|
|
11
|
+
marginBoxRectPt,
|
|
12
|
+
parseWhich,
|
|
13
|
+
planRectoBlanks,
|
|
14
|
+
resolvePage,
|
|
15
|
+
restartedPageValues,
|
|
16
|
+
signaturePadding,
|
|
17
|
+
splitTopLevel,
|
|
18
|
+
stringSymbols,
|
|
19
|
+
stringValueAt,
|
|
20
|
+
toFolioPage,
|
|
21
|
+
wantsRecto
|
|
22
|
+
} from "./index-q1xqxrh9.js";
|
|
7
23
|
import {
|
|
8
24
|
launchChromium
|
|
9
25
|
} from "./index-rzm1phg0.js";
|
|
@@ -13,566 +29,6 @@ import { readFile } from "node:fs/promises";
|
|
|
13
29
|
import { resolve } from "node:path";
|
|
14
30
|
import { pathToFileURL } from "node:url";
|
|
15
31
|
|
|
16
|
-
// src/engine/shared/gcpm-extract.ts
|
|
17
|
-
var NESTED_AT_RULES = /^@(media|supports|layer|scope|container|document)\b/i;
|
|
18
|
-
function scanRules(css) {
|
|
19
|
-
const out = [];
|
|
20
|
-
let i = 0;
|
|
21
|
-
let start = 0;
|
|
22
|
-
let depth = 0;
|
|
23
|
-
let bodyStart = -1;
|
|
24
|
-
while (i < css.length) {
|
|
25
|
-
const c = css[i];
|
|
26
|
-
if (c === "/" && css[i + 1] === "*") {
|
|
27
|
-
const end = css.indexOf("*/", i + 2);
|
|
28
|
-
i = end === -1 ? css.length : end + 2;
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
if (c === '"' || c === "'") {
|
|
32
|
-
i = skipString(css, i);
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
if (c === "{") {
|
|
36
|
-
if (depth === 0)
|
|
37
|
-
bodyStart = i;
|
|
38
|
-
depth++;
|
|
39
|
-
i++;
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (c === "}") {
|
|
43
|
-
depth--;
|
|
44
|
-
if (depth === 0) {
|
|
45
|
-
out.push({
|
|
46
|
-
prelude: stripComments(css.slice(start, bodyStart)).trim(),
|
|
47
|
-
body: css.slice(bodyStart + 1, i)
|
|
48
|
-
});
|
|
49
|
-
start = i + 1;
|
|
50
|
-
}
|
|
51
|
-
i++;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (c === ";" && depth === 0) {
|
|
55
|
-
const stmt = stripComments(css.slice(start, i)).trim();
|
|
56
|
-
if (stmt)
|
|
57
|
-
out.push({ statement: stmt });
|
|
58
|
-
start = i + 1;
|
|
59
|
-
i++;
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
i++;
|
|
63
|
-
}
|
|
64
|
-
return out;
|
|
65
|
-
}
|
|
66
|
-
function stripComments(s) {
|
|
67
|
-
let out = "";
|
|
68
|
-
let i = 0;
|
|
69
|
-
while (i < s.length) {
|
|
70
|
-
if (s[i] === "/" && s[i + 1] === "*") {
|
|
71
|
-
const end = s.indexOf("*/", i + 2);
|
|
72
|
-
i = end === -1 ? s.length : end + 2;
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (s[i] === '"' || s[i] === "'") {
|
|
76
|
-
const end = skipString(s, i);
|
|
77
|
-
out += s.slice(i, end);
|
|
78
|
-
i = end;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
out += s[i++];
|
|
82
|
-
}
|
|
83
|
-
return out;
|
|
84
|
-
}
|
|
85
|
-
function skipString(css, i) {
|
|
86
|
-
const quote = css[i];
|
|
87
|
-
i++;
|
|
88
|
-
while (i < css.length) {
|
|
89
|
-
if (css[i] === "\\")
|
|
90
|
-
i += 2;
|
|
91
|
-
else if (css[i] === quote)
|
|
92
|
-
return i + 1;
|
|
93
|
-
else
|
|
94
|
-
i++;
|
|
95
|
-
}
|
|
96
|
-
return i;
|
|
97
|
-
}
|
|
98
|
-
function parseDeclarations(body) {
|
|
99
|
-
const decls = {};
|
|
100
|
-
let i = 0;
|
|
101
|
-
let start = 0;
|
|
102
|
-
let depth = 0;
|
|
103
|
-
const push = (chunk) => {
|
|
104
|
-
const s = stripComments(chunk).trim();
|
|
105
|
-
if (!s)
|
|
106
|
-
return;
|
|
107
|
-
const colon = indexOfTopLevel(s, ":");
|
|
108
|
-
if (colon <= 0)
|
|
109
|
-
return;
|
|
110
|
-
const rawProp = s.slice(0, colon).trim();
|
|
111
|
-
const prop = rawProp.startsWith("--") ? rawProp : rawProp.toLowerCase();
|
|
112
|
-
const value = s.slice(colon + 1).trim().replace(/\s*!important$/i, "");
|
|
113
|
-
if (prop)
|
|
114
|
-
decls[prop] = value;
|
|
115
|
-
};
|
|
116
|
-
while (i < body.length) {
|
|
117
|
-
const c = body[i];
|
|
118
|
-
if (c === "/" && body[i + 1] === "*") {
|
|
119
|
-
const end = body.indexOf("*/", i + 2);
|
|
120
|
-
i = end === -1 ? body.length : end + 2;
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
if (c === '"' || c === "'") {
|
|
124
|
-
i = skipString(body, i);
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
if (c === "(" || c === "{" || c === "[")
|
|
128
|
-
depth++;
|
|
129
|
-
else if (c === ")" || c === "}" || c === "]")
|
|
130
|
-
depth--;
|
|
131
|
-
else if (c === ";" && depth === 0) {
|
|
132
|
-
push(body.slice(start, i));
|
|
133
|
-
start = i + 1;
|
|
134
|
-
}
|
|
135
|
-
i++;
|
|
136
|
-
}
|
|
137
|
-
push(body.slice(start));
|
|
138
|
-
return decls;
|
|
139
|
-
}
|
|
140
|
-
function indexOfTopLevel(s, ch) {
|
|
141
|
-
let depth = 0;
|
|
142
|
-
for (let i = 0;i < s.length; i++) {
|
|
143
|
-
const c = s[i];
|
|
144
|
-
if (c === '"' || c === "'") {
|
|
145
|
-
i = skipString(s, i) - 1;
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
if (c === "(")
|
|
149
|
-
depth++;
|
|
150
|
-
else if (c === ")")
|
|
151
|
-
depth--;
|
|
152
|
-
else if (c === ch && depth === 0)
|
|
153
|
-
return i;
|
|
154
|
-
}
|
|
155
|
-
return -1;
|
|
156
|
-
}
|
|
157
|
-
function extract(css) {
|
|
158
|
-
const model = {
|
|
159
|
-
pageRules: [],
|
|
160
|
-
stringSets: [],
|
|
161
|
-
pageAssignments: [],
|
|
162
|
-
breaks: [],
|
|
163
|
-
xrefs: [],
|
|
164
|
-
counterResets: [],
|
|
165
|
-
pageNames: [],
|
|
166
|
-
warnings: []
|
|
167
|
-
};
|
|
168
|
-
walk(css, model);
|
|
169
|
-
resolveGeometryVars(model, collectRootCustomProperties(css));
|
|
170
|
-
const names = new Set;
|
|
171
|
-
for (const r of model.pageRules)
|
|
172
|
-
if (r.name)
|
|
173
|
-
names.add(r.name);
|
|
174
|
-
for (const a of model.pageAssignments)
|
|
175
|
-
names.add(a.page);
|
|
176
|
-
model.pageNames = [...names];
|
|
177
|
-
return model;
|
|
178
|
-
}
|
|
179
|
-
var GEOMETRY_PROPS = [
|
|
180
|
-
"size",
|
|
181
|
-
"margin",
|
|
182
|
-
"margin-top",
|
|
183
|
-
"margin-right",
|
|
184
|
-
"margin-bottom",
|
|
185
|
-
"margin-left",
|
|
186
|
-
"bleed",
|
|
187
|
-
"marks"
|
|
188
|
-
];
|
|
189
|
-
function collectRootCustomProperties(css) {
|
|
190
|
-
const props = new Map;
|
|
191
|
-
const walkForRoot = (body) => {
|
|
192
|
-
for (const rule of scanRules(body)) {
|
|
193
|
-
if ("statement" in rule)
|
|
194
|
-
continue;
|
|
195
|
-
const { prelude, body: ruleBody } = rule;
|
|
196
|
-
if (NESTED_AT_RULES.test(prelude)) {
|
|
197
|
-
walkForRoot(ruleBody);
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (!prelude.startsWith("@")) {
|
|
201
|
-
const selectors = splitTopLevel(prelude, ",");
|
|
202
|
-
if (selectors.some((s) => s.trim() === ":root")) {
|
|
203
|
-
const decls = parseDeclarations(ruleBody);
|
|
204
|
-
for (const [k, v] of Object.entries(decls)) {
|
|
205
|
-
if (k.startsWith("--"))
|
|
206
|
-
props.set(k, v);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
walkForRoot(css);
|
|
213
|
-
return props;
|
|
214
|
-
}
|
|
215
|
-
function matchParen(s, open) {
|
|
216
|
-
let depth = 0;
|
|
217
|
-
let i = open;
|
|
218
|
-
while (i < s.length) {
|
|
219
|
-
const c = s[i];
|
|
220
|
-
if (c === '"' || c === "'") {
|
|
221
|
-
i = skipString(s, i);
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
if (c === "(")
|
|
225
|
-
depth++;
|
|
226
|
-
else if (c === ")") {
|
|
227
|
-
depth--;
|
|
228
|
-
if (depth === 0)
|
|
229
|
-
return i;
|
|
230
|
-
}
|
|
231
|
-
i++;
|
|
232
|
-
}
|
|
233
|
-
return -1;
|
|
234
|
-
}
|
|
235
|
-
function resolveVarsInValue(value, customProps, stack = new Set) {
|
|
236
|
-
let out = "";
|
|
237
|
-
let i = 0;
|
|
238
|
-
while (i < value.length) {
|
|
239
|
-
const isVarStart = /^var\(/i.test(value.slice(i, i + 4)) && (i === 0 || !/[\w-]/.test(value[i - 1]));
|
|
240
|
-
if (!isVarStart) {
|
|
241
|
-
out += value[i];
|
|
242
|
-
i++;
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
const open = i + 3;
|
|
246
|
-
const close = matchParen(value, open);
|
|
247
|
-
if (close === -1) {
|
|
248
|
-
out += value.slice(i);
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
const inner = value.slice(open + 1, close);
|
|
252
|
-
const commaIdx = indexOfTopLevel(inner, ",");
|
|
253
|
-
const name = (commaIdx === -1 ? inner : inner.slice(0, commaIdx)).trim();
|
|
254
|
-
const fallback = commaIdx === -1 ? undefined : inner.slice(commaIdx + 1).trim();
|
|
255
|
-
if (!/^--[\w-]+$/.test(name)) {
|
|
256
|
-
return { text: out, unresolved: `var(${inner}) is not a valid custom property reference` };
|
|
257
|
-
}
|
|
258
|
-
if (stack.has(name)) {
|
|
259
|
-
return { text: out, unresolved: `var(${name}) is circular` };
|
|
260
|
-
}
|
|
261
|
-
const rootValue = customProps.get(name);
|
|
262
|
-
if (rootValue !== undefined) {
|
|
263
|
-
const nested = resolveVarsInValue(rootValue, customProps, new Set(stack).add(name));
|
|
264
|
-
if (nested.unresolved)
|
|
265
|
-
return { text: out, unresolved: nested.unresolved };
|
|
266
|
-
out += nested.text;
|
|
267
|
-
} else if (fallback !== undefined) {
|
|
268
|
-
if (/\bvar\(/i.test(fallback)) {
|
|
269
|
-
return {
|
|
270
|
-
text: out,
|
|
271
|
-
unresolved: `var(${name}, ${fallback}) — a fallback containing another var() is not resolved`
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
out += fallback;
|
|
275
|
-
} else {
|
|
276
|
-
return {
|
|
277
|
-
text: out,
|
|
278
|
-
unresolved: `${name} is not defined at :root and var() has no fallback`
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
i = close + 1;
|
|
282
|
-
}
|
|
283
|
-
return { text: out };
|
|
284
|
-
}
|
|
285
|
-
function resolveGeometryVars(model, customProps) {
|
|
286
|
-
for (const rule of model.pageRules) {
|
|
287
|
-
for (const prop of GEOMETRY_PROPS) {
|
|
288
|
-
const value = rule.decls[prop];
|
|
289
|
-
if (!value || !/\bvar\(/i.test(value))
|
|
290
|
-
continue;
|
|
291
|
-
const { text, unresolved } = resolveVarsInValue(value, customProps);
|
|
292
|
-
if (unresolved) {
|
|
293
|
-
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.`);
|
|
294
|
-
}
|
|
295
|
-
const unparsable = unparsableGeometry(prop, text);
|
|
296
|
-
if (unparsable) {
|
|
297
|
-
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\`).`);
|
|
298
|
-
}
|
|
299
|
-
rule.decls[prop] = text;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
function unparsableGeometry(prop, text) {
|
|
304
|
-
const t = text.trim();
|
|
305
|
-
if (prop === "size") {
|
|
306
|
-
if (!t)
|
|
307
|
-
return "which is empty";
|
|
308
|
-
return parseSize(t) ? undefined : "which is not a page size";
|
|
309
|
-
}
|
|
310
|
-
if (prop === "margin" || prop.startsWith("margin-")) {
|
|
311
|
-
if (!t)
|
|
312
|
-
return "which is empty";
|
|
313
|
-
const parts = t.split(/\s+/);
|
|
314
|
-
if (prop !== "margin" && parts.length !== 1)
|
|
315
|
-
return "which is not a single length";
|
|
316
|
-
if (parts.length > 4)
|
|
317
|
-
return "which is not a valid margin";
|
|
318
|
-
const bad = parts.filter((p) => toPt(p) === undefined);
|
|
319
|
-
if (bad.length)
|
|
320
|
-
return `which this engine cannot read as a length (\`${bad[0]}\`)`;
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
if (prop === "bleed") {
|
|
324
|
-
if (!t)
|
|
325
|
-
return "which is empty";
|
|
326
|
-
if (/^(auto|none)$/i.test(t))
|
|
327
|
-
return;
|
|
328
|
-
return toPt(t) === undefined ? "which this engine cannot read as a length" : undefined;
|
|
329
|
-
}
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
function walk(css, model) {
|
|
333
|
-
for (const rule of scanRules(css)) {
|
|
334
|
-
if ("statement" in rule)
|
|
335
|
-
continue;
|
|
336
|
-
const { prelude, body } = rule;
|
|
337
|
-
if (NESTED_AT_RULES.test(prelude)) {
|
|
338
|
-
walk(body, model);
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
if (/^@page\b/i.test(prelude)) {
|
|
342
|
-
model.pageRules.push(parsePageRule(prelude, body));
|
|
343
|
-
continue;
|
|
344
|
-
}
|
|
345
|
-
if (prelude.startsWith("@"))
|
|
346
|
-
continue;
|
|
347
|
-
parseQualifiedRule(prelude, body, model);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
function parsePageRule(prelude, body) {
|
|
351
|
-
const sel = prelude.replace(/^@page\s*/i, "").trim();
|
|
352
|
-
const nameMatch = /^([A-Za-z_][\w-]*)/.exec(sel);
|
|
353
|
-
const pseudos = [...sel.matchAll(/:([A-Za-z-]+)(\([^)]*\))?/g)].map((m) => m[1] + (m[2] ?? ""));
|
|
354
|
-
const rule = {
|
|
355
|
-
name: nameMatch?.[1],
|
|
356
|
-
pseudos,
|
|
357
|
-
decls: {},
|
|
358
|
-
marginBoxes: {},
|
|
359
|
-
raw: `@page ${sel}`.trim()
|
|
360
|
-
};
|
|
361
|
-
let rest = "";
|
|
362
|
-
let i = 0;
|
|
363
|
-
while (i < body.length) {
|
|
364
|
-
const at = findNextAtRule(body, i);
|
|
365
|
-
if (at === -1) {
|
|
366
|
-
rest += body.slice(i);
|
|
367
|
-
break;
|
|
368
|
-
}
|
|
369
|
-
rest += body.slice(i, at);
|
|
370
|
-
const open = body.indexOf("{", at);
|
|
371
|
-
if (open === -1) {
|
|
372
|
-
rest += body.slice(at);
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
const name = body.slice(at + 1, open).trim().toLowerCase();
|
|
376
|
-
let depth = 1;
|
|
377
|
-
let j = open + 1;
|
|
378
|
-
while (j < body.length && depth > 0) {
|
|
379
|
-
const c = body[j];
|
|
380
|
-
if (c === "/" && body[j + 1] === "*") {
|
|
381
|
-
const end = body.indexOf("*/", j + 2);
|
|
382
|
-
j = end === -1 ? body.length : end + 2;
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
385
|
-
if (c === '"' || c === "'") {
|
|
386
|
-
j = skipString(body, j);
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
if (c === "{")
|
|
390
|
-
depth++;
|
|
391
|
-
else if (c === "}")
|
|
392
|
-
depth--;
|
|
393
|
-
j++;
|
|
394
|
-
}
|
|
395
|
-
rule.marginBoxes[`@${name}`] = parseDeclarations(body.slice(open + 1, j - 1));
|
|
396
|
-
i = j;
|
|
397
|
-
}
|
|
398
|
-
rule.decls = parseDeclarations(rest);
|
|
399
|
-
return rule;
|
|
400
|
-
}
|
|
401
|
-
function findNextAtRule(body, start) {
|
|
402
|
-
let i = start;
|
|
403
|
-
while (i < body.length) {
|
|
404
|
-
const c = body[i];
|
|
405
|
-
if (c === "/" && body[i + 1] === "*") {
|
|
406
|
-
const end = body.indexOf("*/", i + 2);
|
|
407
|
-
i = end === -1 ? body.length : end + 2;
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
if (c === '"' || c === "'") {
|
|
411
|
-
i = skipString(body, i);
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
if (c === "@")
|
|
415
|
-
return i;
|
|
416
|
-
i++;
|
|
417
|
-
}
|
|
418
|
-
return -1;
|
|
419
|
-
}
|
|
420
|
-
function parseQualifiedRule(selector, body, model) {
|
|
421
|
-
const decls = parseDeclarations(body);
|
|
422
|
-
for (const [prop, value] of Object.entries(decls)) {
|
|
423
|
-
if (prop === "string-set") {
|
|
424
|
-
for (const entry of splitTopLevel(value, ",")) {
|
|
425
|
-
const m = /^\s*([A-Za-z_][\w-]*)\s+(.+)$/.exec(entry);
|
|
426
|
-
if (m && m[1] !== undefined && m[2] !== undefined)
|
|
427
|
-
model.stringSets.push({ selector, name: m[1], value: m[2].trim() });
|
|
428
|
-
}
|
|
429
|
-
} else if (prop === "page") {
|
|
430
|
-
if (value && value !== "auto")
|
|
431
|
-
model.pageAssignments.push({ selector, page: value.trim() });
|
|
432
|
-
} else if (prop === "break-before" || prop === "break-after" || prop === "break-inside") {
|
|
433
|
-
model.breaks.push({ selector, prop, value });
|
|
434
|
-
} else if (prop === "counter-reset") {
|
|
435
|
-
const m = /\bpage\s+(-?\d+)/.exec(value);
|
|
436
|
-
if (m)
|
|
437
|
-
model.counterResets.push({ selector, start: Number(m[1]) });
|
|
438
|
-
} else if (prop === "content") {
|
|
439
|
-
for (const fn of ["target-counter", "target-text", "leader", "string"]) {
|
|
440
|
-
if (new RegExp(`\\b${fn}\\s*\\(`).test(value)) {
|
|
441
|
-
model.xrefs.push({ selector, content: value, fn });
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
function splitTopLevel(s, sep) {
|
|
448
|
-
const out = [];
|
|
449
|
-
let depth = 0;
|
|
450
|
-
let start = 0;
|
|
451
|
-
for (let i = 0;i < s.length; i++) {
|
|
452
|
-
const c = s[i];
|
|
453
|
-
if (c === '"' || c === "'") {
|
|
454
|
-
i = skipString(s, i) - 1;
|
|
455
|
-
continue;
|
|
456
|
-
}
|
|
457
|
-
if (c === "(")
|
|
458
|
-
depth++;
|
|
459
|
-
else if (c === ")")
|
|
460
|
-
depth--;
|
|
461
|
-
else if (c === sep && depth === 0) {
|
|
462
|
-
out.push(s.slice(start, i));
|
|
463
|
-
start = i + 1;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
out.push(s.slice(start));
|
|
467
|
-
return out.map((x) => x.trim()).filter(Boolean);
|
|
468
|
-
}
|
|
469
|
-
var UNITS_PER_PT = {
|
|
470
|
-
pt: 1,
|
|
471
|
-
px: 0.75,
|
|
472
|
-
in: 72,
|
|
473
|
-
pc: 12,
|
|
474
|
-
cm: 72 / 2.54,
|
|
475
|
-
mm: 72 / 25.4,
|
|
476
|
-
q: 72 / 101.6
|
|
477
|
-
};
|
|
478
|
-
function toPt(value) {
|
|
479
|
-
const m = /^(-?[\d.]+)([a-z%]*)$/i.exec(value.trim());
|
|
480
|
-
if (!m)
|
|
481
|
-
return;
|
|
482
|
-
const n = Number(m[1]);
|
|
483
|
-
const unit = (m[2] || "px").toLowerCase();
|
|
484
|
-
const factor = UNITS_PER_PT[unit];
|
|
485
|
-
return factor === undefined ? undefined : n * factor;
|
|
486
|
-
}
|
|
487
|
-
var PAGE_SIZES = {
|
|
488
|
-
a5: [419.53, 595.28],
|
|
489
|
-
a4: [595.28, 841.89],
|
|
490
|
-
a3: [841.89, 1190.55],
|
|
491
|
-
b5: [498.9, 708.66],
|
|
492
|
-
b4: [708.66, 1000.63],
|
|
493
|
-
"jis-b5": [515.91, 728.5],
|
|
494
|
-
"jis-b4": [728.5, 1031.81],
|
|
495
|
-
letter: [612, 792],
|
|
496
|
-
legal: [612, 1008],
|
|
497
|
-
ledger: [1224, 792]
|
|
498
|
-
};
|
|
499
|
-
function parseSize(value) {
|
|
500
|
-
const parts = value.trim().split(/\s+/);
|
|
501
|
-
let landscape = false;
|
|
502
|
-
const lens = [];
|
|
503
|
-
let named;
|
|
504
|
-
for (const p of parts) {
|
|
505
|
-
const key = p.toLowerCase();
|
|
506
|
-
if (key === "landscape")
|
|
507
|
-
landscape = true;
|
|
508
|
-
else if (key === "portrait")
|
|
509
|
-
continue;
|
|
510
|
-
else if (PAGE_SIZES[key])
|
|
511
|
-
named = PAGE_SIZES[key];
|
|
512
|
-
else {
|
|
513
|
-
const pt = toPt(p);
|
|
514
|
-
if (pt !== undefined)
|
|
515
|
-
lens.push(pt);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
let w, h;
|
|
519
|
-
if (named)
|
|
520
|
-
[w, h] = named;
|
|
521
|
-
else if (lens.length === 1)
|
|
522
|
-
[w, h] = [lens[0], lens[0]];
|
|
523
|
-
else if (lens.length >= 2)
|
|
524
|
-
[w, h] = [lens[0], lens[1]];
|
|
525
|
-
else
|
|
526
|
-
return;
|
|
527
|
-
if (landscape && h > w)
|
|
528
|
-
[w, h] = [h, w];
|
|
529
|
-
return { width: w, height: h };
|
|
530
|
-
}
|
|
531
|
-
function parseMargin(value) {
|
|
532
|
-
const parts = value.trim().split(/\s+/).map((p) => toPt(p) ?? 0);
|
|
533
|
-
const a = parts[0] ?? 0;
|
|
534
|
-
const b = parts[1] ?? a;
|
|
535
|
-
const c = parts[2] ?? a;
|
|
536
|
-
const d = parts[3] ?? b;
|
|
537
|
-
return { top: a, right: b, bottom: c, left: d };
|
|
538
|
-
}
|
|
539
|
-
function resolvePage(model, ctx = {}) {
|
|
540
|
-
const wanted = new Set(ctx.pseudos ?? []);
|
|
541
|
-
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));
|
|
542
|
-
const decls = {};
|
|
543
|
-
const marginBoxes = {};
|
|
544
|
-
const margin = { top: 72, right: 72, bottom: 72, left: 72 };
|
|
545
|
-
for (const rule of applicable) {
|
|
546
|
-
for (const [prop, value] of Object.entries(rule.decls)) {
|
|
547
|
-
if (prop === "margin")
|
|
548
|
-
Object.assign(margin, parseMargin(value));
|
|
549
|
-
else if (prop === "margin-top" || prop === "margin-right" || prop === "margin-bottom" || prop === "margin-left") {
|
|
550
|
-
const side = prop.slice(7);
|
|
551
|
-
margin[side] = toPt(value) ?? margin[side];
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
Object.assign(decls, rule.decls);
|
|
555
|
-
for (const [box, d] of Object.entries(rule.marginBoxes)) {
|
|
556
|
-
marginBoxes[box] = { ...marginBoxes[box] ?? {}, ...d };
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
const size = parseSize(decls.size ?? "letter") ?? { width: 612, height: 792 };
|
|
560
|
-
return {
|
|
561
|
-
decls,
|
|
562
|
-
marginBoxes,
|
|
563
|
-
geometry: {
|
|
564
|
-
width: size.width,
|
|
565
|
-
height: size.height,
|
|
566
|
-
margin,
|
|
567
|
-
bleed: decls.bleed ? toPt(decls.bleed) ?? 0 : 0,
|
|
568
|
-
marks: (decls.marks ?? "none").split(/\s+/).filter((m) => m && m !== "none")
|
|
569
|
-
}
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
function specificity(r) {
|
|
573
|
-
return (r.name ? 2 : 0) + r.pseudos.length;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
32
|
// src/engine/shared/flush.ts
|
|
577
33
|
var FLUSH_EDGES = ["top", "right", "bottom", "left"];
|
|
578
34
|
function flushKey(edges) {
|
|
@@ -612,123 +68,6 @@ function marginBoxesOnEdges(edges) {
|
|
|
612
68
|
return Object.entries(owners).filter(([, own]) => own.some((e) => edges.includes(e))).map(([name]) => name);
|
|
613
69
|
}
|
|
614
70
|
|
|
615
|
-
// src/engine/shared/synthesis.ts
|
|
616
|
-
var RECTO_VERSO_VALUES = /^(right|recto|left|verso)$/;
|
|
617
|
-
function isRectoVersoBreak(decl) {
|
|
618
|
-
return decl.prop === "break-before" && RECTO_VERSO_VALUES.test(decl.value.trim());
|
|
619
|
-
}
|
|
620
|
-
function wantsRecto(value) {
|
|
621
|
-
return /^(right|recto)$/.test(value.trim());
|
|
622
|
-
}
|
|
623
|
-
function planRectoBlanks(sites) {
|
|
624
|
-
let shift = 0;
|
|
625
|
-
return sites.map((site) => {
|
|
626
|
-
if (site.page <= 0)
|
|
627
|
-
return false;
|
|
628
|
-
const effective = site.page + shift;
|
|
629
|
-
const onRecto = effective % 2 === 1;
|
|
630
|
-
const wrong = site.wantsRecto ? !onRecto : onRecto;
|
|
631
|
-
if (wrong)
|
|
632
|
-
shift++;
|
|
633
|
-
return wrong;
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
function signaturePadding(pageCount, signature = 1, reserveLastPage = false) {
|
|
637
|
-
const size = signature > 1 ? signature : 1;
|
|
638
|
-
const padded = (size - pageCount % size) % size;
|
|
639
|
-
return padded === 0 && reserveLastPage ? size : padded;
|
|
640
|
-
}
|
|
641
|
-
var WHICH_VALUES = new Set(["first", "start", "last", "first-except"]);
|
|
642
|
-
function parseWhich(raw) {
|
|
643
|
-
const w = (raw ?? "").trim();
|
|
644
|
-
return WHICH_VALUES.has(w) ? w : "first";
|
|
645
|
-
}
|
|
646
|
-
function stringValueAt(entries, page, which = "first") {
|
|
647
|
-
let entry = "";
|
|
648
|
-
const onPage = [];
|
|
649
|
-
for (const e of entries) {
|
|
650
|
-
if (e.page < page)
|
|
651
|
-
entry = e.value;
|
|
652
|
-
else if (e.page === page)
|
|
653
|
-
onPage.push(e.value);
|
|
654
|
-
else
|
|
655
|
-
break;
|
|
656
|
-
}
|
|
657
|
-
switch (which) {
|
|
658
|
-
case "start":
|
|
659
|
-
return entry;
|
|
660
|
-
case "last":
|
|
661
|
-
return onPage.length ? onPage[onPage.length - 1] : entry;
|
|
662
|
-
case "first-except":
|
|
663
|
-
return onPage.length ? "" : entry;
|
|
664
|
-
case "first":
|
|
665
|
-
return onPage.length ? onPage[0] : entry;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
function stringSymbols(entries, pageCount, which = "first") {
|
|
669
|
-
const symbols = [];
|
|
670
|
-
for (let p = 1;p <= pageCount; p++)
|
|
671
|
-
symbols.push(stringValueAt(entries, p, which));
|
|
672
|
-
return symbols;
|
|
673
|
-
}
|
|
674
|
-
function cssQuote(s) {
|
|
675
|
-
return `"${s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
676
|
-
}
|
|
677
|
-
function counterStyleName(name, which) {
|
|
678
|
-
return which === "first" ? `gp-${name}` : `gp-${name}--${which}`;
|
|
679
|
-
}
|
|
680
|
-
function pageCounterValues(resets, pageCount) {
|
|
681
|
-
const byPage = new Map;
|
|
682
|
-
for (const r of resets)
|
|
683
|
-
if (r.page >= 1)
|
|
684
|
-
byPage.set(r.page, r.start);
|
|
685
|
-
const values = [];
|
|
686
|
-
let value = 0;
|
|
687
|
-
for (let p = 1;p <= pageCount; p++) {
|
|
688
|
-
if (byPage.has(p))
|
|
689
|
-
value = byPage.get(p) - 1;
|
|
690
|
-
value++;
|
|
691
|
-
values.push(value);
|
|
692
|
-
}
|
|
693
|
-
return values;
|
|
694
|
-
}
|
|
695
|
-
function restartedPageValues(resetSites, pageMap, pageCount) {
|
|
696
|
-
const resets = resetSites.map((s) => ({ page: pageMap[s.id] ?? 0, start: s.start })).filter((r) => r.page > 0);
|
|
697
|
-
return resets.length ? pageCounterValues(resets, pageCount) : null;
|
|
698
|
-
}
|
|
699
|
-
function toFolioPage(physicalPage, pageValues) {
|
|
700
|
-
if (!pageValues)
|
|
701
|
-
return physicalPage;
|
|
702
|
-
return pageValues[physicalPage - 1] ?? physicalPage;
|
|
703
|
-
}
|
|
704
|
-
var LEADER_START = "";
|
|
705
|
-
var LEADER_END = "";
|
|
706
|
-
function leaderMarker(glue) {
|
|
707
|
-
return `${LEADER_START}${glue}${LEADER_END}`;
|
|
708
|
-
}
|
|
709
|
-
function generatedContentCss(selectors) {
|
|
710
|
-
const rules = new Set;
|
|
711
|
-
for (const raw of selectors) {
|
|
712
|
-
for (const one of raw.split(",")) {
|
|
713
|
-
const selector = one.trim();
|
|
714
|
-
if (!selector)
|
|
715
|
-
continue;
|
|
716
|
-
const m = /^(.*?)(::?)(after|before)\s*$/i.exec(selector);
|
|
717
|
-
if (!m)
|
|
718
|
-
continue;
|
|
719
|
-
const [, base, colons, pseudo] = m;
|
|
720
|
-
if (base === undefined || colons === undefined || pseudo === undefined)
|
|
721
|
-
continue;
|
|
722
|
-
const where = pseudo.toLowerCase();
|
|
723
|
-
rules.add(`${base.trim()}[data-gp-${where}]${colons}${where} { content: attr(data-gp-${where}); }`);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
rules.add(`[data-gp-after]::after { content: attr(data-gp-after); }`);
|
|
727
|
-
rules.add(`[data-gp-before]::before { content: attr(data-gp-before); }`);
|
|
728
|
-
return [...rules].join(`
|
|
729
|
-
`);
|
|
730
|
-
}
|
|
731
|
-
|
|
732
71
|
// src/engine/shared/content-value.ts
|
|
733
72
|
var FUNC = /^([a-z-]+)\(/i;
|
|
734
73
|
function parseContent(value) {
|
|
@@ -751,7 +90,7 @@ function parseContent(value) {
|
|
|
751
90
|
const fn = FUNC.exec(rest);
|
|
752
91
|
if (fn && fn[1] !== undefined) {
|
|
753
92
|
const open = i + fn[0].length - 1;
|
|
754
|
-
const close =
|
|
93
|
+
const close = matchParen(s, open);
|
|
755
94
|
const args = splitTopLevel(s.slice(open + 1, close), ",");
|
|
756
95
|
parts.push(toPart(fn[1].toLowerCase(), args));
|
|
757
96
|
i = close + 1;
|
|
@@ -802,7 +141,7 @@ function closeString(s, i) {
|
|
|
802
141
|
}
|
|
803
142
|
return i;
|
|
804
143
|
}
|
|
805
|
-
function
|
|
144
|
+
function matchParen(s, open) {
|
|
806
145
|
let depth = 0;
|
|
807
146
|
for (let i = open;i < s.length; i++) {
|
|
808
147
|
const c = s[i];
|
|
@@ -1212,7 +551,7 @@ async function postprocess(input, opts) {
|
|
|
1212
551
|
g.media.width - inset,
|
|
1213
552
|
g.media.height - inset
|
|
1214
553
|
];
|
|
1215
|
-
const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.
|
|
554
|
+
const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.lastPage);
|
|
1216
555
|
for (let i = 0;i < padded; i++)
|
|
1217
556
|
doc.addPage([g.media.width, g.media.height]);
|
|
1218
557
|
const wantMarks = opts.marks || g.marks.includes("crop") || g.marks.includes("cross");
|
|
@@ -2001,12 +1340,12 @@ ${mapCss}`;
|
|
|
2001
1340
|
const post = await postprocess(bytes, {
|
|
2002
1341
|
geometry: tier2.geometry,
|
|
2003
1342
|
signature: opts.signature,
|
|
2004
|
-
|
|
1343
|
+
lastPage: opts.lastPage,
|
|
2005
1344
|
marks: opts.marks,
|
|
2006
1345
|
title: opts.title,
|
|
2007
1346
|
author: opts.author
|
|
2008
1347
|
});
|
|
2009
|
-
log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.
|
|
1348
|
+
log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.lastPage ? `; last page: ${opts.lastPage}` : ""})` : ""));
|
|
2010
1349
|
return {
|
|
2011
1350
|
bytes: post.bytes,
|
|
2012
1351
|
tier,
|