rapier-markdown-kit 1.1.91 → 1.1.93

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.
@@ -21,27 +21,33 @@ const K = new Uint32Array([
21
21
  0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
22
22
  0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2,
23
23
  ]);
24
- const rotate = (x, n) => (x >>> n) | (x << (32 - n));
24
+ // The rounds run on plain 32-bit locals: no array is made per block, so a megabyte (a painting's text) hashes about five times
25
+ // faster than through destructured arrays, with the same digest.
26
+ const W = new Int32Array(64);
25
27
  export function sha256(text) {
26
- const bytes = new TextEncoder().encode(text);
27
- const padded = new Uint8Array(Math.ceil((bytes.length + 9) / 64) * 64);
28
- padded.set(bytes); padded[bytes.length] = 0x80;
29
- const data = new DataView(padded.buffer), bits = bytes.length * 8;
30
- data.setUint32(padded.length - 8, Math.floor(bits / 0x100000000)); data.setUint32(padded.length - 4, bits >>> 0);
31
- const h = new Uint32Array([0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19]), w = new Uint32Array(64);
32
- for (let offset = 0; offset < padded.length; offset += 64) {
33
- for (let i = 0; i < 16; i++) w[i] = data.getUint32(offset + i * 4);
28
+ const bytes = new TextEncoder().encode(text), length = bytes.length;
29
+ const padded = new Uint8Array(Math.ceil((length + 9) / 64) * 64), end = padded.length;
30
+ padded.set(bytes); padded[length] = 0x80;
31
+ const high = Math.floor(length * 8 / 0x100000000), low = (length * 8) >>> 0;
32
+ padded[end - 8] = high >>> 24; padded[end - 7] = high >>> 16; padded[end - 6] = high >>> 8; padded[end - 5] = high;
33
+ padded[end - 4] = low >>> 24; padded[end - 3] = low >>> 16; padded[end - 2] = low >>> 8; padded[end - 1] = low;
34
+ let h0 = 0x6a09e667 | 0, h1 = 0xbb67ae85 | 0, h2 = 0x3c6ef372 | 0, h3 = 0xa54ff53a | 0, h4 = 0x510e527f | 0, h5 = 0x9b05688c | 0, h6 = 0x1f83d9ab | 0, h7 = 0x5be0cd19 | 0;
35
+ const w = W;
36
+ for (let offset = 0; offset < end; offset += 64) {
37
+ for (let i = 0, j = offset; i < 16; i++, j += 4) w[i] = padded[j] << 24 | padded[j + 1] << 16 | padded[j + 2] << 8 | padded[j + 3];
34
38
  for (let i = 16; i < 64; i++) {
35
39
  const x = w[i - 15], y = w[i - 2];
36
- w[i] = w[i - 16] + (rotate(x, 7) ^ rotate(x, 18) ^ (x >>> 3)) + w[i - 7] + (rotate(y, 17) ^ rotate(y, 19) ^ (y >>> 10));
40
+ w[i] = (w[i - 16] + ((x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ x >>> 3) + w[i - 7] + ((y >>> 17 | y << 15) ^ (y >>> 19 | y << 13) ^ y >>> 10)) | 0;
37
41
  }
38
- let [a,b,c,d,e,f,g,k] = h;
42
+ let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, k = h7;
39
43
  for (let i = 0; i < 64; i++) {
40
- const t1 = (k + (rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25)) + ((e & f) ^ (~e & g)) + K[i] + w[i]) >>> 0;
41
- const t2 = ((rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
42
- k = g; g = f; f = e; e = (d + t1) >>> 0; d = c; c = b; b = a; a = (t1 + t2) >>> 0;
44
+ const t1 = (k + ((e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7)) + (e & f ^ ~e & g) + K[i] + w[i]) | 0;
45
+ const t2 = (((a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10)) + (a & b ^ a & c ^ b & c)) | 0;
46
+ k = g; g = f; f = e; e = (d + t1) | 0; d = c; c = b; b = a; a = (t1 + t2) | 0;
43
47
  }
44
- for (const [i, value] of [a,b,c,d,e,f,g,k].entries()) h[i] += value;
48
+ h0 = (h0 + a) | 0; h1 = (h1 + b) | 0; h2 = (h2 + c) | 0; h3 = (h3 + d) | 0; h4 = (h4 + e) | 0; h5 = (h5 + f) | 0; h6 = (h6 + g) | 0; h7 = (h7 + k) | 0;
45
49
  }
46
- return [...h].map(x => x.toString(16).padStart(8, '0')).join('');
50
+ let out = '';
51
+ for (const x of [h0, h1, h2, h3, h4, h5, h6, h7]) out += (x >>> 0).toString(16).padStart(8, '0');
52
+ return out;
47
53
  }
@@ -177,6 +177,57 @@ export function historyProjection(input, {from = 0, to = input?.source?.length,
177
177
  earliestRevision: prepared.earliestRevision, complete: prepared.complete, acts, groups: groupHistoryActs(acts), ...(before ? {before} : {})};
178
178
  }
179
179
 
180
+ // Project all reading places in one replay. Typing only invalidates this transient view.
181
+ export function historyPlaces(input, blocks) {
182
+ const prepared = prepareHistory(input);
183
+ if (!prepared.ok) return prepared;
184
+ if (!Array.isArray(blocks) || blocks.some(block => !block ||
185
+ !historyBoundary(prepared.source, block.from) || !historyBoundary(prepared.source, block.to) || block.to < block.from))
186
+ return historyFailure('range_invalid');
187
+ const projected = blocks.map(block => ({id: block.id, from: block.from, to: block.to,
188
+ source: prepared.source.slice(block.from, block.to), range: {from: block.from, to: block.to}, acts: []}));
189
+ let text = prepared.source;
190
+ for (let index = prepared.rows.length - 1; index >= 0; index--) {
191
+ const {record, splices} = prepared.rows[index], before = historyPreviousSource(text, splices);
192
+ if (before === null) return historyFailure('history_invalid');
193
+ for (const block of projected) {
194
+ const after = {...block.range, source: text.slice(block.range.from, block.range.to)};
195
+ let touched = false;
196
+ for (let at = splices.length - 1; at >= 0; at--) {
197
+ const mapped = historyRangeBefore(block.range, splices[at]);
198
+ block.range = {from: mapped.from, to: mapped.to}; touched ||= mapped.touched;
199
+ }
200
+ const previous = {...block.range, source: before.slice(block.range.from, block.range.to)};
201
+ if (touched && previous.source !== after.source) block.acts.push({...historyAct(record), before: previous, after});
202
+ }
203
+ text = before;
204
+ }
205
+ const acts = prepared.rows.map(({record}) => historyAct(record));
206
+ const present = new Map(), effects = new Map();
207
+ for (const act of acts) {
208
+ const changes = [];
209
+ const set = (id, value) => {
210
+ const prior = present.get(id) === true;
211
+ present.set(id, value); changes.push({id, before: prior, after: value});
212
+ };
213
+ if (act.reapplies) {
214
+ for (const change of effects.get(act.reapplies) || [{id: act.reapplies, after: true}]) set(change.id, change.after);
215
+ } else {
216
+ const ids = act.sourceTransactionIds || (act.sourceTransactionId ? [act.sourceTransactionId] : act.reverts ? [act.reverts] : []);
217
+ for (const id of ids) {
218
+ for (const change of (effects.get(id) || [{id, before: false, after: true}]).slice().reverse()) {
219
+ if (present.get(change.id) === change.after) set(change.id, change.before);
220
+ }
221
+ }
222
+ }
223
+ set(act.id, true); effects.set(act.id, changes);
224
+ }
225
+ for (const block of projected) { block.acts.reverse(); delete block.range; }
226
+ return {ok: true, source: prepared.source, initialSource: prepared.initialSource, revision: prepared.revision,
227
+ earliestRevision: prepared.earliestRevision, complete: prepared.complete, acts, blocks: projected,
228
+ reversed: acts.filter(act => present.get(act.id) !== true).map(act => act.id)};
229
+ }
230
+
180
231
  function minimalHistorySplice(before, after, pos = 0) {
181
232
  let first = 0, a = before.length, b = after.length;
182
233
  while (first < a && first < b && before[first] === after[first]) first++;
@@ -7,8 +7,8 @@ import {merge, transportInterval, transportTouchedInterval} from './ledger/merge
7
7
  export {merge, transportInterval, transportTouchedInterval};
8
8
  import {_rapierTransformSplices, _rapierRecordSplices, _rapierValidLedgerRecord, _rapierRecordMetadata, _rapierValidMetadata, _rapierValidMetadataEffect, _rapierTransformMetadata, _rapierMetadataDelta, _rapierHistoryEffects, _rapierMetadataState, _rapierReplayMetadata, _rapierHasHistoryEffect} from './ledger/journal-records.mjs';
9
9
  export {_rapierTransformSplices, _rapierRecordSplices, _rapierValidLedgerRecord, _rapierRecordMetadata, _rapierValidMetadata, _rapierValidMetadataEffect, _rapierTransformMetadata, _rapierMetadataDelta, _rapierHistoryEffects, _rapierMetadataState, _rapierReplayMetadata, _rapierHasHistoryEffect};
10
- import {replayHistory, sourceBefore, historyProjection, selectiveUndo, groupHistoryActs} from './ledger/history.mjs';
11
- export {replayHistory, sourceBefore, historyProjection, selectiveUndo, groupHistoryActs};
10
+ import {replayHistory, sourceBefore, historyProjection, historyPlaces, selectiveUndo, groupHistoryActs} from './ledger/history.mjs';
11
+ export {replayHistory, sourceBefore, historyProjection, historyPlaces, selectiveUndo, groupHistoryActs};
12
12
 
13
13
  import {transposeSource} from './ledger/transport.mjs';
14
14
  export {transposeSource};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rapier-markdown-kit",
3
- "version": "1.1.91",
3
+ "version": "1.1.93",
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",