liquidsoap-prettier 1.7.4 → 1.8.1

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.
@@ -0,0 +1,70 @@
1
+ // OCaml's sedlex lexer counts UTF-8 bytes; prettier indexes into the JS string
2
+ // using UTF-16 char offsets. For ASCII-only files the two coincide, but any
3
+ // multi-byte character (e.g. π = 2 bytes, 1 JS char) introduces a drift that
4
+ // breaks prettier's ownLine / endOfLine comment classification.
5
+ //
6
+ // Strategy: one AST walk to collect all byte offsets needing remapping, then
7
+ // one linear UTF-8 scan to resolve them — no large intermediate array.
8
+
9
+ // Walk the AST and register a setter for each byte-offset field found.
10
+ // setters: Map<byteOffset, Array<(charIdx: number) => void>>
11
+ const collectOffsets = (node, setters) => {
12
+ if (node === null || typeof node !== "object") return;
13
+ if (Array.isArray(node)) {
14
+ for (const item of node) collectOffsets(item, setters);
15
+ return;
16
+ }
17
+ for (const key of Object.keys(node)) {
18
+ if (
19
+ (key === "cnum" || key === "bol" || key === "start" || key === "end") &&
20
+ typeof node[key] === "number"
21
+ ) {
22
+ const byteOffset = node[key];
23
+ if (!setters.has(byteOffset)) setters.set(byteOffset, []);
24
+ setters.get(byteOffset).push((charIdx) => {
25
+ node[key] = charIdx;
26
+ });
27
+ } else {
28
+ collectOffsets(node[key], setters);
29
+ }
30
+ }
31
+ };
32
+
33
+ export const remapOffsets = (result, text) => {
34
+ // Step 1: collect all byte offsets and their setters.
35
+ const setters = new Map();
36
+ collectOffsets(result, setters);
37
+ if (setters.size === 0) return;
38
+
39
+ // Step 2: sort offsets so we can walk them in order.
40
+ const targets = [...setters.keys()].sort((a, b) => a - b);
41
+
42
+ // Step 3: single linear scan through UTF-8 bytes, resolving setters on the fly.
43
+ const utf8 = new TextEncoder().encode(text);
44
+ let charIdx = 0;
45
+ let targetIdx = 0;
46
+
47
+ for (let byteIdx = 0; byteIdx <= utf8.length; ) {
48
+ // Resolve all setters whose target matches the current byte position.
49
+ while (targetIdx < targets.length && targets[targetIdx] === byteIdx) {
50
+ for (const setter of setters.get(targets[targetIdx])) setter(charIdx);
51
+ targetIdx++;
52
+ }
53
+ if (targetIdx >= targets.length || byteIdx >= utf8.length) break;
54
+
55
+ const b = utf8[byteIdx];
56
+ if (b < 0x80) {
57
+ byteIdx += 1;
58
+ charIdx += 1;
59
+ } else if (b < 0xe0) {
60
+ byteIdx += 2;
61
+ charIdx += 1;
62
+ } else if (b < 0xf0) {
63
+ byteIdx += 3;
64
+ charIdx += 1;
65
+ } else {
66
+ byteIdx += 4;
67
+ charIdx += 2; // Surrogate pair: 4-byte UTF-8 = 2 UTF-16 code units
68
+ }
69
+ }
70
+ };