dompurify 3.4.1 → 3.4.2
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.
- package/README.md +1 -2
- package/dist/purify.cjs.d.ts +1 -1
- package/dist/purify.cjs.js +4 -3
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.d.mts +1 -1
- package/dist/purify.es.mjs +4 -3
- package/dist/purify.es.mjs.map +1 -1
- package/dist/purify.js +4 -3
- package/dist/purify.js.map +1 -1
- package/dist/purify.min.js +2 -2
- package/dist/purify.min.js.map +1 -1
- package/package.json +4 -3
- package/src/attrs.ts +376 -0
- package/src/config.ts +259 -0
- package/src/license_header +1 -0
- package/src/purify.ts +2184 -0
- package/src/regexp.ts +17 -0
- package/src/tags.ts +285 -0
- package/src/utils.ts +338 -0
package/src/regexp.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { seal } from './utils.js';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line unicorn/better-regex
|
|
4
|
+
export const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
5
|
+
export const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
|
6
|
+
export const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
|
7
|
+
export const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
|
8
|
+
export const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
9
|
+
export const IS_ALLOWED_URI = seal(
|
|
10
|
+
/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
11
|
+
);
|
|
12
|
+
export const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
13
|
+
export const ATTR_WHITESPACE = seal(
|
|
14
|
+
/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
15
|
+
);
|
|
16
|
+
export const DOCTYPE_NAME = seal(/^html$/i);
|
|
17
|
+
export const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
package/src/tags.ts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { freeze } from './utils.js';
|
|
2
|
+
|
|
3
|
+
export const html = freeze([
|
|
4
|
+
'a',
|
|
5
|
+
'abbr',
|
|
6
|
+
'acronym',
|
|
7
|
+
'address',
|
|
8
|
+
'area',
|
|
9
|
+
'article',
|
|
10
|
+
'aside',
|
|
11
|
+
'audio',
|
|
12
|
+
'b',
|
|
13
|
+
'bdi',
|
|
14
|
+
'bdo',
|
|
15
|
+
'big',
|
|
16
|
+
'blink',
|
|
17
|
+
'blockquote',
|
|
18
|
+
'body',
|
|
19
|
+
'br',
|
|
20
|
+
'button',
|
|
21
|
+
'canvas',
|
|
22
|
+
'caption',
|
|
23
|
+
'center',
|
|
24
|
+
'cite',
|
|
25
|
+
'code',
|
|
26
|
+
'col',
|
|
27
|
+
'colgroup',
|
|
28
|
+
'content',
|
|
29
|
+
'data',
|
|
30
|
+
'datalist',
|
|
31
|
+
'dd',
|
|
32
|
+
'decorator',
|
|
33
|
+
'del',
|
|
34
|
+
'details',
|
|
35
|
+
'dfn',
|
|
36
|
+
'dialog',
|
|
37
|
+
'dir',
|
|
38
|
+
'div',
|
|
39
|
+
'dl',
|
|
40
|
+
'dt',
|
|
41
|
+
'element',
|
|
42
|
+
'em',
|
|
43
|
+
'fieldset',
|
|
44
|
+
'figcaption',
|
|
45
|
+
'figure',
|
|
46
|
+
'font',
|
|
47
|
+
'footer',
|
|
48
|
+
'form',
|
|
49
|
+
'h1',
|
|
50
|
+
'h2',
|
|
51
|
+
'h3',
|
|
52
|
+
'h4',
|
|
53
|
+
'h5',
|
|
54
|
+
'h6',
|
|
55
|
+
'head',
|
|
56
|
+
'header',
|
|
57
|
+
'hgroup',
|
|
58
|
+
'hr',
|
|
59
|
+
'html',
|
|
60
|
+
'i',
|
|
61
|
+
'img',
|
|
62
|
+
'input',
|
|
63
|
+
'ins',
|
|
64
|
+
'kbd',
|
|
65
|
+
'label',
|
|
66
|
+
'legend',
|
|
67
|
+
'li',
|
|
68
|
+
'main',
|
|
69
|
+
'map',
|
|
70
|
+
'mark',
|
|
71
|
+
'marquee',
|
|
72
|
+
'menu',
|
|
73
|
+
'menuitem',
|
|
74
|
+
'meter',
|
|
75
|
+
'nav',
|
|
76
|
+
'nobr',
|
|
77
|
+
'ol',
|
|
78
|
+
'optgroup',
|
|
79
|
+
'option',
|
|
80
|
+
'output',
|
|
81
|
+
'p',
|
|
82
|
+
'picture',
|
|
83
|
+
'pre',
|
|
84
|
+
'progress',
|
|
85
|
+
'q',
|
|
86
|
+
'rp',
|
|
87
|
+
'rt',
|
|
88
|
+
'ruby',
|
|
89
|
+
's',
|
|
90
|
+
'samp',
|
|
91
|
+
'search',
|
|
92
|
+
'section',
|
|
93
|
+
'select',
|
|
94
|
+
'shadow',
|
|
95
|
+
'slot',
|
|
96
|
+
'small',
|
|
97
|
+
'source',
|
|
98
|
+
'spacer',
|
|
99
|
+
'span',
|
|
100
|
+
'strike',
|
|
101
|
+
'strong',
|
|
102
|
+
'style',
|
|
103
|
+
'sub',
|
|
104
|
+
'summary',
|
|
105
|
+
'sup',
|
|
106
|
+
'table',
|
|
107
|
+
'tbody',
|
|
108
|
+
'td',
|
|
109
|
+
'template',
|
|
110
|
+
'textarea',
|
|
111
|
+
'tfoot',
|
|
112
|
+
'th',
|
|
113
|
+
'thead',
|
|
114
|
+
'time',
|
|
115
|
+
'tr',
|
|
116
|
+
'track',
|
|
117
|
+
'tt',
|
|
118
|
+
'u',
|
|
119
|
+
'ul',
|
|
120
|
+
'var',
|
|
121
|
+
'video',
|
|
122
|
+
'wbr',
|
|
123
|
+
] as const);
|
|
124
|
+
|
|
125
|
+
export const svg = freeze([
|
|
126
|
+
'svg',
|
|
127
|
+
'a',
|
|
128
|
+
'altglyph',
|
|
129
|
+
'altglyphdef',
|
|
130
|
+
'altglyphitem',
|
|
131
|
+
'animatecolor',
|
|
132
|
+
'animatemotion',
|
|
133
|
+
'animatetransform',
|
|
134
|
+
'circle',
|
|
135
|
+
'clippath',
|
|
136
|
+
'defs',
|
|
137
|
+
'desc',
|
|
138
|
+
'ellipse',
|
|
139
|
+
'enterkeyhint',
|
|
140
|
+
'exportparts',
|
|
141
|
+
'filter',
|
|
142
|
+
'font',
|
|
143
|
+
'g',
|
|
144
|
+
'glyph',
|
|
145
|
+
'glyphref',
|
|
146
|
+
'hkern',
|
|
147
|
+
'image',
|
|
148
|
+
'inputmode',
|
|
149
|
+
'line',
|
|
150
|
+
'lineargradient',
|
|
151
|
+
'marker',
|
|
152
|
+
'mask',
|
|
153
|
+
'metadata',
|
|
154
|
+
'mpath',
|
|
155
|
+
'part',
|
|
156
|
+
'path',
|
|
157
|
+
'pattern',
|
|
158
|
+
'polygon',
|
|
159
|
+
'polyline',
|
|
160
|
+
'radialgradient',
|
|
161
|
+
'rect',
|
|
162
|
+
'stop',
|
|
163
|
+
'style',
|
|
164
|
+
'switch',
|
|
165
|
+
'symbol',
|
|
166
|
+
'text',
|
|
167
|
+
'textpath',
|
|
168
|
+
'title',
|
|
169
|
+
'tref',
|
|
170
|
+
'tspan',
|
|
171
|
+
'view',
|
|
172
|
+
'vkern',
|
|
173
|
+
] as const);
|
|
174
|
+
|
|
175
|
+
export const svgFilters = freeze([
|
|
176
|
+
'feBlend',
|
|
177
|
+
'feColorMatrix',
|
|
178
|
+
'feComponentTransfer',
|
|
179
|
+
'feComposite',
|
|
180
|
+
'feConvolveMatrix',
|
|
181
|
+
'feDiffuseLighting',
|
|
182
|
+
'feDisplacementMap',
|
|
183
|
+
'feDistantLight',
|
|
184
|
+
'feDropShadow',
|
|
185
|
+
'feFlood',
|
|
186
|
+
'feFuncA',
|
|
187
|
+
'feFuncB',
|
|
188
|
+
'feFuncG',
|
|
189
|
+
'feFuncR',
|
|
190
|
+
'feGaussianBlur',
|
|
191
|
+
'feImage',
|
|
192
|
+
'feMerge',
|
|
193
|
+
'feMergeNode',
|
|
194
|
+
'feMorphology',
|
|
195
|
+
'feOffset',
|
|
196
|
+
'fePointLight',
|
|
197
|
+
'feSpecularLighting',
|
|
198
|
+
'feSpotLight',
|
|
199
|
+
'feTile',
|
|
200
|
+
'feTurbulence',
|
|
201
|
+
] as const);
|
|
202
|
+
|
|
203
|
+
// List of SVG elements that are disallowed by default.
|
|
204
|
+
// We still need to know them so that we can do namespace
|
|
205
|
+
// checks properly in case one wants to add them to
|
|
206
|
+
// allow-list.
|
|
207
|
+
export const svgDisallowed = freeze([
|
|
208
|
+
'animate',
|
|
209
|
+
'color-profile',
|
|
210
|
+
'cursor',
|
|
211
|
+
'discard',
|
|
212
|
+
'font-face',
|
|
213
|
+
'font-face-format',
|
|
214
|
+
'font-face-name',
|
|
215
|
+
'font-face-src',
|
|
216
|
+
'font-face-uri',
|
|
217
|
+
'foreignobject',
|
|
218
|
+
'hatch',
|
|
219
|
+
'hatchpath',
|
|
220
|
+
'mesh',
|
|
221
|
+
'meshgradient',
|
|
222
|
+
'meshpatch',
|
|
223
|
+
'meshrow',
|
|
224
|
+
'missing-glyph',
|
|
225
|
+
'script',
|
|
226
|
+
'set',
|
|
227
|
+
'solidcolor',
|
|
228
|
+
'unknown',
|
|
229
|
+
'use',
|
|
230
|
+
] as const);
|
|
231
|
+
|
|
232
|
+
export const mathMl = freeze([
|
|
233
|
+
'math',
|
|
234
|
+
'menclose',
|
|
235
|
+
'merror',
|
|
236
|
+
'mfenced',
|
|
237
|
+
'mfrac',
|
|
238
|
+
'mglyph',
|
|
239
|
+
'mi',
|
|
240
|
+
'mlabeledtr',
|
|
241
|
+
'mmultiscripts',
|
|
242
|
+
'mn',
|
|
243
|
+
'mo',
|
|
244
|
+
'mover',
|
|
245
|
+
'mpadded',
|
|
246
|
+
'mphantom',
|
|
247
|
+
'mroot',
|
|
248
|
+
'mrow',
|
|
249
|
+
'ms',
|
|
250
|
+
'mspace',
|
|
251
|
+
'msqrt',
|
|
252
|
+
'mstyle',
|
|
253
|
+
'msub',
|
|
254
|
+
'msup',
|
|
255
|
+
'msubsup',
|
|
256
|
+
'mtable',
|
|
257
|
+
'mtd',
|
|
258
|
+
'mtext',
|
|
259
|
+
'mtr',
|
|
260
|
+
'munder',
|
|
261
|
+
'munderover',
|
|
262
|
+
'mprescripts',
|
|
263
|
+
] as const);
|
|
264
|
+
|
|
265
|
+
// Similarly to SVG, we want to know all MathML elements,
|
|
266
|
+
// even those that we disallow by default.
|
|
267
|
+
export const mathMlDisallowed = freeze([
|
|
268
|
+
'maction',
|
|
269
|
+
'maligngroup',
|
|
270
|
+
'malignmark',
|
|
271
|
+
'mlongdiv',
|
|
272
|
+
'mscarries',
|
|
273
|
+
'mscarry',
|
|
274
|
+
'msgroup',
|
|
275
|
+
'mstack',
|
|
276
|
+
'msline',
|
|
277
|
+
'msrow',
|
|
278
|
+
'semantics',
|
|
279
|
+
'annotation',
|
|
280
|
+
'annotation-xml',
|
|
281
|
+
'mprescripts',
|
|
282
|
+
'none',
|
|
283
|
+
] as const);
|
|
284
|
+
|
|
285
|
+
export const text = freeze(['#text'] as const);
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
const {
|
|
2
|
+
entries,
|
|
3
|
+
setPrototypeOf,
|
|
4
|
+
isFrozen,
|
|
5
|
+
getPrototypeOf,
|
|
6
|
+
getOwnPropertyDescriptor,
|
|
7
|
+
} = Object;
|
|
8
|
+
|
|
9
|
+
let { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports
|
|
10
|
+
let { apply, construct } = typeof Reflect !== 'undefined' && Reflect;
|
|
11
|
+
|
|
12
|
+
if (!freeze) {
|
|
13
|
+
freeze = function <T>(x: T): T {
|
|
14
|
+
return x;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!seal) {
|
|
19
|
+
seal = function <T>(x: T): T {
|
|
20
|
+
return x;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!apply) {
|
|
25
|
+
apply = function <T>(
|
|
26
|
+
func: (thisArg: any, ...args: any[]) => T,
|
|
27
|
+
thisArg: any,
|
|
28
|
+
...args: any[]
|
|
29
|
+
): T {
|
|
30
|
+
return func.apply(thisArg, args);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!construct) {
|
|
35
|
+
construct = function <T>(Func: new (...args: any[]) => T, ...args: any[]): T {
|
|
36
|
+
return new Func(...args);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const arrayForEach = unapply(Array.prototype.forEach);
|
|
41
|
+
const arrayIndexOf = unapply(Array.prototype.indexOf);
|
|
42
|
+
const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
|
|
43
|
+
const arrayPop = unapply(Array.prototype.pop);
|
|
44
|
+
const arrayPush = unapply(Array.prototype.push);
|
|
45
|
+
const arraySlice = unapply(Array.prototype.slice);
|
|
46
|
+
const arraySplice = unapply(Array.prototype.splice);
|
|
47
|
+
const arrayIsArray = Array.isArray;
|
|
48
|
+
|
|
49
|
+
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
50
|
+
const stringToString = unapply(String.prototype.toString);
|
|
51
|
+
const stringMatch = unapply(String.prototype.match);
|
|
52
|
+
const stringReplace = unapply(String.prototype.replace);
|
|
53
|
+
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
54
|
+
const stringTrim = unapply(String.prototype.trim);
|
|
55
|
+
|
|
56
|
+
const numberToString = unapply(Number.prototype.toString);
|
|
57
|
+
const booleanToString = unapply(Boolean.prototype.toString);
|
|
58
|
+
const bigintToString =
|
|
59
|
+
typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
|
|
60
|
+
const symbolToString =
|
|
61
|
+
typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
|
|
62
|
+
|
|
63
|
+
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
|
64
|
+
const objectToString = unapply(Object.prototype.toString);
|
|
65
|
+
|
|
66
|
+
const regExpTest = unapply(RegExp.prototype.test);
|
|
67
|
+
|
|
68
|
+
const typeErrorCreate = unconstruct(TypeError);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
|
72
|
+
*
|
|
73
|
+
* @param func - The function to be wrapped and called.
|
|
74
|
+
* @returns A new function that calls the given function with a specified thisArg and arguments.
|
|
75
|
+
*/
|
|
76
|
+
function unapply<T>(
|
|
77
|
+
func: (thisArg: any, ...args: any[]) => T
|
|
78
|
+
): (thisArg: any, ...args: any[]) => T {
|
|
79
|
+
return (thisArg: any, ...args: any[]): T => {
|
|
80
|
+
if (thisArg instanceof RegExp) {
|
|
81
|
+
thisArg.lastIndex = 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return apply(func, thisArg, args);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
|
|
90
|
+
*
|
|
91
|
+
* @param func - The constructor function to be wrapped and called.
|
|
92
|
+
* @returns A new function that constructs an instance of the given constructor function with the provided arguments.
|
|
93
|
+
*/
|
|
94
|
+
function unconstruct<T>(
|
|
95
|
+
Func: new (...args: any[]) => T
|
|
96
|
+
): (...args: any[]) => T {
|
|
97
|
+
return (...args: any[]): T => construct(Func, args);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Add properties to a lookup table
|
|
102
|
+
*
|
|
103
|
+
* @param set - The set to which elements will be added.
|
|
104
|
+
* @param array - The array containing elements to be added to the set.
|
|
105
|
+
* @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
|
|
106
|
+
* @returns The modified set with added elements.
|
|
107
|
+
*/
|
|
108
|
+
function addToSet(
|
|
109
|
+
set: Record<string, boolean>,
|
|
110
|
+
array: readonly unknown[],
|
|
111
|
+
transformCaseFunc: ReturnType<typeof unapply<string>> = stringToLowerCase
|
|
112
|
+
): Record<string, boolean> {
|
|
113
|
+
if (setPrototypeOf) {
|
|
114
|
+
// Make 'in' and truthy checks like Boolean(set.constructor)
|
|
115
|
+
// independent of any properties defined on Object.prototype.
|
|
116
|
+
// Prevent prototype setters from intercepting set as a this value.
|
|
117
|
+
setPrototypeOf(set, null);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!arrayIsArray(array)) {
|
|
121
|
+
return set;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let l = array.length;
|
|
125
|
+
while (l--) {
|
|
126
|
+
let element = array[l];
|
|
127
|
+
|
|
128
|
+
if (typeof element === 'string') {
|
|
129
|
+
const lcElement = transformCaseFunc(element);
|
|
130
|
+
|
|
131
|
+
if (lcElement !== element) {
|
|
132
|
+
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
133
|
+
if (!isFrozen(array)) {
|
|
134
|
+
(array as unknown[])[l] = lcElement;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
element = lcElement;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
set[element as string] = true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return set;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Clean up an array to harden against CSPP
|
|
149
|
+
*
|
|
150
|
+
* @param array - The array to be cleaned.
|
|
151
|
+
* @returns The cleaned version of the array
|
|
152
|
+
*/
|
|
153
|
+
function cleanArray<T>(array: T[]): Array<T | null> {
|
|
154
|
+
for (let index = 0; index < array.length; index++) {
|
|
155
|
+
const isPropertyExist = objectHasOwnProperty(array, index);
|
|
156
|
+
|
|
157
|
+
if (!isPropertyExist) {
|
|
158
|
+
array[index] = null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return array;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Shallow clone an object
|
|
167
|
+
*
|
|
168
|
+
* @param object - The object to be cloned.
|
|
169
|
+
* @returns A new object that copies the original.
|
|
170
|
+
*/
|
|
171
|
+
function clone<T extends Record<string, any>>(object: T): T {
|
|
172
|
+
const newObject = create(null);
|
|
173
|
+
|
|
174
|
+
for (const [property, value] of entries(object)) {
|
|
175
|
+
const isPropertyExist = objectHasOwnProperty(object, property);
|
|
176
|
+
|
|
177
|
+
if (isPropertyExist) {
|
|
178
|
+
if (arrayIsArray(value)) {
|
|
179
|
+
newObject[property] = cleanArray(value);
|
|
180
|
+
} else if (
|
|
181
|
+
value &&
|
|
182
|
+
typeof value === 'object' &&
|
|
183
|
+
value.constructor === Object
|
|
184
|
+
) {
|
|
185
|
+
newObject[property] = clone(value);
|
|
186
|
+
} else {
|
|
187
|
+
newObject[property] = value;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return newObject;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Convert non-node values into strings without depending on direct property access.
|
|
197
|
+
*
|
|
198
|
+
* @param value - The value to stringify.
|
|
199
|
+
* @returns A string representation of the provided value.
|
|
200
|
+
*/
|
|
201
|
+
function stringifyValue(value: unknown): string {
|
|
202
|
+
switch (typeof value) {
|
|
203
|
+
case 'string': {
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
case 'number': {
|
|
208
|
+
return numberToString(value);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
case 'boolean': {
|
|
212
|
+
return booleanToString(value);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
case 'bigint': {
|
|
216
|
+
return bigintToString ? bigintToString(value) : '0';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
case 'symbol': {
|
|
220
|
+
return symbolToString ? symbolToString(value) : 'Symbol()';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
case 'undefined': {
|
|
224
|
+
return objectToString(value);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
case 'function':
|
|
228
|
+
case 'object': {
|
|
229
|
+
if (value === null) {
|
|
230
|
+
return objectToString(value);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const valueAsRecord = value as Record<string, any>;
|
|
234
|
+
const valueToString = lookupGetter(valueAsRecord, 'toString');
|
|
235
|
+
|
|
236
|
+
if (typeof valueToString === 'function') {
|
|
237
|
+
const stringified = valueToString(valueAsRecord);
|
|
238
|
+
|
|
239
|
+
return typeof stringified === 'string'
|
|
240
|
+
? stringified
|
|
241
|
+
: objectToString(stringified);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return objectToString(value);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
default: {
|
|
248
|
+
return objectToString(value);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
|
255
|
+
*
|
|
256
|
+
* @param object - The object to look up the getter function in its prototype chain.
|
|
257
|
+
* @param prop - The property name for which to find the getter function.
|
|
258
|
+
* @returns The getter function found in the prototype chain or a fallback function.
|
|
259
|
+
*/
|
|
260
|
+
function lookupGetter<T extends Record<string, any>>(
|
|
261
|
+
object: T,
|
|
262
|
+
prop: string
|
|
263
|
+
): ReturnType<typeof unapply<any>> | (() => null) {
|
|
264
|
+
while (object !== null) {
|
|
265
|
+
const desc = getOwnPropertyDescriptor(object, prop);
|
|
266
|
+
|
|
267
|
+
if (desc) {
|
|
268
|
+
if (desc.get) {
|
|
269
|
+
return unapply(desc.get);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (typeof desc.value === 'function') {
|
|
273
|
+
return unapply(desc.value);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
object = getPrototypeOf(object);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function fallbackValue(): null {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return fallbackValue;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function isRegex(value: unknown): value is RegExp {
|
|
288
|
+
try {
|
|
289
|
+
regExpTest(value as RegExp, '');
|
|
290
|
+
return true;
|
|
291
|
+
} catch {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export {
|
|
297
|
+
// Array
|
|
298
|
+
arrayForEach,
|
|
299
|
+
arrayIndexOf,
|
|
300
|
+
arrayIsArray,
|
|
301
|
+
arrayLastIndexOf,
|
|
302
|
+
arrayPop,
|
|
303
|
+
arrayPush,
|
|
304
|
+
arraySlice,
|
|
305
|
+
arraySplice,
|
|
306
|
+
// Object
|
|
307
|
+
entries,
|
|
308
|
+
freeze,
|
|
309
|
+
getPrototypeOf,
|
|
310
|
+
getOwnPropertyDescriptor,
|
|
311
|
+
isFrozen,
|
|
312
|
+
setPrototypeOf,
|
|
313
|
+
seal,
|
|
314
|
+
clone,
|
|
315
|
+
create,
|
|
316
|
+
objectHasOwnProperty,
|
|
317
|
+
objectToString,
|
|
318
|
+
// RegExp
|
|
319
|
+
regExpTest,
|
|
320
|
+
isRegex,
|
|
321
|
+
// String
|
|
322
|
+
stringIndexOf,
|
|
323
|
+
stringMatch,
|
|
324
|
+
stringReplace,
|
|
325
|
+
stringToLowerCase,
|
|
326
|
+
stringToString,
|
|
327
|
+
stringTrim,
|
|
328
|
+
// Other conversion
|
|
329
|
+
stringifyValue,
|
|
330
|
+
// Errors
|
|
331
|
+
typeErrorCreate,
|
|
332
|
+
// Other
|
|
333
|
+
lookupGetter,
|
|
334
|
+
addToSet,
|
|
335
|
+
// Reflect
|
|
336
|
+
unapply,
|
|
337
|
+
unconstruct,
|
|
338
|
+
};
|