rapier-markdown-kit 1.1.102 → 1.2.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/LICENSE +5 -2
- package/README.md +245 -54
- package/dist/agent/vendor/hyphen-en-us/LICENSE +14 -0
- package/dist/agent/vendor/hyphen-en-us/SOURCE.json +33 -0
- package/dist/agent/vendor/hyphen-en-us/hyph-en-us.hyp.txt +14 -0
- package/dist/agent/vendor/hyphen-en-us/hyph-en-us.pat.txt +4938 -0
- package/dist/agent/vendor/hyphen-en-us/patterns.js +25 -0
- package/dist/agent/vendor/pretext/LICENSE +208 -0
- package/dist/agent/vendor/pretext/NOTICE +26 -13
- package/dist/agent/vendor/pretext/SOURCE.json +213 -45
- package/dist/agent/vendor/pretext/analysis.js +675 -1224
- package/dist/agent/vendor/pretext/entry-geometry.js +183 -0
- package/dist/agent/vendor/pretext/gecko-line-breaks.js +688 -0
- package/dist/agent/vendor/pretext/generated/engine-break-data.js +57 -0
- package/dist/agent/vendor/pretext/generated/webkit-generic-families.js +80 -0
- package/dist/agent/vendor/pretext/graphemes.js +98 -0
- package/dist/agent/vendor/pretext/han-kerning.js +253 -0
- package/dist/agent/vendor/pretext/layout.js +352 -290
- package/dist/agent/vendor/pretext/line-break.js +1154 -588
- package/dist/agent/vendor/pretext/line-breaks.js +892 -0
- package/dist/agent/vendor/pretext/line-text.js +81 -39
- package/dist/agent/vendor/pretext/measurement.js +1105 -176
- package/dist/agent/vendor/pretext/prepare.js +807 -0
- package/dist/agent/vendor/pretext/rich-inline.js +1242 -273
- package/dist/agent/will.mjs +2 -0
- package/dist/images/gif.mjs +47 -0
- package/dist/images/playback.mjs +101 -0
- package/dist/kit/assets.mjs +5 -1
- package/dist/kit/conformance/03-wrap-around-silhouette.md +1 -1
- package/dist/kit/conformance/04-wrap-box.md +1 -1
- package/dist/kit/conformance/05-behind.md +1 -1
- package/dist/kit/conformance/06-front.md +1 -1
- package/dist/kit/conformance/07-rotate-raster.md +1 -1
- package/dist/kit/conformance/08-drawing-rotation.md +1 -1
- package/dist/kit/conformance/09-drawing-ring-interior.expected.json +18 -18
- package/dist/kit/conformance/09-drawing-ring-interior.md +1 -1
- package/dist/kit/conformance/10-both-sides.md +1 -1
- package/dist/kit/conformance/11-neighbour-skips-image.md +1 -1
- package/dist/kit/conformance/{12-heading-barrier.expected.json → 12-rule-barrier.expected.json} +1 -1
- package/dist/kit/conformance/{12-heading-barrier.md → 12-rule-barrier.md} +2 -2
- package/dist/kit/conformance/README.md +19 -28
- package/dist/kit/conformance/run.mjs +13 -11
- package/dist/kit/export-fonts.mjs +26 -11
- package/dist/kit/index.mjs +1 -0
- package/dist/kit/ledger/carried.mjs +17 -10
- package/dist/kit/ledger/data.mjs +73 -13
- package/dist/kit/ledger/format.mjs +176 -54
- package/dist/kit/ledger/hash.mjs +91 -18
- package/dist/kit/ledger/history.mjs +156 -116
- package/dist/kit/ledger/inverse-source.mjs +158 -19
- package/dist/kit/ledger/journal-records.mjs +292 -67
- package/dist/kit/ledger/merge.mjs +4 -3
- package/dist/kit/model.mjs +1 -1
- package/dist/kit/pdf-glyphs.mjs +4 -4
- package/dist/kit/pdf-vectors.mjs +4 -1
- package/dist/kit/rapier-ledger.mjs +2 -2
- package/dist/kit/render-ink.mjs +1 -1
- package/dist/kit/render-markdown.mjs +400 -148
- package/dist/kit/render-print.mjs +131 -55
- package/dist/kit/render-sanitize.mjs +30 -7
- package/dist/kit/render-work.mjs +99 -20
- package/dist/kit/render.mjs +133 -140
- package/dist/kit/typography.mjs +2 -0
- package/dist/layout/hyphenation.mjs +127 -0
- package/dist/layout/line-plan.mjs +88 -96
- package/dist/layout/model.mjs +71 -88
- package/dist/layout/paragraph-fit.mjs +191 -0
- package/dist/layout/preparation.mjs +373 -0
- package/dist/layout/prepared-paragraph.mjs +223 -0
- package/dist/layout/typography.mjs +345 -111
- package/dist/packages/rapier-diff/index.mjs +359 -224
- package/dist/spec/document-fonts.mjs +14 -5
- package/dist/spec/document-settings.mjs +11 -164
- package/dist/spec/html-blocks.mjs +618 -79
- package/dist/spec/md-assets.mjs +178 -36
- package/dist/spec/md-layout.mjs +13 -2
- package/dist/spec/md-marks.mjs +220 -127
- package/dist/spec/md-source.mjs +157 -0
- package/package.json +2 -1
- package/style.css +15 -50
- package/dist/agent/vendor/pretext/bidi.js +0 -151
- package/dist/agent/vendor/pretext/generated/bidi-data.js +0 -3831
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
import {markdownParser, installMarkdownImages, normalizeLabel} from './md-assets.mjs';
|
|
4
4
|
import {splitOpeningFrontmatter} from './frontmatter.mjs';
|
|
5
5
|
import {readDocumentSettings, documentFont} from './document-settings.mjs';
|
|
6
|
-
import {normalizeFontFamily, fontFamilyCss, FONT_STACKS} from './md-marks.mjs';
|
|
6
|
+
import {normalizeFontFamily, fontFamilyCss, FONT_STACKS, typography} from './md-marks.mjs';
|
|
7
7
|
|
|
8
8
|
// Unquoted CSS generic families require no portable asset. Quoted names remain custom.
|
|
9
9
|
export const CSS_GENERIC_FONT_FAMILIES = Object.freeze(['serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui',
|
|
10
10
|
'ui-serif', 'ui-sans-serif', 'ui-monospace', 'ui-rounded', 'emoji', 'math', 'fangsong', 'initial', 'revert', 'revert-layer']);
|
|
11
11
|
|
|
12
|
-
//
|
|
12
|
+
// No decoding or external resource loading happens here.
|
|
13
13
|
export function fontDataUrl(url) {
|
|
14
14
|
if (typeof url !== 'string') return null;
|
|
15
15
|
const match = /^data:font\/(woff2|woff|ttf|otf);base64,([A-Za-z0-9+/]+={0,2})$/i.exec(url);
|
|
@@ -188,6 +188,13 @@ function htmlFontFamilies(html, md) {
|
|
|
188
188
|
for (const tag of html.matchAll(/<[A-Za-z][A-Za-z0-9:-]*(?:"[^"]*"|'[^']*'|[^'">])*>/g)) {
|
|
189
189
|
for (const attr of tag[0].matchAll(/\s(data-md-font|style)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi)) {
|
|
190
190
|
const value = decode(attr[2] ?? attr[3] ?? attr[4]), names = [];
|
|
191
|
+
if (/^<span(?=[\s>])/i.test(tag[0])) {
|
|
192
|
+
// Raw or unpaired spans use the same admission as paired typography. A CSS
|
|
193
|
+
// resource expression or authored data-* hook cannot request a font asset.
|
|
194
|
+
const family = attr[1].toLowerCase() === 'style' ? typography.parseStyle(value).family : null;
|
|
195
|
+
if (family?.custom) families.add(family.name);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
191
198
|
if (attr[1].toLowerCase() === 'data-md-font') names.push(value);
|
|
192
199
|
else for (const declared of value.matchAll(/(?:^|;)\s*font-family\s*:\s*((?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|[^;])*)/gi)) {
|
|
193
200
|
const match = /^\s*(?:"((?:\\.|[^"])*)"|'((?:\\.|[^'])*)'|([^,!]+))/.exec(declared[1]);
|
|
@@ -230,9 +237,11 @@ export function documentFontUsage(markdown, parser, defaultFont) {
|
|
|
230
237
|
for (const child of token.children || []) {
|
|
231
238
|
if (child.type === 'html_inline') html += child.content;
|
|
232
239
|
if (['text', 'text_special', 'emoji', 'image', 'code_inline'].includes(child.type)) text += child.content;
|
|
233
|
-
const
|
|
234
|
-
if (
|
|
235
|
-
|
|
240
|
+
const typed = child.meta?.typography;
|
|
241
|
+
if (typed && child.nesting === 1) {
|
|
242
|
+
stack.push(typed.style.family ? typed.style.family.custom ? typed.style.family.name : null : stack.at(-1)); continue;
|
|
243
|
+
}
|
|
244
|
+
if (typed && child.nesting === -1) { if (stack.length > 1) stack.pop(); continue; }
|
|
236
245
|
if (child.type === 'code_inline') add(mono, child.content);
|
|
237
246
|
else if (['text', 'text_special', 'emoji', 'image'].includes(child.type)) add(stack.at(-1), child.content);
|
|
238
247
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
// One reader of document-wide settings and the inherited font snapshot.
|
|
3
3
|
// Framing stays in spec/frontmatter.mjs. Reading never rewrites source.
|
|
4
|
-
// The live view reads fontsize, the three font scopes
|
|
4
|
+
// The live view reads fontsize, the three font scopes and linestretch. It ignores papersize,
|
|
5
5
|
// geometry and pagestyle: a scroll has no page. Word and the PDF read all of them.
|
|
6
6
|
import {frontMatterFrame, frontMatterLine} from './frontmatter.mjs';
|
|
7
7
|
import {normalizeFontFamily, fontFamilyCss, FONT_STACKS} from './md-marks.mjs';
|
|
8
8
|
|
|
9
9
|
// Twelve points are one reference unit (16 px at the default reading scale).
|
|
10
10
|
const NUMBER = /^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
11
|
-
const SPACE = Object.freeze({paragraph: .5, heading: Object.freeze([1.5, .5]), block: 1});
|
|
12
11
|
export const DOCUMENT_LEADING = 1.75 / 1.1;
|
|
13
12
|
|
|
14
13
|
function measure(value, positive = false) {
|
|
@@ -41,7 +40,7 @@ const PAPERS = Object.freeze({
|
|
|
41
40
|
});
|
|
42
41
|
const EMPTY = Object.freeze({
|
|
43
42
|
title: null, subtitle: null, lang: null, fontsize: null, mainfont: null, sansfont: null, monofont: null, defaultfont: null, linestretch: null,
|
|
44
|
-
papersize: null, geometry: null, pagestyle: null,
|
|
43
|
+
papersize: null, geometry: null, pagestyle: null,
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
function unquote(value) {
|
|
@@ -53,7 +52,7 @@ function marginOf(value) {
|
|
|
53
52
|
const match = /^margin\s*=\s*(\d+(?:\.\d+)?)(cm|mm|in|pt)$/i.exec(unquote(value));
|
|
54
53
|
if (!match) return null;
|
|
55
54
|
const number = Number(match[1]);
|
|
56
|
-
if (!Number.isFinite(number) || number < 0
|
|
55
|
+
if (!Number.isFinite(number) || number < 0) return null;
|
|
57
56
|
const unit = match[2].toLowerCase();
|
|
58
57
|
const twips = Math.round(unit === 'in' ? number * 1440 : unit === 'pt' ? number * 20 : unit === 'cm' ? number * 1440 / 2.54 : number * 1440 / 25.4);
|
|
59
58
|
if (!Number.isSafeInteger(twips) || twips < 0 || twips > 1440 * 6) return null;
|
|
@@ -214,97 +213,6 @@ function fieldsOf(source) {
|
|
|
214
213
|
return {frame, fields: parsed.fields, invalid: parsed.invalid || !structureIsClosed(source, lines)};
|
|
215
214
|
}
|
|
216
215
|
|
|
217
|
-
function flowItems(source, start, stop) {
|
|
218
|
-
const items = [];
|
|
219
|
-
for (let at = start; at < stop;) {
|
|
220
|
-
if (!source.slice(at, stop).trim()) break;
|
|
221
|
-
let end = at;
|
|
222
|
-
for (; end < stop; end++) {
|
|
223
|
-
const char = source[end];
|
|
224
|
-
if ((char === '"' || char === "'") && (end === at || /[\s:[{,]/.test(source[end - 1]))) {
|
|
225
|
-
const next = quotedEnd(source, end, stop);
|
|
226
|
-
if (next === null) return null;
|
|
227
|
-
end = next - 1;
|
|
228
|
-
} else if (char === '[' || char === '{') {
|
|
229
|
-
const next = flowEnd(source, end, stop);
|
|
230
|
-
if (next === null) return null;
|
|
231
|
-
end = next - 1;
|
|
232
|
-
} else if (char === ',') break;
|
|
233
|
-
}
|
|
234
|
-
if (!source.slice(at, end).trim()) return null;
|
|
235
|
-
items.push({start: at, end, comma: end < stop ? end : null});
|
|
236
|
-
at = end + 1;
|
|
237
|
-
}
|
|
238
|
-
return items;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function spaceFields(source, field) {
|
|
242
|
-
if (!field || field.opaque || field.invalid || field.multiline) return null;
|
|
243
|
-
const value = source.slice(field.start, field.end);
|
|
244
|
-
if (value.startsWith('{') && value.endsWith('}') && !field.children.length) {
|
|
245
|
-
const chunks = flowItems(source, field.start + 1, field.end - 1), fields = [];
|
|
246
|
-
if (!chunks) return null;
|
|
247
|
-
for (const chunk of chunks) {
|
|
248
|
-
const start = chunk.start + source.slice(chunk.start, chunk.end).match(/^\s*/)[0].length;
|
|
249
|
-
const line = {start, end: chunk.end, next: chunk.end, text: source.slice(start, chunk.end), eol: ''};
|
|
250
|
-
const item = fieldLine(line);
|
|
251
|
-
if (!item) return null;
|
|
252
|
-
valueSpan(source, item, chunk.end);
|
|
253
|
-
if (item.invalid || item.key === null) return null;
|
|
254
|
-
fields.push({...item, entryStart: chunk.start, entryEnd: chunk.end, comma: chunk.comma});
|
|
255
|
-
}
|
|
256
|
-
return {fields, flow: true};
|
|
257
|
-
}
|
|
258
|
-
if (value) return null;
|
|
259
|
-
if (!field.children.length) return {fields: [], flow: false};
|
|
260
|
-
const indent = /^ */.exec(field.children[0].text)[0].length;
|
|
261
|
-
const parsed = mapFields(source, field.children, indent);
|
|
262
|
-
return parsed.invalid ? null : {...parsed, flow: false, indent};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function headingParts(source, field) {
|
|
266
|
-
if (field.opaque || field.invalid || field.multiline) return null;
|
|
267
|
-
let spans;
|
|
268
|
-
if (field.children.length) {
|
|
269
|
-
if (field.start !== field.end) return null;
|
|
270
|
-
let indent = null;
|
|
271
|
-
spans = field.children.map(line => {
|
|
272
|
-
const match = /^( +)-[ \t]+/.exec(line.text);
|
|
273
|
-
if (!match || indent !== null && match[1].length !== indent) return null;
|
|
274
|
-
indent = match[1].length;
|
|
275
|
-
const span = valueSpan(source, {start: line.start + match[0].length, line, children: []}, line.end);
|
|
276
|
-
return span.invalid || span.opaque ? null : span;
|
|
277
|
-
});
|
|
278
|
-
} else {
|
|
279
|
-
if (source[field.start] !== '[' || source[field.end - 1] !== ']') return null;
|
|
280
|
-
spans = flowItems(source, field.start + 1, field.end - 1);
|
|
281
|
-
}
|
|
282
|
-
if (!spans || spans.length !== 2 || spans.some(span => !span)) return null;
|
|
283
|
-
const values = spans.map(span => measure(source.slice(span.start, span.end)));
|
|
284
|
-
return values.includes(null) ? null : {values, spans};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function spaceOf(source, field) {
|
|
288
|
-
const parsed = spaceFields(source, field);
|
|
289
|
-
if (!parsed) return null;
|
|
290
|
-
const value = {...SPACE}, seen = new Set();
|
|
291
|
-
for (const item of parsed.fields) {
|
|
292
|
-
if (seen.has(item.key)) return null;
|
|
293
|
-
seen.add(item.key);
|
|
294
|
-
if (!Object.hasOwn(SPACE, item.key)) continue;
|
|
295
|
-
if (item.key === 'heading') {
|
|
296
|
-
const pair = headingParts(source, item);
|
|
297
|
-
if (!pair) return null;
|
|
298
|
-
value.heading = Object.freeze(pair.values);
|
|
299
|
-
} else {
|
|
300
|
-
if (item.children.length || item.opaque || item.invalid || item.multiline) return null;
|
|
301
|
-
value[item.key] = measure(source.slice(item.start, item.end));
|
|
302
|
-
if (value[item.key] === null) return null;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return Object.keys(SPACE).some(key => seen.has(key)) ? Object.freeze(value) : null;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
216
|
export function documentFont(value) {
|
|
309
217
|
const family = normalizeFontFamily(value);
|
|
310
218
|
if (!family) return null;
|
|
@@ -348,94 +256,37 @@ export function readDocumentSettings(markdown) {
|
|
|
348
256
|
const page = String(take('pagestyle') || '').toLowerCase();
|
|
349
257
|
return Object.freeze({
|
|
350
258
|
title: take('title') || null, subtitle: take('subtitle') || null, lang: languageTag(take('lang')),
|
|
351
|
-
fontsize, mainfont, sansfont, monofont, defaultfont, linestretch,
|
|
259
|
+
fontsize, mainfont, sansfont, monofont, defaultfont, linestretch, papersize, geometry,
|
|
352
260
|
pagestyle: page === 'plain' || page === 'empty' ? page : null,
|
|
353
261
|
});
|
|
354
262
|
}
|
|
355
263
|
|
|
356
|
-
function spaceValue(value) {
|
|
357
|
-
if (!value || typeof value !== 'object' || Array.isArray(value) || Object.keys(value).some(key => !Object.hasOwn(SPACE, key))) return null;
|
|
358
|
-
const result = {...SPACE, ...value};
|
|
359
|
-
if (!Array.isArray(result.heading) || result.heading.length !== 2) return null;
|
|
360
|
-
return [result.paragraph, ...result.heading, result.block].every(number => typeof number === 'number' && Number.isFinite(number) && number >= 0) ? result : null;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
264
|
// Change only supplied settings. Unrelated YAML, comments, line endings, BOM and body are never reprinted.
|
|
364
265
|
export function updateDocumentSettings(markdown, patch) {
|
|
365
266
|
const source = String(markdown ?? ''), parsed = fieldsOf(source), {frame, fields} = parsed, before = readDocumentSettings(source);
|
|
366
267
|
const changes = [], append = [];
|
|
367
268
|
const eol = frame.closing ? frame.opening.eol : (source.match(/\r\n|\r|\n/) || ['\n'])[0];
|
|
368
|
-
const encodeSpace = value => '{ paragraph: ' + value.paragraph + ', heading: [' + value.heading.join(', ') + '], block: ' + value.block + ' }';
|
|
369
269
|
const same = (left, right) => Math.abs(left - right) <= Number.EPSILON * Math.max(Math.abs(left), Math.abs(right)) * 4;
|
|
370
270
|
const refuse = key => { throw new RangeError('Edit this setting in source: ' + key); };
|
|
371
|
-
const removeLine = (line, end
|
|
271
|
+
const removeLine = (line, end) => {
|
|
372
272
|
const suffix = source.slice(end, line.end);
|
|
373
|
-
changes.push({start: line.start, end: line.next, text: suffix.trimStart().startsWith('#') ?
|
|
273
|
+
changes.push({start: line.start, end: line.next, text: suffix.trimStart().startsWith('#') ? suffix + line.eol : ''});
|
|
374
274
|
};
|
|
375
275
|
const replaceValue = (field, text) => changes.push({start: field.start, end: field.end,
|
|
376
276
|
text: (source[field.start - 1] === ':' ? ' ' : '') + text + (source[field.end] === '#' ? ' ' : '')});
|
|
377
277
|
for (const [key, supplied] of Object.entries(patch || {})) {
|
|
378
278
|
const font = ['mainfont', 'sansfont', 'monofont', 'defaultfont'].includes(key);
|
|
379
|
-
if (!font && !['fontsize', 'linestretch'
|
|
279
|
+
if (!font && !['fontsize', 'linestretch'].includes(key)) throw new TypeError('Unknown document setting: ' + key);
|
|
380
280
|
const matches = fields.filter(item => item.key === key);
|
|
381
281
|
if (matches.length > 1) throw new RangeError('Duplicate document setting: ' + key);
|
|
382
282
|
const field = matches[0];
|
|
383
|
-
const value = supplied === null ? null : font ? documentFont(supplied) : key === 'fontsize' ? fontSize(supplied) :
|
|
283
|
+
const value = supplied === null ? null : font ? documentFont(supplied) : key === 'fontsize' ? fontSize(supplied) : leading(supplied);
|
|
384
284
|
if (supplied !== null && !value) throw new TypeError('Invalid document setting: ' + key);
|
|
385
|
-
const encoded = value === null ? '' : font ? JSON.stringify(value.family) : key === 'fontsize' ? value.step :
|
|
386
|
-
if (
|
|
285
|
+
const encoded = value === null ? '' : font ? JSON.stringify(value.family) : key === 'fontsize' ? value.step : String(value.factor);
|
|
286
|
+
if (value !== null && before[key] && (font ? before[key].family === value.family : key === 'fontsize' ? same(before.fontsize.unit, value.unit) : before.linestretch.factor === value.factor)) continue;
|
|
287
|
+
if (key === 'fontsize' && value !== null && fontSize(encoded)?.unit !== value.unit) refuse(key);
|
|
387
288
|
if (!field) { if (value !== null) append.push(key + ': ' + encoded + eol); continue; }
|
|
388
289
|
if (field.opaque || field.invalid || field.multiline || field.block) refuse(key);
|
|
389
|
-
if (key === 'space') {
|
|
390
|
-
const map = spaceFields(source, field);
|
|
391
|
-
if (!map) refuse(key);
|
|
392
|
-
const known = map.fields.filter(item => Object.hasOwn(SPACE, item.key));
|
|
393
|
-
if (new Set(map.fields.map(item => item.key)).size !== map.fields.length) throw new RangeError('Duplicate document setting: space');
|
|
394
|
-
if (known.length && !before.space) refuse(key);
|
|
395
|
-
if (value === null) {
|
|
396
|
-
const unknown = map.fields.length !== known.length;
|
|
397
|
-
for (const item of known) {
|
|
398
|
-
if (map.flow) {
|
|
399
|
-
if (unknown) changes.push({start: item.entryStart, end: item.comma === null ? item.entryEnd : item.comma + 1, text: ''});
|
|
400
|
-
} else {
|
|
401
|
-
for (const child of item.children) {
|
|
402
|
-
const own = headingParts(source, item)?.spans.find(span => span.line === child);
|
|
403
|
-
if (!own) refuse(key);
|
|
404
|
-
removeLine(child, own.end, /^ */.exec(child.text)[0].length);
|
|
405
|
-
}
|
|
406
|
-
removeLine(item.line, item.end, item.indent);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
if (!unknown) removeLine(field.line, field.end);
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
if (before.space && encodeSpace(before.space) === encoded) continue;
|
|
413
|
-
if (!map.fields.length) { replaceValue(field, encoded); continue; }
|
|
414
|
-
const missing = [];
|
|
415
|
-
for (const name of Object.keys(SPACE)) {
|
|
416
|
-
if (before.space && JSON.stringify(before.space[name]) === JSON.stringify(value[name])) continue;
|
|
417
|
-
const item = map.fields.find(item => item.key === name);
|
|
418
|
-
const text = name === 'heading' ? '[' + value.heading.join(', ') + ']' : String(value[name]);
|
|
419
|
-
if (!item) { missing.push(name + ': ' + text); continue; }
|
|
420
|
-
if (name === 'heading') {
|
|
421
|
-
const pair = headingParts(source, item);
|
|
422
|
-
for (let i = 0; i < 2; i++) if (pair.values[i] !== value.heading[i]) {
|
|
423
|
-
const span = pair.spans[i], raw = source.slice(span.start, span.end);
|
|
424
|
-
changes.push({start: span.start + raw.length - raw.trimStart().length, end: span.end - raw.length + raw.trimEnd().length, text: String(value.heading[i])});
|
|
425
|
-
}
|
|
426
|
-
} else replaceValue(item, text);
|
|
427
|
-
}
|
|
428
|
-
if (missing.length) {
|
|
429
|
-
if (map.flow) {
|
|
430
|
-
const last = map.fields.at(-1);
|
|
431
|
-
changes.push({start: field.end - 1, end: field.end - 1, text: (last.comma === null ? ', ' : ' ') + missing.join(', ')});
|
|
432
|
-
} else {
|
|
433
|
-
const last = field.children.at(-1), indent = ' '.repeat(map.indent);
|
|
434
|
-
changes.push({start: last.next, end: last.next, text: missing.map(item => indent + item + eol).join('')});
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
continue;
|
|
438
|
-
}
|
|
439
290
|
if (field.children.length) refuse(key);
|
|
440
291
|
if (value === null) removeLine(field.line, field.end);
|
|
441
292
|
else replaceValue(field, encoded);
|
|
@@ -472,10 +323,6 @@ export function documentSettingsStyle(settings, defaultFont) {
|
|
|
472
323
|
const decls = [];
|
|
473
324
|
if (settings.fontsize) decls.push('--md-text-body:' + settings.fontsize.css);
|
|
474
325
|
if (settings.linestretch || settings.fontsize) decls.push('--md-line:calc(var(--md-text-body) * ' + (settings.linestretch?.factor ?? DOCUMENT_LEADING) + ')');
|
|
475
|
-
if (settings.space) {
|
|
476
|
-
decls.push('--md-space-paragraph:' + settings.space.paragraph, '--md-space-heading-before:' + settings.space.heading[0],
|
|
477
|
-
'--md-space-heading-after:' + settings.space.heading[1], '--md-space-block:' + settings.space.block);
|
|
478
|
-
}
|
|
479
326
|
const {main, sans, mono} = documentSettingsFonts(settings, defaultFont);
|
|
480
327
|
if (sans) decls.push('--md-font-sans:' + (sans.css || fontFamilyCss(sans.family)));
|
|
481
328
|
if (main) decls.push('font-family:' + (main.css || fontFamilyCss(main.family)));
|