rapier-markdown-kit 1.2.42 → 1.2.44
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/kit/ledger/data.mjs +7 -3
- package/dist/kit/ledger/format.mjs +30 -10
- package/dist/kit/ledger/journal-records.mjs +169 -99
- package/dist/kit/render-markdown.mjs +318 -43
- package/dist/kit/render-sanitize.mjs +67 -2
- package/dist/kit/render.mjs +24 -7
- package/dist/layout/model.mjs +13 -0
- package/dist/spec/md-assets.mjs +7 -10
- package/dist/spec/md-layout.mjs +1 -1
- package/package.json +1 -1
package/dist/kit/ledger/data.mjs
CHANGED
|
@@ -110,11 +110,15 @@ function keyedRow(row, depth) {
|
|
|
110
110
|
}
|
|
111
111
|
return json;
|
|
112
112
|
}
|
|
113
|
+
const plainRowArrays = new WeakSet();
|
|
113
114
|
export function* canonicalRowsParts(rows, depth = 0) {
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
if (!(depth <= 64 && plainRowArrays.has(rows))) {
|
|
116
|
+
const {array} = fields(rows, depth, new Set());
|
|
117
|
+
if (!array) { yield* canonicalParts(rows, depth); return; }
|
|
118
|
+
if (Object.isFrozen(rows) && depth <= 64) plainRowArrays.add(rows);
|
|
119
|
+
}
|
|
116
120
|
yield '[';
|
|
117
|
-
for (let i = 0; i <
|
|
121
|
+
for (let i = 0; i < rows.length; i++) { if (i) yield ','; yield canonicalRow(rows[i], depth + 1); }
|
|
118
122
|
yield ']';
|
|
119
123
|
}
|
|
120
124
|
export function exactKeys(value, keys) {
|
|
@@ -10,10 +10,10 @@ import {minimalHistorySplice} from './inverse-source.mjs';
|
|
|
10
10
|
import {evaluateWill} from '../../agent/will.mjs';
|
|
11
11
|
export {textRoot, rootAfter};
|
|
12
12
|
const rootShape = value => typeof value === 'string' && /^\d+:[a-z0-9]+:[a-z0-9]+$/.test(value);
|
|
13
|
-
function* checkedRecords(ledger, prepared) {
|
|
13
|
+
function* checkedRecords(ledger, prepared, from = null) {
|
|
14
14
|
if (!prepared.ok || ledger.records.length !== prepared.records.length) throw fault('record chain differs');
|
|
15
|
-
let root = ledger.start.root, revision = ledger.start.revision;
|
|
16
|
-
for (let index = 0; index < prepared.records.length; index++) {
|
|
15
|
+
let root = from ? from.root : ledger.start.root, revision = from ? from.revision : ledger.start.revision;
|
|
16
|
+
for (let index = from ? from.index : 0; index < prepared.records.length; index++) {
|
|
17
17
|
const record = ledger.records[index];
|
|
18
18
|
if (!Array.isArray(record.splices) || !prepared.validRecord(index,
|
|
19
19
|
ledger.documentAuthority, 64 * 1024 * 1024, utf8Length, !ledger.complete) ||
|
|
@@ -170,6 +170,7 @@ const expandedRows = new WeakMap();
|
|
|
170
170
|
const sameSplices = (a, b) => a === b || a.length === b.length &&
|
|
171
171
|
a.every((row, i) => row.pos === b[i].pos && row.removed === b[i].removed && row.inserted === b[i].inserted);
|
|
172
172
|
const sameEffect = (a, b) => a === b || !!a && !!b && canonicalJSON(a) === canonicalJSON(b);
|
|
173
|
+
let recentLedgers = [];
|
|
173
174
|
function* produceLedger({text, metadata, records, documentAuthority, revision, root, complete = false, earlier = records} = {}, native = false) {
|
|
174
175
|
if (!_rapierValidMetadata(metadata)) throw fault('document metadata required');
|
|
175
176
|
metadata = {...metadata};
|
|
@@ -191,16 +192,30 @@ function* produceLedger({text, metadata, records, documentAuthority, revision, r
|
|
|
191
192
|
yield;
|
|
192
193
|
}
|
|
193
194
|
const headBytes = bytes;
|
|
195
|
+
let base = recentLedgers.find(row => row.rows.length <= expanded.length && row.rows.every((value, at) => value === expanded[at]));
|
|
194
196
|
let startSource = new HistorySource(text), startMetadata = {...metadata};
|
|
195
|
-
for (let i = expanded.length - 1; i >= 0; i--) {
|
|
197
|
+
for (let i = expanded.length - 1; i >= (base ? base.rows.length : 0); i--) {
|
|
196
198
|
startSource = startSource.apply(expanded[i].splices, true);
|
|
197
|
-
startMetadata = _rapierTransformMetadata(startMetadata, expanded[i].metadata, true);
|
|
199
|
+
if (expanded[i].metadata) startMetadata = _rapierTransformMetadata(startMetadata, expanded[i].metadata, true);
|
|
198
200
|
if (startSource === null || !startMetadata) throw fault('history does not reverse from this document');
|
|
199
201
|
for (const row of expanded[i].splices) bytes += utf8Length(row.removed) - utf8Length(row.inserted);
|
|
200
202
|
if (bytes > 64 * 1024 * 1024) throw fault('document exceeds the editor text limit');
|
|
201
203
|
yield;
|
|
202
204
|
}
|
|
203
|
-
|
|
205
|
+
if (base && (bytes !== base.headBytes || startSource.length !== base.headText.length || !startSource.matches(0, base.headText) ||
|
|
206
|
+
canonicalJSON(startMetadata) !== base.headMetadata)) {
|
|
207
|
+
base = null; bytes = headBytes; startSource = new HistorySource(text); startMetadata = {...metadata};
|
|
208
|
+
for (let i = expanded.length - 1; i >= 0; i--) {
|
|
209
|
+
startSource = startSource.apply(expanded[i].splices, true);
|
|
210
|
+
if (expanded[i].metadata) startMetadata = _rapierTransformMetadata(startMetadata, expanded[i].metadata, true);
|
|
211
|
+
if (startSource === null || !startMetadata) throw fault('history does not reverse from this document');
|
|
212
|
+
for (const row of expanded[i].splices) bytes += utf8Length(row.removed) - utf8Length(row.inserted);
|
|
213
|
+
if (bytes > 64 * 1024 * 1024) throw fault('document exceeds the editor text limit');
|
|
214
|
+
yield;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (base) { startMetadata = {...base.startMetadata}; bytes = base.startBytes; }
|
|
218
|
+
const startText = base ? base.startText : startSource.slice();
|
|
204
219
|
const unchangedText = expanded.every(row => !row.splices.length);
|
|
205
220
|
const contentRoot = headFacts.contentRoot;
|
|
206
221
|
revision ??= expanded.at(-1)?.transaction.revision ?? 0;
|
|
@@ -209,19 +224,24 @@ function* produceLedger({text, metadata, records, documentAuthority, revision, r
|
|
|
209
224
|
const startRevision = expanded[0]?.transaction.baseRevision ?? revision, startRoot = expanded[0]?.beforeHash ?? root;
|
|
210
225
|
if (typeof documentAuthority !== 'string' || !documentAuthority || documentAuthority.length > 256) throw fault('unsupported or invalid envelope');
|
|
211
226
|
if (!nonnegative(startRevision) || !rootShape(startRoot)) throw fault('invalid start');
|
|
212
|
-
const startFacts = unchangedText ? headFacts : yield* sourceFacts(startText, native);
|
|
227
|
+
const startFacts = unchangedText ? headFacts : base ? base.startFacts : yield* sourceFacts(startText, native);
|
|
213
228
|
if (startRevision === 0 && startRoot !== startFacts.contentRoot) throw fault('invalid start');
|
|
214
229
|
const headSHA = headFacts.sha256, startSHA = startFacts.sha256;
|
|
215
230
|
const payload = {format: 'rapier-ledger/2', documentAuthority,
|
|
216
231
|
start: {text: startText, revision: startRevision, root: startRoot, sha256: startSHA, metadata: startMetadata},
|
|
217
232
|
records: expanded, head: {revision, root, sha256: headSHA, metadata: {...metadata}}, complete: complete === true && startRevision === 0 && expanded.every((row, i) => !i || row.transaction.baseRevision === expanded[i - 1].transaction.revision)};
|
|
218
|
-
|
|
233
|
+
const from = base && base.documentAuthority === documentAuthority && base.complete === payload.complete &&
|
|
234
|
+
base.startRoot === startRoot && base.startRevision === startRevision ? {index: base.rows.length, root: base.chainRoot, revision: base.chainRevision} : null;
|
|
235
|
+
for (const _record of checkedRecords(payload, prepared, from)) yield;
|
|
219
236
|
if (expanded.some(row => Object.hasOwn(row, 'authored'))) {
|
|
220
237
|
try { authoredHistory(startText, expanded); } catch (_) { throw fault('authored origin differs'); }
|
|
221
238
|
}
|
|
222
239
|
const replayedMetadata = prepared.replayMetadata(startMetadata);
|
|
223
240
|
if (!replayedMetadata || canonicalJSON(replayedMetadata) !== canonicalJSON(metadata)) throw fault('metadata does not describe this document');
|
|
224
241
|
const ledger = {...payload, sha256: yield* checksum(envelopeParts(payload), native)};
|
|
242
|
+
recentLedgers = [{rows: expanded, headText: text, headMetadata: canonicalJSON(metadata), headBytes, startText, startMetadata: {...startMetadata},
|
|
243
|
+
startFacts, startBytes: bytes, documentAuthority, complete: payload.complete, startRoot, startRevision, chainRoot: payload.head.root,
|
|
244
|
+
chainRevision: payload.head.revision}, ...recentLedgers.filter(row => row.rows[0] !== expanded[0] && row.documentAuthority === documentAuthority)].slice(0, 4);
|
|
225
245
|
ownLedger(ledger);
|
|
226
246
|
proofs.set(ledger, {shell: Array.from(envelopeParts({...ledger, start: {...ledger.start, text: ''}})).join(''), startText,
|
|
227
247
|
text, metadata: {...metadata}, root, revision, prepared: _rapierPrepareHistoryRecords(ledger.records),
|
|
@@ -273,7 +293,7 @@ function historyNavigation(ledger, text, metadata, prepared, source) {
|
|
|
273
293
|
let traversed = source, traversedMetadata = {...metadata};
|
|
274
294
|
for (let i = cursor - 1; i >= 0; i--) {
|
|
275
295
|
traversed = step(traversed, branch[i], false);
|
|
276
|
-
traversedMetadata = _rapierTransformMetadata(traversedMetadata, byId.get(branch[i]).metadata, true);
|
|
296
|
+
if (byId.get(branch[i]).metadata) traversedMetadata = _rapierTransformMetadata(traversedMetadata, byId.get(branch[i]).metadata, true);
|
|
277
297
|
if (traversed === null || !traversedMetadata) throw fault('undo branch does not reverse');
|
|
278
298
|
}
|
|
279
299
|
if (ledger.complete) {
|
|
@@ -284,7 +304,7 @@ function historyNavigation(ledger, text, metadata, prepared, source) {
|
|
|
284
304
|
traversed = source; traversedMetadata = {...metadata};
|
|
285
305
|
for (let i = cursor; i < branch.length; i++) {
|
|
286
306
|
traversed = step(traversed, branch[i], true);
|
|
287
|
-
traversedMetadata = _rapierTransformMetadata(traversedMetadata, byId.get(branch[i]).metadata);
|
|
307
|
+
if (byId.get(branch[i]).metadata) traversedMetadata = _rapierTransformMetadata(traversedMetadata, byId.get(branch[i]).metadata);
|
|
288
308
|
if (traversed === null || !traversedMetadata) throw fault('redo branch does not replay');
|
|
289
309
|
}
|
|
290
310
|
if (ledger.complete && pictures.size) {
|
|
@@ -110,7 +110,8 @@ function _rapierRecordIndex(records, shared = false) {
|
|
|
110
110
|
}
|
|
111
111
|
return value;
|
|
112
112
|
};
|
|
113
|
-
|
|
113
|
+
const extend = more => { for (const record of more) { const id = record?.transaction?.id; if (!byId.has(id)) byId.set(id, []); byId.get(id).push(record); } };
|
|
114
|
+
return {byId, extend, splices: record => resolve(record, false), metadata: record => resolve(record, true)};
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
const _rapierLedgerIndexes = new WeakMap();
|
|
@@ -233,87 +234,89 @@ function _rapierPictureFinish(record, original, earlier, lookup) {
|
|
|
233
234
|
});
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
function
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
inactive.add(ref);
|
|
286
|
-
}
|
|
237
|
+
function _rapierHistoryWalker(records, lookup, visit = null, observe = null) {
|
|
238
|
+
let nodes = new Map(), references = new Map(), pictures = new Map();
|
|
239
|
+
const byId = new Map(), finished = new Set(), earlier = [];
|
|
240
|
+
const update = (target, delta) => {
|
|
241
|
+
const pending = [[target, delta]];
|
|
242
|
+
while (pending.length) {
|
|
243
|
+
const [id, change] = pending.pop(), node = nodes.get(id), was = node.active;
|
|
244
|
+
node.blockers += change;
|
|
245
|
+
if (node.blockers < 0) throw Error('effect');
|
|
246
|
+
node.active = node.blockers === 0;
|
|
247
|
+
if (was !== node.active) for (const ref of node.references) pending.push([ref, node.active ? 1 : -1]);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
const activity = new Map();
|
|
251
|
+
const active = id => {
|
|
252
|
+
if (visit) return nodes.get(id).active;
|
|
253
|
+
const pending = [[id, 0]];
|
|
254
|
+
while (pending.length) {
|
|
255
|
+
const frame = pending.at(-1), target = frame[0];
|
|
256
|
+
if (activity.has(target)) { pending.pop(); continue; }
|
|
257
|
+
const dependents = nodes.get(target).dependents;
|
|
258
|
+
if (frame[1] === dependents.length) { activity.set(target, true); pending.pop(); continue; }
|
|
259
|
+
const next = dependents[frame[1]];
|
|
260
|
+
if (!activity.has(next)) pending.push([next, 0]);
|
|
261
|
+
else if (activity.get(next)) { activity.set(target, false); pending.pop(); }
|
|
262
|
+
else frame[1]++;
|
|
263
|
+
}
|
|
264
|
+
return activity.get(id);
|
|
265
|
+
};
|
|
266
|
+
const lastUndo = new Map(), contexts = new Map(), order = [];
|
|
267
|
+
const contextOf = origin => {
|
|
268
|
+
if (!origin) return null;
|
|
269
|
+
if (!_rapierValidAuthored(origin)) throw Error('origin');
|
|
270
|
+
const known = new Set(), pending = origin.basis.slice();
|
|
271
|
+
while (pending.length) {
|
|
272
|
+
const id = pending.pop(), context = contexts.get(id);
|
|
273
|
+
if (!context) throw Error('origin');
|
|
274
|
+
if (known.has(id)) continue;
|
|
275
|
+
known.add(id);
|
|
276
|
+
if (context.basis) pending.push(...context.basis);
|
|
277
|
+
else for (let index = 0; index < context.index; index++) known.add(order[index]);
|
|
278
|
+
}
|
|
279
|
+
const inactive = new Set();
|
|
280
|
+
for (let index = order.length - 1; index >= 0; index--) {
|
|
281
|
+
const id = order[index];
|
|
282
|
+
if (!known.has(id) || inactive.has(id)) continue;
|
|
283
|
+
for (const ref of references.get(id)) {
|
|
284
|
+
if (!known.has(ref)) throw Error('origin');
|
|
285
|
+
inactive.add(ref);
|
|
287
286
|
}
|
|
288
|
-
|
|
289
|
-
};
|
|
290
|
-
|
|
287
|
+
}
|
|
288
|
+
return {known, inactive};
|
|
289
|
+
};
|
|
290
|
+
const walker = {observe, failed: false};
|
|
291
|
+
walker.add = record => {
|
|
292
|
+
if (walker.failed) return false;
|
|
293
|
+
try {
|
|
291
294
|
const tx = record?.transaction;
|
|
292
|
-
if (!tx || typeof tx.id !== 'string' || !tx.id || nodes.has(tx.id) || (tx.reverts && tx.reapplies)) return
|
|
295
|
+
if (!tx || typeof tx.id !== 'string' || !tx.id || nodes.has(tx.id) || (tx.reverts && tx.reapplies)) { walker.failed = true; return false; }
|
|
293
296
|
const supplied = tx.sourceTransactionIds || (tx.sourceTransactionId ? [tx.sourceTransactionId] : []);
|
|
294
297
|
if (!Array.isArray(supplied) || new Set(supplied).size !== supplied.length ||
|
|
295
|
-
(tx.sourceTransactionIds && tx.sourceTransactionId && (supplied.length !== 1 || supplied[0] !== tx.sourceTransactionId))) return
|
|
298
|
+
(tx.sourceTransactionIds && tx.sourceTransactionId && (supplied.length !== 1 || supplied[0] !== tx.sourceTransactionId))) { walker.failed = true; return false; }
|
|
296
299
|
let refs = supplied;
|
|
297
300
|
if (tx.operation === 'document.finish-picture' && tx.sourceTransactionId) {
|
|
298
301
|
const owner = tx.sourceTransactionId;
|
|
299
302
|
if (!nodes.has(owner) || !active(owner) || finished.has(owner) ||
|
|
300
|
-
!_rapierPictureFinish(record, byId.get(owner), earlier, lookup ||= _rapierRecordIndex(records))) return
|
|
303
|
+
!_rapierPictureFinish(record, byId.get(owner), earlier, lookup ||= _rapierRecordIndex(records))) { walker.failed = true; return false; }
|
|
301
304
|
pictures.set(tx.id, owner); finished.add(owner); refs = [];
|
|
302
305
|
}
|
|
303
306
|
if (tx.reverts || tx.reapplies) {
|
|
304
307
|
const target = tx.reverts || tx.reapplies;
|
|
305
|
-
if (!nodes.has(target) || (supplied.length && (supplied.length !== 1 || supplied[0] !== target))) return
|
|
308
|
+
if (!nodes.has(target) || (supplied.length && (supplied.length !== 1 || supplied[0] !== target))) { walker.failed = true; return false; }
|
|
306
309
|
if (tx.reverts) refs = [target];
|
|
307
310
|
else {
|
|
308
311
|
const context = contextOf(record.authored || tx.authored);
|
|
309
312
|
const undo = (lastUndo.get(target) || []).findLast(id => context
|
|
310
313
|
? context.known.has(id) && !context.inactive.has(id) : active(id));
|
|
311
|
-
if (!undo) return
|
|
314
|
+
if (!undo) { walker.failed = true; return false; }
|
|
312
315
|
refs = [undo];
|
|
313
316
|
}
|
|
314
317
|
}
|
|
315
|
-
if (refs.some(id => typeof id !== 'string' || !nodes.has(id) || pictures.has(id))) return
|
|
316
|
-
if (tx.actor?.kind === 'agent' && refs.some(id => byId.get(id).transaction.actor?.kind !== 'agent')) return
|
|
318
|
+
if (refs.some(id => typeof id !== 'string' || !nodes.has(id) || pictures.has(id))) { walker.failed = true; return false; }
|
|
319
|
+
if (tx.actor?.kind === 'agent' && refs.some(id => byId.get(id).transaction.actor?.kind !== 'agent')) { walker.failed = true; return false; }
|
|
317
320
|
nodes.set(tx.id, {active: true, blockers: 0, references: refs, dependents: []}); references.set(tx.id, refs.slice());
|
|
318
321
|
byId.set(tx.id, record); earlier.push(record);
|
|
319
322
|
for (const ref of refs) {
|
|
@@ -328,23 +331,45 @@ function _rapierWalkHistoryEffects(records, lookup, visit = null, observe = null
|
|
|
328
331
|
lastUndo.get(tx.reverts).push(tx.id);
|
|
329
332
|
}
|
|
330
333
|
if (visit) visit(record, nodes, refs);
|
|
331
|
-
if (observe) observe(record, refs, active);
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
if (walker.observe) walker.observe(record, refs, active);
|
|
335
|
+
return true;
|
|
336
|
+
} catch (_) { walker.failed = true; return false; }
|
|
337
|
+
};
|
|
338
|
+
walker.finish = () => {
|
|
339
|
+
if (walker.failed) return {ok: false};
|
|
340
|
+
const blockers = new Map(), effectiveActIds = [];
|
|
341
|
+
for (let i = order.length - 1; i >= 0; i--) {
|
|
342
|
+
const id = order[i], node = nodes.get(id), on = visit ? node.active : !(blockers.get(id) > 0);
|
|
343
|
+
if (!visit && on) for (const ref of node.references) blockers.set(ref, (blockers.get(ref) || 0) + 1);
|
|
344
|
+
if (on && !pictures.has(id)) effectiveActIds.push(id);
|
|
336
345
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
346
|
+
effectiveActIds.reverse();
|
|
347
|
+
const result = {ok: true, effectiveActIds, active: new Set(effectiveActIds), references, pictures};
|
|
348
|
+
walker.shared = true;
|
|
349
|
+
return result;
|
|
350
|
+
};
|
|
351
|
+
const add = walker.add;
|
|
352
|
+
walker.add = record => {
|
|
353
|
+
if (walker.shared) { references = new Map(references); pictures = new Map(pictures); walker.shared = false; }
|
|
354
|
+
return add(record);
|
|
355
|
+
};
|
|
356
|
+
return walker;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function _rapierWalkHistoryEffects(records, lookup, visit = null, observe = null) {
|
|
360
|
+
if (!Array.isArray(records)) return {ok: false};
|
|
361
|
+
const walker = _rapierHistoryWalker(records, lookup, visit, observe);
|
|
362
|
+
for (const record of records) if (!walker.add(record)) return {ok: false};
|
|
363
|
+
return walker.finish();
|
|
340
364
|
}
|
|
341
365
|
|
|
342
366
|
function _rapierHistoryEffects(records, visit = null) {
|
|
343
367
|
return _rapierWalkHistoryEffects(records, null, visit);
|
|
344
368
|
}
|
|
345
369
|
|
|
346
|
-
function _rapierMetadataProof(lookup) {
|
|
347
|
-
const values = {}, required = {},
|
|
370
|
+
function _rapierMetadataProof(lookup, from = null) {
|
|
371
|
+
const values = {...from?.values}, required = {...from?.required},
|
|
372
|
+
assignments = {filename: [...(from?.assignments.filename || [])], docKind: [...(from?.assignments.docKind || [])]};
|
|
348
373
|
const requireInitial = (key, value) => {
|
|
349
374
|
if (Object.hasOwn(required, key) && required[key] !== value) throw Error('metadata_effect');
|
|
350
375
|
required[key] = value;
|
|
@@ -371,7 +396,7 @@ function _rapierMetadataProof(lookup) {
|
|
|
371
396
|
if (!_rapierValidMetadata(initial) || Object.keys(required).some(key => initial[key] !== required[key])) return null;
|
|
372
397
|
return {...initial, ...values};
|
|
373
398
|
};
|
|
374
|
-
return {observe, replay};
|
|
399
|
+
return {observe, replay, fork: other => _rapierMetadataProof(other || lookup, {values, required, assignments})};
|
|
375
400
|
}
|
|
376
401
|
|
|
377
402
|
function _rapierMetadataState(initial, records, effects = _rapierHistoryEffects(records)) {
|
|
@@ -478,16 +503,79 @@ const _rapierPrepareHistoryRecords = (() => {
|
|
|
478
503
|
frame.descriptors = descriptors; frame.fields = fields;
|
|
479
504
|
frame.leaving = true; active.add(value); pending.push(frame);
|
|
480
505
|
for (let at = fields.length - 1; at >= 0; at--) {
|
|
481
|
-
const key = fields[at]
|
|
506
|
+
const key = fields[at], child = descriptors[key].value;
|
|
507
|
+
const prior = array && child && typeof child === 'object' ? copies.get(child) : undefined;
|
|
508
|
+
if (prior?.immutable && !active.has(child) && frame.depth + 1 + prior.height <= 64) {
|
|
509
|
+
finish({parent: frame, key}, prior.copy, true, prior.height); continue;
|
|
510
|
+
}
|
|
511
|
+
pending.push({value: child, parent: frame, key, depth: frame.depth + 1});
|
|
482
512
|
}
|
|
483
513
|
}
|
|
484
514
|
return result.value;
|
|
485
515
|
};
|
|
516
|
+
let resumable = [];
|
|
517
|
+
const rowOf = (lookup, record) => {
|
|
518
|
+
const splices = lookup.splices(record), metadata = lookup.metadata(record);
|
|
519
|
+
if (splices && !Object.isFrozen(splices)) {
|
|
520
|
+
for (const row of splices) Object.freeze(row);
|
|
521
|
+
Object.freeze(splices);
|
|
522
|
+
}
|
|
523
|
+
if (metadata && !Object.isFrozen(metadata)) {
|
|
524
|
+
for (const pair of Object.values(metadata)) Object.freeze(pair);
|
|
525
|
+
Object.freeze(metadata);
|
|
526
|
+
}
|
|
527
|
+
return Object.freeze({record, splices, metadata});
|
|
528
|
+
};
|
|
529
|
+
const observe = (records, basis, byId, rows, effects, proof) => {
|
|
530
|
+
for (const refs of effects.references.values()) Object.freeze(refs);
|
|
531
|
+
const effectView = Object.freeze({ok: true, effectiveActIds: Object.freeze(effects.effectiveActIds),
|
|
532
|
+
active: view(effects.active), references: view(effects.references), pictures: view(effects.pictures)});
|
|
533
|
+
const observation = Object.freeze({ok: effects.ok, records, rows: Object.freeze(rows), effects: effectView, byId: view(byId),
|
|
534
|
+
replayMetadata: initial => effects.ok ? proof.replay(initial) : null,
|
|
535
|
+
validRecord: (index, documentAuthority, maxDocumentBytes, utf8Length, allowGap = false) => {
|
|
536
|
+
if (!effects.ok || !Number.isSafeInteger(index) || index < 0 || index >= records.length) return false;
|
|
537
|
+
const row = rows[index], tx = row.record.transaction;
|
|
538
|
+
return _rapierCheckLedgerRecord(row.record, records[index - 1] || null, documentAuthority, maxDocumentBytes, utf8Length, allowGap,
|
|
539
|
+
{...row, duplicate: false, semantic: !!(tx.reverts || tx.reapplies || tx.sourceTransactionId || tx.sourceTransactionIds?.length)});
|
|
540
|
+
}});
|
|
541
|
+
prepared = new WeakMap([[records, {basis, observation}]]);
|
|
542
|
+
return observation;
|
|
543
|
+
};
|
|
544
|
+
const authorityOf = state => state.records[0]?.transaction?.documentAuthority;
|
|
545
|
+
const keep = state => { resumable = [state, ...resumable.filter(row => row !== state && row.records[0] !== state.records[0] &&
|
|
546
|
+
authorityOf(row) === authorityOf(state))].slice(0, 4); };
|
|
547
|
+
const extend = records => {
|
|
548
|
+
const base = resumable.find(row => row.records.length < records.length && row.records[0] === records[0] &&
|
|
549
|
+
row.records.every((record, at) => record === records[at]));
|
|
550
|
+
if (!base) return null;
|
|
551
|
+
resumable = resumable.filter(row => row !== base);
|
|
552
|
+
const more = records.slice(base.records.length), byId = new Map(base.byId);
|
|
553
|
+
for (const record of more) {
|
|
554
|
+
const id = record?.transaction?.id;
|
|
555
|
+
if (typeof id !== 'string' || !id || byId.has(id)) return null;
|
|
556
|
+
byId.set(id, record);
|
|
557
|
+
}
|
|
558
|
+
const {lookup, walker} = base;
|
|
559
|
+
lookup.extend(more);
|
|
560
|
+
const rows = base.rows.concat(more.map(record => rowOf(lookup, record)));
|
|
561
|
+
const proof = base.proof.fork(lookup);
|
|
562
|
+
walker.observe = proof.observe;
|
|
563
|
+
for (const record of more) if (!walker.add(record)) return null;
|
|
564
|
+
const effects = walker.finish();
|
|
565
|
+
if (!effects.ok) return null;
|
|
566
|
+
if (rows.every(row => row.splices && row.metadata !== undefined)) keep({records, lookup, walker, proof, byId, rows});
|
|
567
|
+
return observe(records, records, byId, rows, effects, proof);
|
|
568
|
+
};
|
|
486
569
|
return (input, earlier = input) => {
|
|
487
570
|
try {
|
|
488
571
|
if (!Array.isArray(input) || !Array.isArray(earlier)) return {ok: false};
|
|
489
572
|
const records = capture(input), basis = input === earlier ? records : capture(earlier), previous = prepared.get(records);
|
|
490
573
|
if (previous?.basis === basis) return previous.observation;
|
|
574
|
+
if (basis === records) {
|
|
575
|
+
let grown = null;
|
|
576
|
+
try { grown = extend(records); } catch (_) { grown = null; }
|
|
577
|
+
if (grown) return grown;
|
|
578
|
+
}
|
|
491
579
|
const byId = new Map();
|
|
492
580
|
for (const record of records) {
|
|
493
581
|
const id = record?.transaction?.id;
|
|
@@ -495,32 +583,14 @@ const _rapierPrepareHistoryRecords = (() => {
|
|
|
495
583
|
byId.set(id, record);
|
|
496
584
|
}
|
|
497
585
|
const lookup = _rapierRecordIndex(basis), proof = _rapierMetadataProof(lookup);
|
|
498
|
-
const rows = records.map(record =>
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
Object.freeze(splices);
|
|
503
|
-
}
|
|
504
|
-
if (metadata && !Object.isFrozen(metadata)) {
|
|
505
|
-
for (const pair of Object.values(metadata)) Object.freeze(pair);
|
|
506
|
-
Object.freeze(metadata);
|
|
507
|
-
}
|
|
508
|
-
return Object.freeze({record, splices, metadata});
|
|
509
|
-
});
|
|
510
|
-
const effects = _rapierWalkHistoryEffects(records, lookup, null, proof.observe);
|
|
586
|
+
const rows = records.map(record => rowOf(lookup, record));
|
|
587
|
+
const walker = _rapierHistoryWalker(records, lookup, null, proof.observe);
|
|
588
|
+
for (const record of records) if (!walker.add(record)) return {ok: false};
|
|
589
|
+
const effects = walker.finish();
|
|
511
590
|
if (!effects.ok) return {ok: false};
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const observation = Object.freeze({ok: effects.ok, records, rows: Object.freeze(rows), effects: effectView, byId: view(byId),
|
|
516
|
-
replayMetadata: initial => effects.ok ? proof.replay(initial) : null,
|
|
517
|
-
validRecord: (index, documentAuthority, maxDocumentBytes, utf8Length, allowGap = false) => {
|
|
518
|
-
if (!effects.ok || !Number.isSafeInteger(index) || index < 0 || index >= records.length) return false;
|
|
519
|
-
const row = rows[index], tx = row.record.transaction;
|
|
520
|
-
return _rapierCheckLedgerRecord(row.record, records[index - 1] || null, documentAuthority, maxDocumentBytes, utf8Length, allowGap,
|
|
521
|
-
{...row, duplicate: false, semantic: !!(tx.reverts || tx.reapplies || tx.sourceTransactionId || tx.sourceTransactionIds?.length)});
|
|
522
|
-
}});
|
|
523
|
-
prepared = new WeakMap([[records, {basis, observation}]]); return observation;
|
|
591
|
+
if (basis === records && rows.every(row => row.splices && row.metadata !== undefined))
|
|
592
|
+
keep({records, lookup, walker, proof, byId, rows});
|
|
593
|
+
return observe(records, basis, byId, rows, effects, proof);
|
|
524
594
|
} catch (_) { return {ok: false}; }
|
|
525
595
|
};
|
|
526
596
|
})();
|
|
@@ -55,18 +55,23 @@ function createMarkdownRenderer(runtime) {
|
|
|
55
55
|
window?.addEventListener?.('rapier:original-file-ready', scheduleWikiEmbeds);
|
|
56
56
|
const wikiMode = options => options.wikiEmbedding ? 'links' : options.wikiLinks !== undefined ? options.wikiLinks
|
|
57
57
|
: globalThis.RapierOriginalFolderCore?.currentOriginal?.() ? 'label' : false;
|
|
58
|
+
let codeLeft = Infinity;
|
|
58
59
|
function initMarkdownIt() {
|
|
59
60
|
if (typeof window.markdownit !== 'function') throw new Error('markdownit');
|
|
60
61
|
if (typeof _rapierMarkdownPreview === 'function') globalThis.rapierRenderPreview = _rapierMarkdownPreview;
|
|
61
62
|
|
|
62
63
|
md = window.markdownit({
|
|
63
64
|
...RAPIER_MARKDOWN_SPEC.options,
|
|
64
|
-
highlight: (code, lang) => lang && _rapierHighlightAdmitted(code) ? _rapierCodeHtml(code, lang) : '',
|
|
65
|
+
highlight: (code, lang) => lang && _rapierHighlightAdmitted(code) && (codeLeft -= code.length) >= 0 ? _rapierCodeHtml(code, lang) : '',
|
|
65
66
|
});
|
|
66
67
|
|
|
67
68
|
_rapierApplyMarkdownSpec(md, window);
|
|
68
69
|
globalThis.RapierImageAssets.installMarkdownImages(md);
|
|
69
70
|
_rapierInstallSemanticProbe(md);
|
|
71
|
+
md.core.ruler.after('block', 'rapier_part_decorations', state => {
|
|
72
|
+
if (state.env.rapierPartDecorations && !/[<$\\]/.test(state.src) && !state.src.includes('^['))
|
|
73
|
+
state.tokens = _rapierPartDecorationGroups(state.tokens).flat();
|
|
74
|
+
});
|
|
70
75
|
_rapierInstallMarkdownMath(md, RAPIER_MARKDOWN_SPEC.rules.mathBlock);
|
|
71
76
|
|
|
72
77
|
const markOpenDefault = md.renderer.rules.mark_open ||
|
|
@@ -138,7 +143,7 @@ function initMarkdownIt() {
|
|
|
138
143
|
'" data-rapier-image-source="' + esc(encodeURIComponent(token.content)) + '">' + esc(label) + '</span>';
|
|
139
144
|
}
|
|
140
145
|
const note = embed && !env.rapierWikiEmbedding;
|
|
141
|
-
if (note) scheduleWikiEmbeds();
|
|
146
|
+
if (note && !env.rapierPassive) scheduleWikiEmbeds();
|
|
142
147
|
return '<span class="rapier-source-token rapier-source-token--wiki' + (note ? '-embed' : '') +
|
|
143
148
|
'" data-rapier-source="' + esc(encodeURIComponent(token.content)) + '" data-rapier-visible="' + esc(encodeURIComponent(label)) +
|
|
144
149
|
'"><a href="' + esc(href) + '">' + esc(label) + '</a></span>';
|
|
@@ -371,12 +376,12 @@ function initMarkdownIt() {
|
|
|
371
376
|
const mathProvider = env.rapierProviders === false ? null : _rapierProviders.math;
|
|
372
377
|
const mathNeeded = provider?.requiresMath?.(src) === true;
|
|
373
378
|
const mathReady = !mathNeeded || mathProvider?.status === 'ready';
|
|
374
|
-
if (!mathReady && !mathProvider?.request?.() && env.rapierProviders !== false && !_mathPromptedOnce) {
|
|
379
|
+
if (!mathReady && !env.rapierPassive && !mathProvider?.request?.() && env.rapierProviders !== false && !_mathPromptedOnce) {
|
|
375
380
|
_mathPromptedOnce = true;
|
|
376
381
|
try { _rapierUiMath.request(); } catch (_) {}
|
|
377
382
|
}
|
|
378
383
|
const ready = diagramReady && mathReady;
|
|
379
|
-
if (!diagramReady && !provider?.request?.() && env.rapierProviders !== false && !_diagramPromptedOnce) {
|
|
384
|
+
if (!diagramReady && !env.rapierPassive && !provider?.request?.() && env.rapierProviders !== false && !_diagramPromptedOnce) {
|
|
380
385
|
_diagramPromptedOnce = true;
|
|
381
386
|
try { _rapierUiDiagram.request(); } catch (_) {}
|
|
382
387
|
}
|
|
@@ -420,7 +425,7 @@ function initMarkdownIt() {
|
|
|
420
425
|
if (env.rapierPage) return sourceHtml;
|
|
421
426
|
const mathProvider = env.rapierProviders === false ? null : _rapierProviders.math;
|
|
422
427
|
if (!mathProvider || mathProvider.status !== 'ready' || typeof mathProvider.renderToString !== 'function') {
|
|
423
|
-
if (!mathProvider?.request?.() && env.rapierProviders !== false && !_mathPromptedOnce) {
|
|
428
|
+
if (!env.rapierPassive && !mathProvider?.request?.() && env.rapierProviders !== false && !_mathPromptedOnce) {
|
|
424
429
|
_mathPromptedOnce = true;
|
|
425
430
|
try { _rapierUiMath.request(); } catch (_) {}
|
|
426
431
|
}
|
|
@@ -454,10 +459,215 @@ function initMarkdownIt() {
|
|
|
454
459
|
globalThis.RapierImageAssets.configureParser(md, _rapierSplitOpeningFrontmatter);
|
|
455
460
|
const render = md.renderer.render;
|
|
456
461
|
md.renderer.render = function (tokens, options, env) {
|
|
457
|
-
return render.call(this, _rapierCloseOpenDetails(tokens), options, env);
|
|
462
|
+
return render.call(this, _rapierHideForeignParagraphs(_rapierCloseOpenDetails(tokens)), options, env);
|
|
458
463
|
};
|
|
459
464
|
}
|
|
460
465
|
|
|
466
|
+
function _rapierHtmlTagStack(html, stack = []) {
|
|
467
|
+
if (!html) return stack;
|
|
468
|
+
const swallow = _rapierHtmlTagStack.swallow || (_rapierHtmlTagStack.swallow = new Set('select template textarea title style xmp plaintext noscript iframe noembed noframes script svg math'.split(' ')));
|
|
469
|
+
const rawTags = _rapierHtmlTagStack.raw || (_rapierHtmlTagStack.raw = new Set('script style textarea title xmp iframe noembed noframes noscript plaintext'.split(' ')));
|
|
470
|
+
let i = 0;
|
|
471
|
+
while (i < html.length) {
|
|
472
|
+
const top = stack.at(-1);
|
|
473
|
+
if (top && top.raw) {
|
|
474
|
+
const closer = new RegExp('</' + top.name + '(?=[\\t\\n\\f\\r />])', 'ig');
|
|
475
|
+
closer.lastIndex = i;
|
|
476
|
+
const found = closer.exec(html);
|
|
477
|
+
if (!found) break;
|
|
478
|
+
i = found.index;
|
|
479
|
+
}
|
|
480
|
+
const open = html.indexOf('<', i);
|
|
481
|
+
if (open < 0) break;
|
|
482
|
+
if (html.startsWith('<!--', open)) {
|
|
483
|
+
const end = html.indexOf('-->', open + 4);
|
|
484
|
+
if (end < 0) break;
|
|
485
|
+
i = end + 3;
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
if (html.startsWith('<!', open) || html.startsWith('<?', open)) {
|
|
489
|
+
const end = html.indexOf('>', open + 2);
|
|
490
|
+
i = end < 0 ? html.length : end + 1;
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
const match = /^<\/?([A-Za-z][A-Za-z0-9:-]*)/.exec(html.slice(open));
|
|
494
|
+
if (!match) { i = open + 1; continue; }
|
|
495
|
+
const name = match[1].toLowerCase();
|
|
496
|
+
let end = open + match[0].length, quote = '';
|
|
497
|
+
for (; end < html.length; end++) {
|
|
498
|
+
const character = html[end];
|
|
499
|
+
if (quote) { if (character === quote) quote = ''; }
|
|
500
|
+
else if (character === '"' || character === "'") quote = character;
|
|
501
|
+
else if (character === '>') break;
|
|
502
|
+
}
|
|
503
|
+
if (end >= html.length) break;
|
|
504
|
+
if (html[open + 1] === '/') {
|
|
505
|
+
let at = stack.length - 1;
|
|
506
|
+
while (at >= 0 && stack[at].name !== name && !swallow.has(stack[at].name)) at--;
|
|
507
|
+
if (at >= 0 && stack[at].name === name) stack.length = at;
|
|
508
|
+
} else stack.push({name, at: open, tagEnd: end + 1, raw: rawTags.has(name)});
|
|
509
|
+
i = end + 1;
|
|
510
|
+
}
|
|
511
|
+
return stack;
|
|
512
|
+
}
|
|
513
|
+
function _rapierForeignOpen(stack) {
|
|
514
|
+
for (let index = 0; index < stack.length; index++) {
|
|
515
|
+
const name = stack[index].name;
|
|
516
|
+
if (name === 'svg' || name === 'math') return true;
|
|
517
|
+
}
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
function _rapierSealBlockHtml(html) {
|
|
521
|
+
if (!html || html.indexOf('<') < 0) return html;
|
|
522
|
+
const stack = _rapierHtmlTagStack(html);
|
|
523
|
+
const swallow = _rapierHtmlTagStack.swallow;
|
|
524
|
+
const foreign = _rapierSealBlockHtml.foreign || (_rapierSealBlockHtml.foreign = new Set(['svg', 'math']));
|
|
525
|
+
const cut = stack.find(frame => swallow.has(frame.name) && (frame.raw || foreign.has(frame.name)));
|
|
526
|
+
if (cut) {
|
|
527
|
+
const wrappers = stack.filter(frame => frame.at < cut.at);
|
|
528
|
+
return html.slice(0, cut.at) + _rapierSealBlockTail(html.slice(cut.at), wrappers);
|
|
529
|
+
}
|
|
530
|
+
const stale = stack.filter(frame => swallow.has(frame.name));
|
|
531
|
+
if (!stale.length) return html;
|
|
532
|
+
let out = html;
|
|
533
|
+
for (const frame of stale.sort((left, right) => right.at - left.at))
|
|
534
|
+
out = out.slice(0, frame.at) + escapeRapierHtmlText(out.slice(frame.at, frame.tagEnd)) + out.slice(frame.tagEnd);
|
|
535
|
+
return out;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function _rapierSealBlockTail(tail, wrappers) {
|
|
539
|
+
const open = wrappers.map(frame => frame.name);
|
|
540
|
+
let out = '', i = 0;
|
|
541
|
+
while (i < tail.length) {
|
|
542
|
+
const at = tail.indexOf('<', i);
|
|
543
|
+
if (at < 0) { out += escapeRapierHtmlText(tail.slice(i)); break; }
|
|
544
|
+
out += escapeRapierHtmlText(tail.slice(i, at));
|
|
545
|
+
const match = /^<\/([A-Za-z][A-Za-z0-9:-]*)\s*>/.exec(tail.slice(at));
|
|
546
|
+
if (match && open.at(-1) === match[1].toLowerCase()) {
|
|
547
|
+
out += match[0];
|
|
548
|
+
open.pop();
|
|
549
|
+
i = at + match[0].length;
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
out += escapeRapierHtmlText(tail[at]);
|
|
553
|
+
i = at + 1;
|
|
554
|
+
}
|
|
555
|
+
return out;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function _rapierRenderTokenHtml(tokens, index, env) {
|
|
559
|
+
const token = tokens[index], rule = md.renderer.rules[token.type];
|
|
560
|
+
return token.type === 'inline' ? md.renderer.renderInline(token.children, md.options, env)
|
|
561
|
+
: rule ? rule(tokens, index, md.options, env, md.renderer) : md.renderer.renderToken(tokens, index, md.options);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function _rapierTokenBlocks(tokens) {
|
|
565
|
+
const blocks = [];
|
|
566
|
+
let start = 0, depth = 0;
|
|
567
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
568
|
+
depth += tokens[index].nesting || 0;
|
|
569
|
+
if (depth <= 0) { blocks.push([start, index + 1]); start = index + 1; depth = 0; }
|
|
570
|
+
}
|
|
571
|
+
if (start < tokens.length) blocks.push([start, tokens.length]);
|
|
572
|
+
return blocks;
|
|
573
|
+
}
|
|
574
|
+
function _rapierScanHtmlBlocks(tokens, start, end, stack) {
|
|
575
|
+
for (let index = start; index < end; index++) {
|
|
576
|
+
if (tokens[index].type === 'html_block') _rapierHtmlTagStack(tokens[index].content || '', stack);
|
|
577
|
+
}
|
|
578
|
+
return stack;
|
|
579
|
+
}
|
|
580
|
+
function _rapierForeignSealRanges(tokens) {
|
|
581
|
+
const blocks = _rapierTokenBlocks(tokens);
|
|
582
|
+
const ranges = [];
|
|
583
|
+
const scanLater = ([start, end], frames) => {
|
|
584
|
+
if (tokens[start].type !== 'paragraph_open') return _rapierScanHtmlBlocks(tokens, start, end, frames);
|
|
585
|
+
for (const child of tokens[start + 1] && tokens[start + 1].children || [])
|
|
586
|
+
if (child.type === 'html_inline') _rapierHtmlTagStack(child.content || '', frames);
|
|
587
|
+
return frames;
|
|
588
|
+
};
|
|
589
|
+
for (let index = 0; index < blocks.length; index++) {
|
|
590
|
+
const stack = _rapierScanHtmlBlocks(tokens, blocks[index][0], blocks[index][1], []);
|
|
591
|
+
if (!_rapierForeignOpen(stack)) { ranges.push(blocks[index]); continue; }
|
|
592
|
+
const frames = stack.map(frame => ({name: frame.name, raw: frame.raw}));
|
|
593
|
+
let joined = -1;
|
|
594
|
+
for (let later = index + 1; later < blocks.length && later <= index + 512; later++) {
|
|
595
|
+
scanLater(blocks[later], frames);
|
|
596
|
+
if (!_rapierForeignOpen(frames)) { joined = later; break; }
|
|
597
|
+
}
|
|
598
|
+
if (joined < 0) { ranges.push(blocks[index]); continue; }
|
|
599
|
+
const range = [blocks[index][0], blocks[joined][1]];
|
|
600
|
+
for (let later = index + 1; later <= joined; later++) {
|
|
601
|
+
const [start, end] = blocks[later];
|
|
602
|
+
if (tokens[start].type === 'paragraph_open' && tokens[end - 1].type === 'paragraph_close' &&
|
|
603
|
+
(tokens[start + 1] && tokens[start + 1].children || []).some(child => child.type === 'html_inline'))
|
|
604
|
+
(range.hide || (range.hide = new Set())).add(start).add(end - 1);
|
|
605
|
+
}
|
|
606
|
+
ranges.push(range);
|
|
607
|
+
index = joined;
|
|
608
|
+
}
|
|
609
|
+
return ranges;
|
|
610
|
+
}
|
|
611
|
+
function _rapierHideForeignParagraphs(tokens) {
|
|
612
|
+
let out = tokens;
|
|
613
|
+
for (const range of _rapierForeignSealRanges(tokens)) {
|
|
614
|
+
if (!range.hide) continue;
|
|
615
|
+
if (out === tokens) out = tokens.slice();
|
|
616
|
+
for (const index of range.hide) out[index] = Object.assign(Object.create(Object.getPrototypeOf(tokens[index])), tokens[index], {hidden: true});
|
|
617
|
+
}
|
|
618
|
+
return out;
|
|
619
|
+
}
|
|
620
|
+
function _rapierMergeForeignBlocks(blocks, source, parser) {
|
|
621
|
+
const text = String(source || '');
|
|
622
|
+
const out = [];
|
|
623
|
+
const inline = new Map();
|
|
624
|
+
const scanLater = (row, frames) => {
|
|
625
|
+
if (!row) return frames;
|
|
626
|
+
if (row.type === 'html_block') return _rapierHtmlTagStack(String(row.raw || ''), frames);
|
|
627
|
+
if (row.type !== 'paragraph' || String(row.raw || '').indexOf('<') < 0) return frames;
|
|
628
|
+
let children = inline.get(row);
|
|
629
|
+
if (!children) {
|
|
630
|
+
if (!parser && !md) initMarkdownIt();
|
|
631
|
+
const parsed = (parser || md).parseInline(String(row.raw || ''), {});
|
|
632
|
+
children = parsed[0] && parsed[0].children || [];
|
|
633
|
+
inline.set(row, children);
|
|
634
|
+
}
|
|
635
|
+
for (const child of children) if (child.type === 'html_inline') _rapierHtmlTagStack(child.content || '', frames);
|
|
636
|
+
return frames;
|
|
637
|
+
};
|
|
638
|
+
let index = 0;
|
|
639
|
+
while (index < blocks.length) {
|
|
640
|
+
const block = blocks[index];
|
|
641
|
+
const stack = [];
|
|
642
|
+
if (block && block.type === 'html_block') _rapierHtmlTagStack(String(block.raw || ''), stack);
|
|
643
|
+
if (!_rapierForeignOpen(stack)) { out.push(block); index++; continue; }
|
|
644
|
+
const frames = stack.map(frame => ({name: frame.name, raw: frame.raw}));
|
|
645
|
+
let joined = -1;
|
|
646
|
+
for (let later = index + 1; later < blocks.length && later <= index + 512; later++) {
|
|
647
|
+
scanLater(blocks[later], frames);
|
|
648
|
+
if (!_rapierForeignOpen(frames)) { joined = later; break; }
|
|
649
|
+
}
|
|
650
|
+
if (joined < 0) { out.push(block); index++; continue; }
|
|
651
|
+
const start = Number(block._sourceStart), end = Number(blocks[joined]._sourceEnd);
|
|
652
|
+
const raw = Number.isFinite(start) && Number.isFinite(end) && start >= 0 && end >= start && end <= text.length
|
|
653
|
+
? text.slice(start, end)
|
|
654
|
+
: blocks.slice(index, joined + 1).map(row => String(row && row.raw || '')).join('\n\n');
|
|
655
|
+
out.push({...block, raw, _sourceEnd: Number.isFinite(end) ? end : block._sourceEnd, rendered: null});
|
|
656
|
+
index = joined + 1;
|
|
657
|
+
}
|
|
658
|
+
out._rapierFacts = Array.isArray(blocks && blocks._rapierFacts) ? blocks._rapierFacts.slice() : [];
|
|
659
|
+
return out;
|
|
660
|
+
}
|
|
661
|
+
function _rapierRenderSealedHtml(tokens, env) {
|
|
662
|
+
let html = '';
|
|
663
|
+
for (const range of _rapierForeignSealRanges(tokens)) {
|
|
664
|
+
let block = '';
|
|
665
|
+
for (let index = range[0]; index < range[1]; index++) block += range.hide && range.hide.has(index) ? (tokens[index].nesting < 0 ? '\n' : '') : _rapierRenderTokenHtml(tokens, index, env);
|
|
666
|
+
html += _rapierSealBlockHtml(block);
|
|
667
|
+
}
|
|
668
|
+
return html;
|
|
669
|
+
}
|
|
670
|
+
|
|
461
671
|
function _rapierRenderSemanticRoot(canonical, metadata, options = {}) {
|
|
462
672
|
const root = document.createElement('template').content.ownerDocument.createElement('div');
|
|
463
673
|
root.setAttribute('data-rapier-semantic-root', 'true');
|
|
@@ -476,24 +686,28 @@ function _rapierRenderSemanticRoot(canonical, metadata, options = {}) {
|
|
|
476
686
|
}
|
|
477
687
|
|
|
478
688
|
const markdown = _rapierSplitOpeningFrontmatter(canonical).body;
|
|
479
|
-
const env = {rapierImagePresentation: options.imagePresentation === true, ...(options.page ? {rapierPage: true} : {}), ...(options.providers === false ? {rapierProviders: false} : {})};
|
|
689
|
+
const env = {rapierImagePresentation: options.imagePresentation === true, rapierPassive: options.passive === true, ...(options.page ? {rapierPage: true} : {}), ...(options.providers === false ? {rapierProviders: false} : {})};
|
|
480
690
|
if (options.wikiEmbedding) env.rapierWikiEmbedding = true;
|
|
481
691
|
const wikiLinks = wikiMode(options);
|
|
482
692
|
if (wikiLinks) env.rapierWikiLinks = wikiLinks;
|
|
483
693
|
if (options.mathEquations) env.rapierMathEquations = options.mathEquations;
|
|
484
694
|
const nesting = md && options.maxNesting > 0 ? options.maxNesting : 0;
|
|
485
|
-
let cutAt = -1, rendered;
|
|
486
|
-
|
|
695
|
+
let cutAt = -1, rendered = '';
|
|
696
|
+
codeLeft = options.codeBudget >= 0 ? options.codeBudget : Infinity;
|
|
697
|
+
try {
|
|
698
|
+
if (!md) rendered = '<pre><code>' + escapeRapierHtmlText(markdown) + '</code></pre>';
|
|
699
|
+
else {
|
|
487
700
|
const saved = md.options.maxNesting;
|
|
488
701
|
if (nesting) md.options.maxNesting = nesting;
|
|
489
702
|
try {
|
|
490
|
-
|
|
703
|
+
let tokens = md.parse(markdown, env);
|
|
491
704
|
if (nesting) cutAt = _rapierNestingCutAt(tokens, nesting);
|
|
492
|
-
|
|
705
|
+
tokens = _rapierCloseOpenDetails(tokens);
|
|
706
|
+
rendered = _rapierRenderSealedHtml(tokens, env);
|
|
707
|
+
if (md.renderer.rapierTransformHtml) rendered = md.renderer.rapierTransformHtml(rendered);
|
|
493
708
|
} finally { md.options.maxNesting = saved; }
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
: '<pre><code>' + escapeRapierHtmlText(markdown) + '</code></pre>';
|
|
709
|
+
}
|
|
710
|
+
} finally { codeLeft = Infinity; }
|
|
497
711
|
if (md && env.footnotes && Array.isArray(env.footnotes.list) && env.footnotes.list.length) {
|
|
498
712
|
const labels = env.footnotes.list.map((item, index) =>
|
|
499
713
|
String(item && item.label || ('inline-' + (index + 1))));
|
|
@@ -503,14 +717,14 @@ function _rapierRenderSemanticRoot(canonical, metadata, options = {}) {
|
|
|
503
717
|
if (cutAt >= 0) _rapierAppendNestingCut(root, markdown, cutAt);
|
|
504
718
|
_rapierApplyBlockDirection(root);
|
|
505
719
|
|
|
506
|
-
_rapierAssignHeadingSlugs(root, RAPIER_RENDERED_HEADING_SELECTOR, false);
|
|
720
|
+
_rapierAssignHeadingSlugs(root, RAPIER_RENDERED_HEADING_SELECTOR, false, options.carry?.slugs, options.carry?.headingIds);
|
|
507
721
|
_rapierDisambiguateRenderedAnchors(root);
|
|
508
722
|
|
|
509
723
|
root.querySelectorAll('pre > code').forEach(_rapierNormalizeCodeElement);
|
|
510
|
-
_rapierMarkTableCaptions(root);
|
|
724
|
+
_rapierMarkTableCaptions(root, options.carry);
|
|
511
725
|
_rapierMarkFigureCaptions(root);
|
|
512
726
|
_rapierMarkListContinuations(_rapierChildElements(root));
|
|
513
|
-
_rapierDecorateJumpLists(root);
|
|
727
|
+
_rapierDecorateJumpLists(root, options.carry);
|
|
514
728
|
return root;
|
|
515
729
|
}
|
|
516
730
|
|
|
@@ -543,12 +757,13 @@ async function _rapierRenderSemanticRootAsync(canonical, metadata, options = {})
|
|
|
543
757
|
let {tokens, env} = parsed, labels = env.footnotes?.list?.map((item, index) => String(item?.label || ('inline-' + (index + 1))));
|
|
544
758
|
const cutAt = nesting ? _rapierNestingCutAt(tokens, nesting) : -1;
|
|
545
759
|
tokens = _rapierCloseOpenDetails(tokens);
|
|
546
|
-
env = {...env, rapierImagePresentation: options.imagePresentation === true};
|
|
760
|
+
env = {...env, rapierImagePresentation: options.imagePresentation === true, rapierPassive: options.passive === true};
|
|
547
761
|
await pause(work, .3);
|
|
548
762
|
const inert = document.createElement('template').content.ownerDocument;
|
|
549
763
|
const root = inert.createElement('div'), part = inert.createElement('div'), boundary = htmlBoundary();
|
|
550
764
|
root.setAttribute('data-rapier-semantic-root', 'true');
|
|
551
765
|
let html = '', began = performance.now(), complete = false;
|
|
766
|
+
codeLeft = options.codeBudget >= 0 ? options.codeBudget : Infinity;
|
|
552
767
|
const append = () => {
|
|
553
768
|
if (md.renderer.rapierTransformHtml) html = md.renderer.rapierTransformHtml(html);
|
|
554
769
|
if (labels?.length) html = _relabelFootnoteHtml(html, labels);
|
|
@@ -556,37 +771,90 @@ async function _rapierRenderSemanticRootAsync(canonical, metadata, options = {})
|
|
|
556
771
|
while (part.firstChild) root.appendChild(part.firstChild);
|
|
557
772
|
html = '';
|
|
558
773
|
};
|
|
774
|
+
const finishBlock = block => {
|
|
775
|
+
const sealed = _rapierSealBlockHtml(block);
|
|
776
|
+
html += sealed;
|
|
777
|
+
if (boundary(sealed) && html.length >= 16384) append();
|
|
778
|
+
};
|
|
559
779
|
try {
|
|
560
|
-
for (
|
|
561
|
-
|
|
562
|
-
let
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
began = performance.now();
|
|
780
|
+
for (const range of _rapierForeignSealRanges(tokens)) {
|
|
781
|
+
let block = '';
|
|
782
|
+
for (let index = range[0]; index < range[1]; index++) {
|
|
783
|
+
block += range.hide && range.hide.has(index) ? (tokens[index].nesting < 0 ? '\n' : '') : _rapierRenderTokenHtml(tokens, index, env);
|
|
784
|
+
if (performance.now() - began >= 8) {
|
|
785
|
+
await pause(work, .3 + .2 * (index + 1) / tokens.length);
|
|
786
|
+
began = performance.now();
|
|
787
|
+
}
|
|
569
788
|
}
|
|
789
|
+
finishBlock(block);
|
|
570
790
|
}
|
|
571
791
|
if (html) append();
|
|
572
792
|
if (cutAt >= 0) _rapierAppendNestingCut(root, markdown, cutAt);
|
|
573
793
|
parsed = tokens = env = labels = null;
|
|
574
|
-
await finishAsync(_rapierSemanticDecorations(root), work);
|
|
794
|
+
await finishAsync(_rapierSemanticDecorations(root, options.carry), work);
|
|
575
795
|
await pause(work, .6);
|
|
576
796
|
complete = true;
|
|
577
797
|
return root;
|
|
578
|
-
} finally { if (!complete) { root.replaceChildren(); part.replaceChildren(); } }
|
|
798
|
+
} finally { codeLeft = Infinity; if (!complete) { root.replaceChildren(); part.replaceChildren(); } }
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function _rapierPartDecorationGroups(tokens) {
|
|
802
|
+
const groups = [];
|
|
803
|
+
for (let at = 0; at < tokens.length; at++) {
|
|
804
|
+
const first = tokens[at];
|
|
805
|
+
if (first.type !== 'heading_open' && first.type !== 'table_open') continue;
|
|
806
|
+
const close = first.type === 'heading_open' ? 'heading_close' : 'table_close';
|
|
807
|
+
let end = at + 1;
|
|
808
|
+
while (end < tokens.length && !(tokens[end].type === close && tokens[end].level === first.level)) end++;
|
|
809
|
+
end++;
|
|
810
|
+
if (first.type === 'table_open' && tokens[end]?.type === 'paragraph_open' && tokens[end].level === first.level) {
|
|
811
|
+
while (end < tokens.length && !(tokens[end].type === 'paragraph_close' && tokens[end].level === first.level)) end++;
|
|
812
|
+
end++;
|
|
813
|
+
}
|
|
814
|
+
groups.push(tokens.slice(at, end));
|
|
815
|
+
at = end - 1;
|
|
816
|
+
}
|
|
817
|
+
return groups;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function _rapierReadPartDecorations(canonical, metadata, options = {}) {
|
|
821
|
+
const carry = options.carry || {slugs: Object.create(null), captions: 0, continued: true}, captionStart = carry.captions || 0;
|
|
822
|
+
const markdown = _rapierSplitOpeningFrontmatter(canonical).body, env = {rapierImagePresentation: options.imagePresentation === true, rapierPassive: true, rapierPartDecorations: true,
|
|
823
|
+
...(options.page ? {rapierPage: true} : {}), ...(options.providers === false ? {rapierProviders: false} : {})};
|
|
824
|
+
if (options.wikiEmbedding) env.rapierWikiEmbedding = true;
|
|
825
|
+
const wikiLinks = wikiMode(options);
|
|
826
|
+
if (wikiLinks) env.rapierWikiLinks = wikiLinks;
|
|
827
|
+
if (options.mathEquations) env.rapierMathEquations = options.mathEquations;
|
|
828
|
+
const saved = md.options.maxNesting;
|
|
829
|
+
let tokens;
|
|
830
|
+
try {
|
|
831
|
+
if (options.maxNesting > 0) md.options.maxNesting = options.maxNesting;
|
|
832
|
+
tokens = md.parse(markdown, env);
|
|
833
|
+
} finally { md.options.maxNesting = saved; }
|
|
834
|
+
if (tokens.some(token => token.type === 'html_block' || token.type === 'math_block' || token.type.startsWith('footnote_') ||
|
|
835
|
+
token.type === 'inline' && token.children?.some(child => child.type === 'html_inline' || child.type === 'math_inline' || child.type.startsWith('footnote_')))) {
|
|
836
|
+
const root = _rapierRenderSemanticRoot(canonical, metadata, {...options, carry, codeBudget: 0, passive: true});
|
|
837
|
+
return Object.freeze({headingIds: Object.freeze([...root.querySelectorAll(RAPIER_RENDERED_HEADING_SELECTOR)].map(heading => heading.id)), captionStart});
|
|
838
|
+
}
|
|
839
|
+
const html = [];
|
|
840
|
+
for (const group of _rapierPartDecorationGroups(tokens)) html.push('<div>', md.renderer.render(group, md.options, env), '</div>');
|
|
841
|
+
const root = document.createElement('template').content.ownerDocument.createElement('div');
|
|
842
|
+
root.innerHTML = sanitizeRapierHtml(html.join(''), 'export');
|
|
843
|
+
_rapierAssignHeadingSlugs(root, RAPIER_RENDERED_HEADING_SELECTOR, false, carry.slugs);
|
|
844
|
+
const headingIds = Object.freeze([...root.querySelectorAll(RAPIER_RENDERED_HEADING_SELECTOR)].map(heading => heading.id));
|
|
845
|
+
_rapierMarkTableCaptions(root, carry);
|
|
846
|
+
return Object.freeze({headingIds, captionStart});
|
|
579
847
|
}
|
|
580
848
|
|
|
581
|
-
function* _rapierSemanticDecorations(root) {
|
|
849
|
+
function* _rapierSemanticDecorations(root, carry = null) {
|
|
582
850
|
yield* _rapierApplyBlockDirectionSteps(root); yield;
|
|
583
|
-
yield* _rapierAssignHeadingSlugsSteps(root, RAPIER_RENDERED_HEADING_SELECTOR, false); yield;
|
|
851
|
+
yield* _rapierAssignHeadingSlugsSteps(root, RAPIER_RENDERED_HEADING_SELECTOR, false, carry?.slugs, carry?.headingIds); yield;
|
|
584
852
|
yield* _rapierDisambiguateRenderedAnchorsSteps(root); yield;
|
|
585
853
|
for (const code of root.querySelectorAll('pre > code')) { _rapierNormalizeCodeElement(code); yield; }
|
|
586
|
-
yield* _rapierMarkTableCaptionsSteps(root); yield;
|
|
854
|
+
yield* _rapierMarkTableCaptionsSteps(root, carry); yield;
|
|
587
855
|
yield* _rapierMarkFigureCaptionsSteps(root); yield;
|
|
588
856
|
yield* _rapierMarkListContinuationsSteps(_rapierChildElements(root)); yield;
|
|
589
|
-
yield* _rapierDecorateJumpListsSteps(root); yield;
|
|
857
|
+
yield* _rapierDecorateJumpListsSteps(root, carry); yield;
|
|
590
858
|
}
|
|
591
859
|
|
|
592
860
|
function _rapierInstallSemanticProbe(instance) {
|
|
@@ -931,17 +1199,23 @@ function _rapierFirstStrongDir(text) {
|
|
|
931
1199
|
|
|
932
1200
|
const _RAPIER_DIR_BLOCKS = 'p,h1,h2,h3,h4,h5,h6,li,blockquote,ul,ol,dt,dd,td,th';
|
|
933
1201
|
|
|
934
|
-
function _rapierAssignHeadingSlugs(root, selector, reserveExisting) { return finish(_rapierAssignHeadingSlugsSteps(root, selector, reserveExisting)); }
|
|
1202
|
+
function _rapierAssignHeadingSlugs(root, selector, reserveExisting, taken, assigned) { return finish(_rapierAssignHeadingSlugsSteps(root, selector, reserveExisting, taken, assigned)); }
|
|
935
1203
|
|
|
936
|
-
function* _rapierAssignHeadingSlugsSteps(root, selector = RAPIER_RENDERED_HEADING_SELECTOR, reserveExisting = true) {
|
|
1204
|
+
function* _rapierAssignHeadingSlugsSteps(root, selector = RAPIER_RENDERED_HEADING_SELECTOR, reserveExisting = true, taken = null, assigned = null) {
|
|
937
1205
|
if (!root || !root.querySelectorAll) return;
|
|
938
|
-
const used = Object.create(null);
|
|
1206
|
+
const used = taken || Object.create(null);
|
|
939
1207
|
const headings = _rapierDormantHeadings(root, selector, true);
|
|
1208
|
+
if (assigned && assigned.length !== headings.length) {
|
|
1209
|
+
try { console.warn('[rapier-reader] Part heading facts do not match its rendered headings; assigning ordinary heading IDs.'); } catch (_) {}
|
|
1210
|
+
assigned = null;
|
|
1211
|
+
}
|
|
940
1212
|
const headingSet = new Set(headings);
|
|
941
1213
|
if (reserveExisting) for (const element of _rapierDormantHeadings(root.isConnected ? document : root, '[id]', true)) { yield;
|
|
942
1214
|
if (!headingSet.has(element) && element.id) used[element.id] = 0;
|
|
943
1215
|
}
|
|
1216
|
+
let index = 0;
|
|
944
1217
|
for (const heading of headings) { yield;
|
|
1218
|
+
if (assigned) { heading.id = assigned[index++]; continue; }
|
|
945
1219
|
const base = _rapierHeadingSlugBase(heading.textContent);
|
|
946
1220
|
const owned = typeof _rapierChromeOwnsId === 'function' && _rapierChromeOwnsId(base);
|
|
947
1221
|
heading.id = _rapierNextHeadingSlug(owned ? 'heading-' + base : base, used);
|
|
@@ -1042,9 +1316,9 @@ function _rapierDecodeHash(hash) {
|
|
|
1042
1316
|
catch (_) { return raw; }
|
|
1043
1317
|
}
|
|
1044
1318
|
|
|
1045
|
-
function _rapierDecorateJumpLists(root) { return finish(_rapierDecorateJumpListsSteps(root)); }
|
|
1319
|
+
function _rapierDecorateJumpLists(root, carry) { return finish(_rapierDecorateJumpListsSteps(root, carry)); }
|
|
1046
1320
|
|
|
1047
|
-
function* _rapierDecorateJumpListsSteps(root) {
|
|
1321
|
+
function* _rapierDecorateJumpListsSteps(root, carry = null) {
|
|
1048
1322
|
for (const list of root.querySelectorAll('ul')) { yield;
|
|
1049
1323
|
if (list.closest('li')) continue;
|
|
1050
1324
|
const items = Array.from(list.children).filter(item => item.tagName === 'LI');
|
|
@@ -1067,7 +1341,7 @@ function* _rapierDecorateJumpListsSteps(root) {
|
|
|
1067
1341
|
}
|
|
1068
1342
|
}
|
|
1069
1343
|
|
|
1070
|
-
const first = root.firstElementChild, only = first && !first.nextElementSibling ? first : null;
|
|
1344
|
+
const first = root.firstElementChild, only = !carry && first && !first.nextElementSibling ? first : null;
|
|
1071
1345
|
if (only && only.tagName === 'P' && /^(?:jump\s+to|contents|table\s+of\s+contents):?$/i.test(String(only.textContent || '').trim())) {
|
|
1072
1346
|
only.classList.add('rapier-jump-label-candidate');
|
|
1073
1347
|
}
|
|
@@ -1109,11 +1383,11 @@ function* _rapierMarkListContinuationsSteps(blocks, mark = (element, name) => el
|
|
|
1109
1383
|
}
|
|
1110
1384
|
}
|
|
1111
1385
|
|
|
1112
|
-
function _rapierMarkTableCaptions(root) { return finish(_rapierMarkTableCaptionsSteps(root)); }
|
|
1386
|
+
function _rapierMarkTableCaptions(root, carry) { return finish(_rapierMarkTableCaptionsSteps(root, carry)); }
|
|
1113
1387
|
|
|
1114
|
-
function* _rapierMarkTableCaptionsSteps(root) {
|
|
1388
|
+
function* _rapierMarkTableCaptionsSteps(root, carry = null) {
|
|
1115
1389
|
const used = new Set(Array.from(root.querySelectorAll('[id]'), element => element.id));
|
|
1116
|
-
let ordinal = 0;
|
|
1390
|
+
let ordinal = carry?.captions || 0;
|
|
1117
1391
|
for (const table of root.querySelectorAll('table')) { yield;
|
|
1118
1392
|
const sibling = table.nextElementSibling;
|
|
1119
1393
|
if (!sibling || sibling.tagName !== 'P') continue;
|
|
@@ -1126,6 +1400,7 @@ function* _rapierMarkTableCaptionsSteps(root) {
|
|
|
1126
1400
|
const existing = (table.getAttribute('aria-describedby') || '').trim();
|
|
1127
1401
|
table.setAttribute('aria-describedby', existing ? existing + ' ' + id : id);
|
|
1128
1402
|
}
|
|
1403
|
+
if (carry) carry.captions = ordinal;
|
|
1129
1404
|
}
|
|
1130
1405
|
|
|
1131
1406
|
|
|
@@ -1829,7 +2104,7 @@ function renderWithMathML(source, metadata = {}) {
|
|
|
1829
2104
|
return {html, equations};
|
|
1830
2105
|
}
|
|
1831
2106
|
|
|
1832
|
-
return {renderWithMathML, _rapierClipboardPayloadAsync, _rapierPlainTextFileAsync, _rapierCloneRootAsync, _rapierPortablePlainTextAsync, _rapierHeldPicturesAsWordsAsync, _rapierRenderSemanticRootAsync, _rapierProjectPortableRootAsync, _rapierPortableHtmlAsync, _rapierCalloutInfo, _rapierRemoveCalloutMarker, _rapierMathSource, _rapierFlattenPortableDetails, _rapierProjectPortableRoot, _rapierPortableHtml, _rapierNormalizeInlineText, _rapierPortableInlineText, _rapierPortableListText, _rapierPortableTableText, _rapierPortablePlainText, _rapierPlainTextFile, _rapierHeldPicturesAsWords, _rapierSourceTokenValue, _rapierResolveSoftBreakTokens, _rapierInertParse, _rapierUnwrapElement, _rapierBidiStrong, render: (source, metadata = {}) => { if (!md) initMarkdownIt(); return _rapierRenderSemanticRoot(source, metadata).innerHTML; }, initMarkdownIt, _rapierRenderSemanticRoot, _rapierInstallSemanticProbe, _rapierApplyImageGeometry, _rapierImageAltSize, _rapierImageAltSourceParts, _rapierImageAltText, _rapierImageSizeAttributes, _rapierRawHtmlFragment, _rapierApplyBlockDirection, _rapierFirstStrongDir, _rapierAssignHeadingSlugs, _rapierDisambiguateRenderedAnchors, _rapierDecodeHash, _rapierDecorateJumpLists, _rapierMarkFigureCaptions, _rapierMarkListContinuations, _rapierMarkTableCaptions, _rapierNormalizeCodeElement, _rapierLanguageClass, _relabelFootnoteHtml, _footnoteIdFromLabel, wrapDisplayMath, parser: () => md};
|
|
2107
|
+
return {_rapierReadPartDecorations, renderWithMathML, _rapierClipboardPayloadAsync, _rapierPlainTextFileAsync, _rapierCloneRootAsync, _rapierPortablePlainTextAsync, _rapierHeldPicturesAsWordsAsync, _rapierRenderSemanticRootAsync, _rapierProjectPortableRootAsync, _rapierPortableHtmlAsync, _rapierCalloutInfo, _rapierRemoveCalloutMarker, _rapierMathSource, _rapierFlattenPortableDetails, _rapierProjectPortableRoot, _rapierPortableHtml, _rapierNormalizeInlineText, _rapierPortableInlineText, _rapierPortableListText, _rapierPortableTableText, _rapierPortablePlainText, _rapierPlainTextFile, _rapierHeldPicturesAsWords, _rapierSourceTokenValue, _rapierResolveSoftBreakTokens, _rapierInertParse, _rapierUnwrapElement, _rapierBidiStrong, _rapierSealBlockHtml, _rapierMergeForeignBlocks, render: (source, metadata = {}) => { if (!md) initMarkdownIt(); return _rapierRenderSemanticRoot(source, metadata).innerHTML; }, initMarkdownIt, _rapierRenderSemanticRoot, _rapierInstallSemanticProbe, _rapierApplyImageGeometry, _rapierImageAltSize, _rapierImageAltSourceParts, _rapierImageAltText, _rapierImageSizeAttributes, _rapierRawHtmlFragment, _rapierApplyBlockDirection, _rapierFirstStrongDir, _rapierAssignHeadingSlugs, _rapierDisambiguateRenderedAnchors, _rapierDecodeHash, _rapierDecorateJumpLists, _rapierMarkFigureCaptions, _rapierMarkListContinuations, _rapierMarkTableCaptions, _rapierNormalizeCodeElement, _rapierLanguageClass, _relabelFootnoteHtml, _footnoteIdFromLabel, wrapDisplayMath, parser: () => md};
|
|
1833
2108
|
}
|
|
1834
2109
|
export {RAPIER_TABLE_CAPTION_PREFIX_RE as tableCaptionPrefix, RAPIER_PORTABLE_HIGHLIGHT_HEX as portableHighlightHex, _RAPIER_RTL_SCRIPT as rtlScripts, createMarkdownRenderer};
|
|
1835
2110
|
|
|
@@ -69,7 +69,8 @@ function cleanDocumentStyle(tag, value, context, classes = '') {
|
|
|
69
69
|
const property = part.slice(0, colon).trim().toLowerCase(), body = part.slice(colon + 1).trim();
|
|
70
70
|
const diagramProperty = diagram && /^--(?:_[a-z0-9_-]+|pele-[a-z0-9-]+)$/.test(property);
|
|
71
71
|
if (!DOCUMENT_STYLE_PROPERTIES.has(property) && !/^--md-[a-z0-9-]+$/.test(property) && !diagramProperty && !(diagram && property === 'font')) return;
|
|
72
|
-
if (!body || /[
|
|
72
|
+
if (!body || /[\u0000-\u0008\u000b\u000e-\u001f{}@]|\/\*|\*\//.test(body) ||
|
|
73
|
+
/["'\\]/.test(body.replace(/"(?:[^"\\\n\r\f]|\\["\\])*"|'(?:[^'\\\n\r\f]|\\['\\])*'/g, ''))) return;
|
|
73
74
|
const withoutLocal = body.replace(/\burl\(\s*(['"]?)#[a-z0-9_.:-]+\1\s*\)/gi, '');
|
|
74
75
|
if (/(?:url|image|image-set|-webkit-image-set|element|paint|attr|expression)\s*\(/i.test(withoutLocal)) return;
|
|
75
76
|
kept.push(part.trim());
|
|
@@ -304,6 +305,31 @@ function _rapierInstallSanitizeHooks() {
|
|
|
304
305
|
if (level) node.setAttribute('data-rapier-word-level', String(level));
|
|
305
306
|
else if (node.nodeName === 'SPAN' && wordListIsMarker(style)) node.setAttribute('data-rapier-word-marker', '1');
|
|
306
307
|
});
|
|
308
|
+
DOMPurify.addHook('uponSanitizeElement', node => {
|
|
309
|
+
if (_rapierSanitizeRuntime.context !== 'paste' || !node || node.nodeName !== 'TABLE') return;
|
|
310
|
+
node.removeAttribute('data-rapier-paste-word-header');
|
|
311
|
+
try {
|
|
312
|
+
const own = (node.getAttribute('style') || '') + ' ' + (node.getAttribute('class') || '');
|
|
313
|
+
const word = /mso-yfti-|MsoTable/i.test(own) || !!node.querySelector('[style*="mso-"],[class*="Mso"]');
|
|
314
|
+
if (!word || node.tHead || node.querySelector('th')) return;
|
|
315
|
+
const row = Array.from(node.querySelectorAll('tr')).find(candidate => candidate.closest('table') === node);
|
|
316
|
+
if (!row) return;
|
|
317
|
+
const cells = Array.from(row.children).filter(cell => cell.nodeName === 'TD' || cell.nodeName === 'TH');
|
|
318
|
+
if (!cells.length) return;
|
|
319
|
+
let bold = false;
|
|
320
|
+
for (const cell of cells) {
|
|
321
|
+
const walker = node.ownerDocument.createTreeWalker(cell, NodeFilter.SHOW_TEXT);
|
|
322
|
+
for (let text = walker.nextNode(); text; text = walker.nextNode()) {
|
|
323
|
+
if (!/\S/.test(text.nodeValue || '')) continue;
|
|
324
|
+
const parent = text.parentElement;
|
|
325
|
+
const style = parent?.getAttribute?.('style') || '';
|
|
326
|
+
if (!(parent && (parent.closest('b,strong') || /font-weight\s*:\s*(?:bold|[6-9]00|1000)\b/i.test(style)))) return;
|
|
327
|
+
bold = true;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (bold) node.setAttribute('data-rapier-paste-word-header', '');
|
|
331
|
+
} catch (_) {}
|
|
332
|
+
});
|
|
307
333
|
}
|
|
308
334
|
|
|
309
335
|
function _rapierInstallDocumentSanitizeHooks() {
|
|
@@ -414,9 +440,17 @@ function sanitize(value, context, fragment) {
|
|
|
414
440
|
if (purifyConfigured.get(DOMPurify) !== options) { DOMPurify.setConfig(options); purifyConfigured.set(DOMPurify, options); }
|
|
415
441
|
const previous = _rapierSanitizeRuntime.context;
|
|
416
442
|
_rapierSanitizeRuntime.context = selected;
|
|
443
|
+
ensureScratchParseHook();
|
|
444
|
+
const scratch = [];
|
|
445
|
+
const outerSink = scratchSink;
|
|
446
|
+
scratchSink = scratch;
|
|
447
|
+
let result;
|
|
417
448
|
try {
|
|
418
|
-
|
|
449
|
+
result = DOMPurify.sanitize(value == null ? '' : String(value));
|
|
450
|
+
return result;
|
|
419
451
|
} finally {
|
|
452
|
+
scratchSink = outerSink;
|
|
453
|
+
releaseScratchMedia(scratch, result);
|
|
420
454
|
if (labels) {
|
|
421
455
|
DOMPurify.removeHook('uponSanitizeElement', diagramLabelElement);
|
|
422
456
|
DOMPurify.removeHook('uponSanitizeAttribute', diagramLabelAttribute);
|
|
@@ -426,6 +460,37 @@ function sanitize(value, context, fragment) {
|
|
|
426
460
|
}
|
|
427
461
|
}
|
|
428
462
|
|
|
463
|
+
let scratchSink = null;
|
|
464
|
+
function ensureScratchParseHook() {
|
|
465
|
+
if (typeof DOMParser !== 'function' || DOMParser.prototype.parseFromString._rapierScratch) return;
|
|
466
|
+
const original = DOMParser.prototype.parseFromString;
|
|
467
|
+
function wrapped(source, type) {
|
|
468
|
+
const doc = original.call(this, source, type);
|
|
469
|
+
scratchSink?.push(doc);
|
|
470
|
+
return doc;
|
|
471
|
+
}
|
|
472
|
+
wrapped._rapierScratch = true;
|
|
473
|
+
DOMParser.prototype.parseFromString = wrapped;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function releaseScratchMedia(docs, result) {
|
|
477
|
+
const kept = result && typeof result === 'object' ? result.nodeType === 9 ? result : result.ownerDocument : null;
|
|
478
|
+
for (const doc of docs) {
|
|
479
|
+
if (!doc || doc === kept || !doc.querySelectorAll) continue;
|
|
480
|
+
for (const el of [...doc.querySelectorAll('video, audio')]) releaseMediaElement(el);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
function releaseMediaElement(el) {
|
|
484
|
+
if (!el || (el.nodeName !== 'VIDEO' && el.nodeName !== 'AUDIO')) return;
|
|
485
|
+
try {
|
|
486
|
+
el.pause();
|
|
487
|
+
el.removeAttribute('src');
|
|
488
|
+
for (const source of el.querySelectorAll('source')) source.removeAttribute('src');
|
|
489
|
+
el.load();
|
|
490
|
+
} catch (_) {}
|
|
491
|
+
el.remove();
|
|
492
|
+
}
|
|
493
|
+
|
|
429
494
|
function escapeRapierHtmlText(value) {
|
|
430
495
|
return String(value == null ? '' : value)
|
|
431
496
|
.replace(/&/g, '&')
|
package/dist/kit/render.mjs
CHANGED
|
@@ -289,15 +289,21 @@ function* _rapierProjectStyledRootSteps(semanticRoot, options) {
|
|
|
289
289
|
if (code) {
|
|
290
290
|
const lang = _rapierLanguageClass(code) || String(metadata.codeLang || '');
|
|
291
291
|
code.classList.add('artifact-code');
|
|
292
|
-
if (metadata.docKind === 'code')
|
|
292
|
+
if (metadata.docKind === 'code') {
|
|
293
|
+
const colored = _rapierArtifactHighlight(code.textContent || '', lang);
|
|
294
|
+
_rapierPaintCode(code, opts.sanitized ? sanitizeRapierHtml(colored, 'export') : colored);
|
|
295
|
+
}
|
|
293
296
|
if (lang) code.classList.add('language-' + String(lang).replace(/[^a-z0-9_-]/gi, ''));
|
|
294
297
|
}
|
|
295
298
|
} else {
|
|
299
|
+
let codeLeft = opts.codeBudget >= 0 ? opts.codeBudget : Infinity;
|
|
296
300
|
for (const code of root.querySelectorAll('pre > code')) { yield;
|
|
297
301
|
if (code.parentElement?.classList.contains('diagram-source') &&
|
|
298
302
|
code.closest('.diagram-block')?.getAttribute('data-diagram-state') === 'ready') continue;
|
|
299
303
|
const lang = _rapierLanguageClass(code) || 'text';
|
|
300
|
-
|
|
304
|
+
if ((codeLeft -= code.textContent.length) < 0) { code.replaceChildren(document.createTextNode(code.textContent)); continue; }
|
|
305
|
+
const colored = _rapierArtifactHighlight(code.textContent || '', lang);
|
|
306
|
+
_rapierPaintCode(code, opts.sanitized ? sanitizeRapierHtml(colored, 'export') : colored);
|
|
301
307
|
}
|
|
302
308
|
|
|
303
309
|
for (const table of root.querySelectorAll('table')) { yield;
|
|
@@ -336,6 +342,13 @@ function* _rapierProjectStyledRootSteps(semanticRoot, options) {
|
|
|
336
342
|
|
|
337
343
|
yield* _rapierPrefixPortableAnchorsSteps(root, opts.baseName || metadata.filename || 'document');
|
|
338
344
|
|
|
345
|
+
if (opts.sanitized) {
|
|
346
|
+
for (const cache of root.querySelectorAll('.diagram-cache')) {
|
|
347
|
+
yield;
|
|
348
|
+
cache.innerHTML = sanitizeRapierHtml(cache.innerHTML, 'export');
|
|
349
|
+
}
|
|
350
|
+
return root;
|
|
351
|
+
}
|
|
339
352
|
return yield* cleanTree(root, sanitizeRapierHtml, 'export');
|
|
340
353
|
}
|
|
341
354
|
|
|
@@ -712,7 +725,7 @@ function* _rapierSharedPageLayoutSteps(root) {
|
|
|
712
725
|
for (const image of root.querySelectorAll('img[data-rapier-image-layout]')) {
|
|
713
726
|
yield;
|
|
714
727
|
const layout = globalThis.RapierMarkdownLayout.parseLayoutAttribute(image.getAttribute('data-rapier-image-layout'));
|
|
715
|
-
if (layout?.wrap !== 'around' && layout?.wrap !== 'box') continue;
|
|
728
|
+
if (layout?.wrap !== 'around' && layout?.wrap !== 'beside' && layout?.wrap !== 'box') continue;
|
|
716
729
|
const paragraph = _rapierSharePictureParagraph(image);
|
|
717
730
|
if (!paragraph) continue;
|
|
718
731
|
const owner = globalThis.RapierMarkdownLayout.wrapNeighbour(paragraph, _rapierShareWrapKind);
|
|
@@ -1445,6 +1458,8 @@ function _rapierProjectArtifactLayout(root, metadata, geometry, preparation) {
|
|
|
1445
1458
|
if (layout.wrap === 'box') {
|
|
1446
1459
|
value = boxProfile(image);
|
|
1447
1460
|
if (!value && rotateRad) value = geometry.rasterTiltProfile(image.naturalWidth, image.naturalHeight, rotateRad);
|
|
1461
|
+
} else if (layout.wrap === 'beside') {
|
|
1462
|
+
value = rotateRad ? geometry.rasterTiltProfile(image.naturalWidth, image.naturalHeight, rotateRad) : null;
|
|
1448
1463
|
} else {
|
|
1449
1464
|
const occupancy = typeof geometry.parseProfile === 'function' && geometry.parseProfile(image.getAttribute('data-rapier-occupancy'));
|
|
1450
1465
|
value = occupancy || geometry.alphaProfile(image);
|
|
@@ -1468,7 +1483,7 @@ function _rapierProjectArtifactLayout(root, metadata, geometry, preparation) {
|
|
|
1468
1483
|
for (const image of root.querySelectorAll('img[data-rapier-image-layout]')) {
|
|
1469
1484
|
if (exclude.has(image) || !image.complete || !image.naturalWidth || !image.naturalHeight) continue;
|
|
1470
1485
|
const layout = metadata.parseLayoutAttribute(image.getAttribute('data-rapier-image-layout'));
|
|
1471
|
-
if (!layout?.rotate || ['around', 'box', 'behind', 'front'].includes(layout.wrap)) continue;
|
|
1486
|
+
if (!layout?.rotate || ['around', 'beside', 'box', 'behind', 'front'].includes(layout.wrap)) continue;
|
|
1472
1487
|
const width = image.offsetWidth, height = image.offsetHeight;
|
|
1473
1488
|
if (!(width > 0 && height > 0)) continue;
|
|
1474
1489
|
const paragraph = image.closest('p');
|
|
@@ -1606,7 +1621,7 @@ function _rapierProjectArtifactLayout(root, metadata, geometry, preparation) {
|
|
|
1606
1621
|
const origin = box(root).top, obstacles = [], anchors = new Map(), wrapped = new Set(), placed = [], positionedImages = new Set();
|
|
1607
1622
|
for (const element of children) {
|
|
1608
1623
|
const layout = metadata.parseLayoutAttribute(element.getAttribute('data-md-layout'));
|
|
1609
|
-
const image = ['around', 'box', 'behind', 'front'].includes(layout?.wrap) && element.tagName === 'P'
|
|
1624
|
+
const image = ['around', 'beside', 'box', 'behind', 'front'].includes(layout?.wrap) && element.tagName === 'P'
|
|
1610
1625
|
? element.querySelector('img[data-rapier-image-layout]') : null;
|
|
1611
1626
|
if (!image?.complete || !image.naturalWidth || !image.naturalHeight || !imageOnly(element, image)) continue;
|
|
1612
1627
|
|
|
@@ -1652,7 +1667,9 @@ function _rapierProjectArtifactLayout(root, metadata, geometry, preparation) {
|
|
|
1652
1667
|
obstacle.y + obstacle.height > y - room && obstacle.y < y + rectangle.height + room)
|
|
1653
1668
|
y = obstacle.y + obstacle.height + room;
|
|
1654
1669
|
}
|
|
1655
|
-
|
|
1670
|
+
let slices = geometry.pictureSlices(profile(image, layout), left, y, rectangle.width, rectangle.height, scale);
|
|
1671
|
+
if (layout.wrap === 'beside') slices = geometry.besideSlices(slices, bounds.left + inset, bounds.left + inset + width, left, rectangle.width);
|
|
1672
|
+
obstacles.push(...geometry.linesSlices(slices, layout, lines, y, rectangle.height));
|
|
1656
1673
|
}
|
|
1657
1674
|
placed.push({source, image, rectangle, left, y, wrap: layout.wrap,
|
|
1658
1675
|
visualLeft: left + visualDeltaX, visualTop: y + visualDeltaY, visualWidth: fit.fit.width, visualHeight: fit.fit.height,
|
|
@@ -1733,7 +1750,7 @@ function _rapierArtifactLayoutScript(root, nonce = '', {pictures = true} = {}) {
|
|
|
1733
1750
|
const dependencies = globalThis.RapierArtifactLayoutDependencies;
|
|
1734
1751
|
const layoutOf = element => globalThis.RapierMarkdownLayout.parseLayoutAttribute(element.getAttribute('data-md-layout'));
|
|
1735
1752
|
const pictureLayoutOf = image => globalThis.RapierMarkdownLayout.parseLayoutAttribute(image.getAttribute('data-rapier-image-layout'));
|
|
1736
|
-
const wrapping = pictures && ([...root.querySelectorAll('p[data-md-layout]')].some(element => ['around', 'box', 'behind', 'front'].includes(layoutOf(element)?.wrap)) ||
|
|
1753
|
+
const wrapping = pictures && ([...root.querySelectorAll('p[data-md-layout]')].some(element => ['around', 'beside', 'box', 'behind', 'front'].includes(layoutOf(element)?.wrap)) ||
|
|
1737
1754
|
[...root.querySelectorAll('img[data-rapier-image-layout]')].some(image => pictureLayoutOf(image)?.rotate));
|
|
1738
1755
|
const typography = _rapierArtifactTypographyScript(root);
|
|
1739
1756
|
if (!wrapping && !typography) return '';
|
package/dist/layout/model.mjs
CHANGED
|
@@ -309,6 +309,19 @@ export function pictureSlices(profile, x, y, width, height, scale = 1) {
|
|
|
309
309
|
return slices;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
export function besideSlices(slices, columnLeft, columnRight, pictureLeft, pictureWidth) {
|
|
313
|
+
if (!Array.isArray(slices) || !(columnRight > columnLeft) || !(pictureWidth > 0) || !finite(pictureLeft)) return slices;
|
|
314
|
+
const blockLeft = pictureLeft + pictureWidth / 2 <= (columnLeft + columnRight) / 2;
|
|
315
|
+
return slices.map(slice => {
|
|
316
|
+
if (!slice || !finite(slice.x) || !finite(slice.width)) return slice;
|
|
317
|
+
if (blockLeft) {
|
|
318
|
+
const right = slice.x + slice.width;
|
|
319
|
+
return {...slice, x: columnLeft, width: Math.max(0, right - columnLeft)};
|
|
320
|
+
}
|
|
321
|
+
return {...slice, width: Math.max(0, columnRight - slice.x)};
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
312
325
|
export {slotSequence, columnsFilled};
|
|
313
326
|
export function slotsForBand(width, obstacles, top, height, minWidth = 40) {
|
|
314
327
|
if (!finite(width) || width <= 0 || !finite(top) || !finite(height) || height <= 0 ||
|
package/dist/spec/md-assets.mjs
CHANGED
|
@@ -100,7 +100,7 @@ export function* blockWindows(source, bodyOffset, parser, env, keepNul = false)
|
|
|
100
100
|
return end < body.length ? sourceOffset(end + 1) : undefined;
|
|
101
101
|
}});
|
|
102
102
|
let lines = 0;
|
|
103
|
-
for (let at =
|
|
103
|
+
for (let at = body.indexOf('\n'); at !== -1; at = body.indexOf('\n', at + 1)) lines++;
|
|
104
104
|
if (lines <= BLOCK_WINDOW) {
|
|
105
105
|
state = new parser.block.State(body, parser, env, tokens);
|
|
106
106
|
state.rapierSourceSlice = (from, to) => source.slice(sourceOffset(from), sourceOffset(to));
|
|
@@ -179,8 +179,7 @@ export function* blockWindows(source, bodyOffset, parser, env, keepNul = false)
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
const
|
|
183
|
-
code >= 97 && code <= 122 || '-._~:/?@+$,;='.includes(String.fromCharCode(code)));
|
|
182
|
+
const INVALID_PERCENT_PAYLOAD = /[^A-Za-z0-9._~:\/?@+$,;=%-]/;
|
|
184
183
|
const isHexUnit = code => code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
|
|
185
184
|
let lastScan = null;
|
|
186
185
|
export function dataImage(url) {
|
|
@@ -197,13 +196,11 @@ function scanDataImage(url) {
|
|
|
197
196
|
...(prepared.encoding ? {encoding: prepared.encoding} : {})};
|
|
198
197
|
if (/^data:image\/svg\+xml,/i.test(url)) {
|
|
199
198
|
const payloadStart = 19;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
at += 2;
|
|
206
|
-
} else if (!(code < 128 && PERCENT_PAYLOAD[code])) return null;
|
|
199
|
+
if (INVALID_PERCENT_PAYLOAD.test(url)) return null;
|
|
200
|
+
let byteLength = url.length - payloadStart;
|
|
201
|
+
for (let at = url.indexOf('%', payloadStart); at !== -1; at = url.indexOf('%', at + 3)) {
|
|
202
|
+
if (!isHexUnit(url.charCodeAt(at + 1)) || !isHexUnit(url.charCodeAt(at + 2))) return null;
|
|
203
|
+
byteLength -= 2;
|
|
207
204
|
}
|
|
208
205
|
return byteLength && byteLength <= IMAGE_LIMITS.bytes
|
|
209
206
|
? {codec: 'image/svg+xml', byteLength, payloadStart, encoding: 'percent'} : null;
|
package/dist/spec/md-layout.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
export const fields = new Set(['align', 'width', 'lines', 'wrap', 'x', 'y', 'rotate', 'opacity', 'first', 'indent', 'marker', 'lock', 'hyphens', 'caps', 'hanging', 'before', 'after', 'line']);
|
|
4
4
|
export const SPACING_FIELDS = Object.freeze(['before', 'after', 'line']);
|
|
5
5
|
export const alignments = new Set(['left', 'center', 'right', 'justify']);
|
|
6
|
-
export const wraps = new Set(['around', 'box', 'behind', 'front']);
|
|
6
|
+
export const wraps = new Set(['around', 'beside', 'box', 'behind', 'front']);
|
|
7
7
|
const has = (value, key) => Object.hasOwn(value, key);
|
|
8
8
|
const percent = value => typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 100;
|
|
9
9
|
const lineCount = value => Number.isInteger(value) && value >= 1 && value <= 12;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rapier-markdown-kit",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.44",
|
|
4
4
|
"description": "Read, render and write Self-contained Markdown: one .md file that carries its pictures, drawings and layout, and that any Markdown app can read. HTML renderer, stylesheet, text layout, Will/1 agent permissions, and an edit history with authorship and offline merge. MIT, no dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|