UNPKG

7.11 kBTypeScriptView Raw
1/**
2 * Sanitize a tree.
3 *
4 * @param {Readonly<Nodes>} node
5 * Unsafe tree.
6 * @param {Readonly<Schema> | null | undefined} [options]
7 * Configuration (default: `defaultSchema`).
8 * @returns {Nodes}
9 * New, safe tree.
10 */
11export function sanitize(node: Readonly<Nodes>, options?: Readonly<Schema> | null | undefined): Nodes;
12export type Comment = import('hast').Comment;
13export type Doctype = import('hast').Doctype;
14export type Element = import('hast').Element;
15export type ElementContent = import('hast').ElementContent;
16export type Nodes = import('hast').Nodes;
17export type Properties = import('hast').Properties;
18export type Root = import('hast').Root;
19export type RootContent = import('hast').RootContent;
20export type Text = import('hast').Text;
21/**
22 * Definition for a property.
23 */
24export type PropertyDefinition = [string, ...Array<Exclude<Properties[keyof Properties], Array<any>> | RegExp>] | string;
25/**
26 * Schema that defines what nodes and properties are allowed.
27 *
28 * The default schema is `defaultSchema`, which follows how GitHub cleans.
29 * If any top-level key is missing in the given schema, the corresponding
30 * value of the default schema is used.
31 *
32 * To extend the standard schema with a few changes, clone `defaultSchema`
33 * like so:
34 *
35 * ```js
36 * import deepmerge from 'deepmerge'
37 * import {h} from 'hastscript'
38 * import {defaultSchema, sanitize} from 'hast-util-sanitize'
39 *
40 * // This allows `className` on all elements.
41 * const schema = deepmerge(defaultSchema, {attributes: {'*': ['className']}})
42 *
43 * const tree = sanitize(h('div', {className: ['foo']}), schema)
44 *
45 * // `tree` still has `className`.
46 * console.log(tree)
47 * // {
48 * // type: 'element',
49 * // tagName: 'div',
50 * // properties: {className: ['foo']},
51 * // children: []
52 * // }
53 * ```
54 */
55export type Schema = {
56 /**
57 * Whether to allow comment nodes (default: `false`).
58 *
59 * For example:
60 *
61 * ```js
62 * allowComments: true
63 * ```
64 */
65 allowComments?: boolean | null | undefined;
66 /**
67 * Whether to allow doctype nodes (default: `false`).
68 *
69 * For example:
70 *
71 * ```js
72 * allowDoctypes: true
73 * ```
74 */
75 allowDoctypes?: boolean | null | undefined;
76 /**
77 * Map of tag names to a list of tag names which are required ancestors
78 * (default: `defaultSchema.ancestors`).
79 *
80 * Elements with these tag names will be ignored if they occur outside of one
81 * of their allowed parents.
82 *
83 * For example:
84 *
85 * ```js
86 * ancestors: {
87 * tbody: ['table'],
88 * // …
89 * tr: ['table']
90 * }
91 * ```
92 */
93 ancestors?: Record<string, Array<string>> | null | undefined;
94 /**
95 * Map of tag names to allowed property names (default:
96 * `defaultSchema.attributes`).
97 *
98 * The special key `'*'` as a tag name defines property names allowed on all
99 * elements.
100 *
101 * The special value `'data*'` as a property name can be used to allow all
102 * `data` properties.
103 *
104 * For example:
105 *
106 * ```js
107 * attributes: {
108 * 'ariaDescribedBy', 'ariaLabel', 'ariaLabelledBy', …, 'href'
109 * // …
110 * '*': [
111 * 'abbr',
112 * 'accept',
113 * 'acceptCharset',
114 * // …
115 * 'vAlign',
116 * 'value',
117 * 'width'
118 * ]
119 * }
120 * ```
121 *
122 * Instead of a single string in the array, which allows any property value
123 * for the field, you can use an array to allow several values.
124 * For example, `input: ['type']` allows `type` set to any value on `input`s.
125 * But `input: [['type', 'checkbox', 'radio']]` allows `type` when set to
126 * `'checkbox'` or `'radio'`.
127 *
128 * You can use regexes, so for example `span: [['className', /^hljs-/]]`
129 * allows any class that starts with `hljs-` on `span`s.
130 *
131 * When comma- or space-separated values are used (such as `className`), each
132 * value in is checked individually.
133 * For example, to allow certain classes on `span`s for syntax highlighting,
134 * use `span: [['className', 'number', 'operator', 'token']]`.
135 * This will allow `'number'`, `'operator'`, and `'token'` classes, but drop
136 * others.
137 */
138 attributes?: Record<string, Array<PropertyDefinition>> | null | undefined;
139 /**
140 * List of property names that clobber (default: `defaultSchema.clobber`).
141 *
142 * For example:
143 *
144 * ```js
145 * clobber: ['ariaDescribedBy', 'ariaLabelledBy', 'id', 'name']
146 * ```
147 */
148 clobber?: Array<string> | null | undefined;
149 /**
150 * Prefix to use before clobbering properties (default:
151 * `defaultSchema.clobberPrefix`).
152 *
153 * For example:
154 *
155 * ```js
156 * clobberPrefix: 'user-content-'
157 * ```
158 */
159 clobberPrefix?: string | null | undefined;
160 /**
161 * Map of *property names* to allowed protocols (default:
162 * `defaultSchema.protocols`).
163 *
164 * This defines URLs that are always allowed to have local URLs (relative to
165 * the current website, such as `this`, `#this`, `/this`, or `?this`), and
166 * only allowed to have remote URLs (such as `https://example.com`) if they
167 * use a known protocol.
168 *
169 * For example:
170 *
171 * ```js
172 * protocols: {
173 * cite: ['http', 'https'],
174 * // …
175 * src: ['http', 'https']
176 * }
177 * ```
178 */
179 protocols?: Record<string, Array<string> | null | undefined> | null | undefined;
180 /**
181 * Map of tag names to required property names with a default value
182 * (default: `defaultSchema.required`).
183 *
184 * This defines properties that must be set.
185 * If a field does not exist (after the element was made safe), these will be
186 * added with the given value.
187 *
188 * For example:
189 *
190 * ```js
191 * required: {
192 * input: {disabled: true, type: 'checkbox'}
193 * }
194 * ```
195 *
196 * > 👉 **Note**: properties are first checked based on `schema.attributes`,
197 * > then on `schema.required`.
198 * > That means properties could be removed by `attributes` and then added
199 * > again with `required`.
200 */
201 required?: Record<string, Record<string, Properties[keyof Properties]>> | null | undefined;
202 /**
203 * List of tag names to strip from the tree (default: `defaultSchema.strip`).
204 *
205 * By default, unsafe elements (those not in `schema.tagNames`) are replaced
206 * by what they contain.
207 * This option can drop their contents.
208 *
209 * For example:
210 *
211 * ```js
212 * strip: ['script']
213 * ```
214 */
215 strip?: Array<string> | null | undefined;
216 /**
217 * List of allowed tag names (default: `defaultSchema.tagNames`).
218 *
219 * For example:
220 *
221 * ```js
222 * tagNames: [
223 * 'a',
224 * 'b',
225 * // …
226 * 'ul',
227 * 'var'
228 * ]
229 * ```
230 */
231 tagNames?: Array<string> | null | undefined;
232};
233/**
234 * Info passed around.
235 */
236export type State = {
237 /**
238 * Schema.
239 */
240 schema: Readonly<Schema>;
241 /**
242 * Tag names of ancestors.
243 */
244 stack: Array<string>;
245};