-
Notifications
You must be signed in to change notification settings - Fork 124
Expand file tree
/
Copy pathhashUtils.ts
More file actions
116 lines (99 loc) · 4.39 KB
/
hashUtils.ts
File metadata and controls
116 lines (99 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import type { BorderSpec, CellBorders, Run, TableBorders, TableBorderValue } from '@superdoc/contracts';
/**
* Hash helpers for block version computation.
*
* Duplicated from painters/dom/src/paragraph-hash-utils.ts to avoid a circular
* dependency (painter-dom -> layout-resolved is not allowed). Keep the two
* copies in sync.
*/
// ---------------------------------------------------------------------------
// Table/Cell border hashing
// ---------------------------------------------------------------------------
const isNoneBorder = (value: TableBorderValue): value is { none: true } => {
return typeof value === 'object' && value !== null && 'none' in value && (value as { none: true }).none === true;
};
const isBorderSpec = (value: unknown): value is BorderSpec => {
return typeof value === 'object' && value !== null && !('none' in value);
};
export const hashBorderSpec = (border: BorderSpec): string => {
const parts: string[] = [];
if (border.style !== undefined) parts.push(`s:${border.style}`);
if (border.width !== undefined) parts.push(`w:${border.width}`);
if (border.color !== undefined) parts.push(`c:${border.color}`);
if (border.space !== undefined) parts.push(`sp:${border.space}`);
return parts.join(',');
};
const hashTableBorderValue = (borderValue: TableBorderValue | undefined): string => {
if (borderValue === undefined) return '';
if (borderValue === null) return 'null';
if (isNoneBorder(borderValue)) return 'none';
if (isBorderSpec(borderValue)) {
return hashBorderSpec(borderValue);
}
return '';
};
export const hashTableBorders = (borders: TableBorders | undefined): string => {
if (!borders) return '';
const parts: string[] = [];
if (borders.top !== undefined) parts.push(`t:[${hashTableBorderValue(borders.top)}]`);
if (borders.right !== undefined) parts.push(`r:[${hashTableBorderValue(borders.right)}]`);
if (borders.bottom !== undefined) parts.push(`b:[${hashTableBorderValue(borders.bottom)}]`);
if (borders.left !== undefined) parts.push(`l:[${hashTableBorderValue(borders.left)}]`);
if (borders.insideH !== undefined) parts.push(`ih:[${hashTableBorderValue(borders.insideH)}]`);
if (borders.insideV !== undefined) parts.push(`iv:[${hashTableBorderValue(borders.insideV)}]`);
return parts.join(';');
};
export const hashCellBorders = (borders: CellBorders | undefined): string => {
if (!borders) return '';
const parts: string[] = [];
if (borders.top) parts.push(`t:[${hashBorderSpec(borders.top)}]`);
if (borders.right) parts.push(`r:[${hashBorderSpec(borders.right)}]`);
if (borders.bottom) parts.push(`b:[${hashBorderSpec(borders.bottom)}]`);
if (borders.left) parts.push(`l:[${hashBorderSpec(borders.left)}]`);
return parts.join(';');
};
// ---------------------------------------------------------------------------
// Run property accessors
// ---------------------------------------------------------------------------
const hasStringProp = (run: Run, prop: string): run is Run & Record<string, string> => {
return prop in run && typeof (run as Record<string, unknown>)[prop] === 'string';
};
const hasNumberProp = (run: Run, prop: string): run is Run & Record<string, number> => {
return prop in run && typeof (run as Record<string, unknown>)[prop] === 'number';
};
const hasBooleanProp = (run: Run, prop: string): run is Run & Record<string, boolean> => {
return prop in run && typeof (run as Record<string, unknown>)[prop] === 'boolean';
};
export const getRunStringProp = (run: Run, prop: string): string => {
if (hasStringProp(run, prop)) {
return run[prop];
}
return '';
};
export const getRunNumberProp = (run: Run, prop: string): number => {
if (hasNumberProp(run, prop)) {
return run[prop];
}
return 0;
};
export const getRunBooleanProp = (run: Run, prop: string): boolean => {
if (hasBooleanProp(run, prop)) {
return run[prop];
}
return false;
};
export const getRunUnderlineStyle = (run: Run): string => {
if ('underline' in run && typeof run.underline === 'boolean') {
return run.underline ? 'single' : '';
}
if ('underline' in run && run.underline && typeof run.underline === 'object') {
return (run.underline as { style?: string }).style ?? '';
}
return '';
};
export const getRunUnderlineColor = (run: Run): string => {
if ('underline' in run && run.underline && typeof run.underline === 'object') {
return (run.underline as { color?: string }).color ?? '';
}
return '';
};