/
hashPlaceholders.ts
74 lines (66 loc) · 2.47 KB
/
hashPlaceholders.ts
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
import { toBase64 } from './base64';
import { errFailedValidation, error } from './error';
// Four random characters from the private use area to minimize risk of conflicts
const hashPlaceholderLeft = '!~{';
const hashPlaceholderRight = '}~';
const hashPlaceholderOverhead = hashPlaceholderLeft.length + hashPlaceholderRight.length;
// This is the size of a sha256
export const maxHashSize = 64;
export const defaultHashSize = 8;
export type HashPlaceholderGenerator = (optionName: string, hashSize?: number) => string;
export const getHashPlaceholderGenerator = (): HashPlaceholderGenerator => {
let nextIndex = 0;
return (optionName: string, hashSize: number = defaultHashSize) => {
if (hashSize > maxHashSize) {
return error(
errFailedValidation(
`Hashes cannot be longer than ${maxHashSize} characters, received ${hashSize}. Check the "${optionName}" option.`
)
);
}
const placeholder = `${hashPlaceholderLeft}${toBase64(++nextIndex).padStart(
hashSize - hashPlaceholderOverhead,
'0'
)}${hashPlaceholderRight}`;
if (placeholder.length > hashSize) {
return error(
errFailedValidation(
`To generate hashes for this number of chunks (currently ${nextIndex}), you need a minimum hash size of ${placeholder.length}, received ${hashSize}. Check the "${optionName}" option.`
)
);
}
return placeholder;
};
};
const REPLACER_REGEX = new RegExp(
`${hashPlaceholderLeft}[0-9a-zA-Z_$]{1,${
maxHashSize - hashPlaceholderOverhead
}}${hashPlaceholderRight}`,
'g'
);
export const replacePlaceholders = (
code: string,
hashesByPlaceholder: Map<string, string>
): string =>
code.replace(REPLACER_REGEX, placeholder => hashesByPlaceholder.get(placeholder) || placeholder);
export const replaceSinglePlaceholder = (
code: string,
placeholder: string,
value: string
): string => code.replace(REPLACER_REGEX, match => (match === placeholder ? value : match));
export const replacePlaceholdersWithDefaultAndGetContainedPlaceholders = (
code: string,
placeholders: Set<string>
): { containedPlaceholders: Set<string>; transformedCode: string } => {
const containedPlaceholders = new Set<string>();
const transformedCode = code.replace(REPLACER_REGEX, placeholder => {
if (placeholders.has(placeholder)) {
containedPlaceholders.add(placeholder);
return `${hashPlaceholderLeft}${'0'.repeat(
placeholder.length - hashPlaceholderOverhead
)}${hashPlaceholderRight}`;
}
return placeholder;
});
return { containedPlaceholders, transformedCode };
};