-
-
Notifications
You must be signed in to change notification settings - Fork 61
/
utils.ts
127 lines (103 loc) · 2.78 KB
/
utils.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
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
117
118
119
120
121
122
123
124
125
126
127
// TODO: allow '-' to trim up until newline. Use [^\S\n\r] instead of \s
// TODO: only include trimLeft polyfill if not in ES6
import { trimLeft, trimRight } from "./polyfills.ts";
/* TYPES */
import type { EtaConfig } from "./config.ts";
interface EscapeMap {
"&": "&";
"<": "<";
">": ">";
'"': """;
"'": "'";
[index: string]: string;
}
/* END TYPES */
export function hasOwnProp(obj: object, prop: string): boolean {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
export function copyProps<T>(toObj: T, fromObj: T): T {
for (const key in fromObj) {
if (hasOwnProp((fromObj as unknown) as object, key)) {
toObj[key] = fromObj[key];
}
}
return toObj;
}
/**
* Takes a string within a template and trims it, based on the preceding tag's whitespace control and `config.autoTrim`
*/
function trimWS(
str: string,
config: EtaConfig,
wsLeft: string | false,
wsRight?: string | false,
): string {
let leftTrim;
let rightTrim;
if (Array.isArray(config.autoTrim)) {
// kinda confusing
// but _}} will trim the left side of the following string
leftTrim = config.autoTrim[1];
rightTrim = config.autoTrim[0];
} else {
leftTrim = rightTrim = config.autoTrim;
}
if (wsLeft || wsLeft === false) {
leftTrim = wsLeft;
}
if (wsRight || wsRight === false) {
rightTrim = wsRight;
}
if (!rightTrim && !leftTrim) {
return str;
}
if (leftTrim === "slurp" && rightTrim === "slurp") {
return str.trim();
}
if (leftTrim === "_" || leftTrim === "slurp") {
// console.log('trimming left' + leftTrim)
// full slurp
str = trimLeft(str);
} else if (leftTrim === "-" || leftTrim === "nl") {
// nl trim
str = str.replace(/^(?:\r\n|\n|\r)/, "");
}
if (rightTrim === "_" || rightTrim === "slurp") {
// full slurp
str = trimRight(str);
} else if (rightTrim === "-" || rightTrim === "nl") {
// nl trim
str = str.replace(/(?:\r\n|\n|\r)$/, ""); // TODO: make sure this gets \r\n
}
return str;
}
/**
* A map of special HTML characters to their XML-escaped equivalents
*/
const escMap: EscapeMap = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
};
function replaceChar(s: string): string {
return escMap[s];
}
/**
* XML-escapes an input value after converting it to a string
*
* @param str - Input value (usually a string)
* @returns XML-escaped string
*/
function XMLEscape(str: any): string {
// eslint-disable-line @typescript-eslint/no-explicit-any
// To deal with XSS. Based on Escape implementations of Mustache.JS and Marko, then customized.
const newStr = String(str);
if (/[&<>"']/.test(newStr)) {
return newStr.replace(/[&<>"']/g, replaceChar);
} else {
return newStr;
}
}
export { trimWS, XMLEscape };