22
22
* @property {boolean } [allowComments] Whether to allow comments
23
23
* @property {boolean } [allowDoctypes] Whether to allow doctypes
24
24
*
25
- * @typedef {(schema: Schema, value: unknown , node: Node , stack: Array.<string>) => unknown } Handler
25
+ * @typedef {(schema: Schema, value: any , node: any , stack: Array.<string>) => unknown } Handler
26
26
* @typedef {Object.<string, Handler> } NodeDefinition
27
- * @typedef {((schema: Schema, node: Node) => NodeDefinition) } NodeDefinitionGetter
27
+ * @typedef {((schema: Schema, node: Node) => NodeDefinition|undefined ) } NodeDefinitionGetter
28
28
* @typedef {Object.<string, NodeDefinition|NodeDefinitionGetter> } NodeSchema
29
29
*/
30
30
@@ -68,7 +68,7 @@ export function sanitize(node, schema) {
68
68
if ( replace . length === 1 ) {
69
69
ctx = replace [ 0 ]
70
70
} else {
71
- // @ts -ignore Assume `root` is not a child.
71
+ // @ts -expect-error Assume `root` is not a child.
72
72
ctx . children = replace
73
73
}
74
74
} else {
@@ -86,17 +86,18 @@ export function sanitize(node, schema) {
86
86
* @param {Schema } schema
87
87
* @param {Node } node
88
88
* @param {Array.<string> } stack
89
- * @returns {Node|Array.<Node>|null }
89
+ * @returns {Node|Array.<Node>|undefined }
90
90
*/
91
91
function one ( schema , node , stack ) {
92
92
const type = node && node . type
93
93
/** @type {Node } */
94
- // @ts -ignore rest of props added later.
94
+ // @ts -expect-error rest of props added later.
95
95
const replacement = { type : node . type }
96
- /** @type {boolean } */
96
+ /** @type {boolean|undefined } */
97
97
let replace
98
98
99
99
if ( own . call ( nodeSchema , type ) ) {
100
+ /** @type {NodeDefinition|NodeDefinitionGetter|undefined } */
100
101
let definition = nodeSchema [ type ]
101
102
102
103
if ( typeof definition === 'function' ) {
@@ -112,14 +113,20 @@ function one(schema, node, stack) {
112
113
113
114
for ( key in allowed ) {
114
115
if ( own . call ( allowed , key ) ) {
116
+ // @ts -expect-error: fine.
117
+ // type-coverage:ignore-next-line
115
118
const result = allowed [ key ] ( schema , node [ key ] , node , stack )
116
119
117
120
// eslint-disable-next-line max-depth
118
121
if ( result === false ) {
119
- replace = null
122
+ replace = undefined
120
123
// Set the non-safe value.
124
+ // @ts -expect-error: fine.
125
+ // type-coverage:ignore-next-line
121
126
replacement [ key ] = node [ key ]
122
127
} else if ( result !== undefined && result !== null ) {
128
+ // @ts -expect-error: fine.
129
+ // type-coverage:ignore-next-line
123
130
replacement [ key ] = result
124
131
}
125
132
}
@@ -132,16 +139,18 @@ function one(schema, node, stack) {
132
139
}
133
140
134
141
return replacement . type === 'element' &&
142
+ schema . strip &&
135
143
! schema . strip . includes ( replacement . tagName )
136
144
? replacement . children
137
- : null
145
+ : undefined
138
146
}
139
147
140
148
/**
141
149
* Sanitize `children`.
142
150
*
143
151
* @type {Handler }
144
152
* @param {Array.<Node> } children
153
+ * @param {Node } node
145
154
* @returns {Array.<Node> }
146
155
*/
147
156
function all ( schema , children , node , stack ) {
@@ -177,12 +186,12 @@ function all(schema, children, node, stack) {
177
186
178
187
/** @type {NodeDefinitionGetter } */
179
188
function handleDoctype ( schema ) {
180
- return schema . allowDoctypes ? { name : handleDoctypeName } : null
189
+ return schema . allowDoctypes ? { name : handleDoctypeName } : undefined
181
190
}
182
191
183
192
/** @type {NodeDefinitionGetter } */
184
193
function handleComment ( schema ) {
185
- return schema . allowComments ? { value : handleCommentValue } : null
194
+ return schema . allowComments ? { value : handleCommentValue } : undefined
186
195
}
187
196
188
197
/**
@@ -196,14 +205,14 @@ function handleComment(schema) {
196
205
function handleProperties ( schema , properties , node , stack ) {
197
206
const name = handleTagName ( schema , node . tagName , node , stack )
198
207
/* c8 ignore next */
208
+ const attrs = schema . attributes || { }
209
+ /* c8 ignore next */
199
210
const reqs = schema . required || { }
200
211
const props = properties || { }
201
212
const allowed = Object . assign (
202
213
{ } ,
203
- toPropertyValueMap ( schema . attributes [ '*' ] ) ,
204
- toPropertyValueMap (
205
- name && own . call ( schema . attributes , name ) ? schema . attributes [ name ] : [ ]
206
- )
214
+ toPropertyValueMap ( attrs [ '*' ] ) ,
215
+ toPropertyValueMap ( name && own . call ( attrs , name ) ? attrs [ name ] : [ ] )
207
216
)
208
217
/** @type {Properties } */
209
218
const result = { }
@@ -259,19 +268,25 @@ function handleDoctypeName() {
259
268
* Sanitize `tagName`.
260
269
*
261
270
* @type {Handler }
271
+ * @param {unknown } tagName
272
+ * @param {Node } _
262
273
* @returns {string|false }
263
274
*/
264
275
function handleTagName ( schema , tagName , _ , stack ) {
265
276
const name = typeof tagName === 'string' ? tagName : ''
266
277
let index = - 1
267
278
268
- if ( ! name || name === '*' || ! schema . tagNames . includes ( name ) ) {
279
+ if (
280
+ ! name ||
281
+ name === '*' ||
282
+ ( schema . tagNames && ! schema . tagNames . includes ( name ) )
283
+ ) {
269
284
return false
270
285
}
271
286
272
287
// Some nodes can break out of their context if they don’t have a certain
273
288
// ancestor.
274
- if ( own . call ( schema . ancestors , name ) ) {
289
+ if ( schema . ancestors && own . call ( schema . ancestors , name ) ) {
275
290
while ( ++ index < schema . ancestors [ name ] . length ) {
276
291
if ( stack . includes ( schema . ancestors [ name ] [ index ] ) ) {
277
292
return name
@@ -288,6 +303,7 @@ function handleTagName(schema, tagName, _, stack) {
288
303
* See <https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments>
289
304
*
290
305
* @type {Handler }
306
+ * @param {unknown } value
291
307
* @returns {string }
292
308
*/
293
309
function handleCommentValue ( _ , value ) {
@@ -301,6 +317,7 @@ function handleCommentValue(_, value) {
301
317
* Sanitize `value`.
302
318
*
303
319
* @type {Handler }
320
+ * @param {unknown } value
304
321
* @returns {string }
305
322
*/
306
323
function handleValue ( _ , value ) {
@@ -311,6 +328,7 @@ function handleValue(_, value) {
311
328
* Allow `value`.
312
329
*
313
330
* @type {Handler }
331
+ * @param {unknown } value
314
332
*/
315
333
function allow ( _ , value ) {
316
334
return value
@@ -334,7 +352,7 @@ function handlePropertyValues(schema, values, prop, definition) {
334
352
const value = handlePropertyValue ( schema , values [ index ] , prop , definition )
335
353
336
354
if ( value !== undefined && value !== null ) {
337
- // @ts -ignore Assume no booleans were in arrays.
355
+ // @ts -expect-error Assume no booleans were in arrays.
338
356
result . push ( value )
339
357
}
340
358
}
@@ -359,7 +377,11 @@ function handlePropertyValue(schema, value, prop, definition) {
359
377
safeProtocol ( schema , value , prop ) &&
360
378
( definition . length === 0 || definition . includes ( value ) )
361
379
) {
362
- return schema . clobber . includes ( prop ) ? schema . clobberPrefix + value : value
380
+ return schema . clobberPrefix &&
381
+ schema . clobber &&
382
+ schema . clobber . includes ( prop )
383
+ ? schema . clobberPrefix + value
384
+ : value
363
385
}
364
386
}
365
387
@@ -377,9 +399,10 @@ function safeProtocol(schema, value, prop) {
377
399
const questionMark = url . indexOf ( '?' )
378
400
const numberSign = url . indexOf ( '#' )
379
401
const slash = url . indexOf ( '/' )
380
- const protocols = own . call ( schema . protocols , prop )
381
- ? schema . protocols [ prop ] . concat ( )
382
- : [ ]
402
+ const protocols =
403
+ schema . protocols && own . call ( schema . protocols , prop )
404
+ ? schema . protocols [ prop ] . concat ( )
405
+ : [ ]
383
406
let index = - 1
384
407
385
408
if (
0 commit comments