|
1 | 1 | /** |
2 | 2 | * @author Titus Wormer |
3 | | - * @copyright 2015 Titus Wormer |
| 3 | + * @copyright 2016 Titus Wormer |
4 | 4 | * @license MIT |
5 | | - * @module mdast:to-hast |
6 | | - * @fileoverview Transform MDAST to HAST. |
| 5 | + * @module hast:to-html |
| 6 | + * @fileoverview Stringify HAST to HTML. |
7 | 7 | */ |
8 | 8 |
|
9 | 9 | 'use strict'; |
10 | 10 |
|
11 | 11 | /* eslint-env commonjs */ |
12 | 12 |
|
13 | | -/* Dependencies. */ |
14 | | -var voids = require('html-void-elements'); |
15 | | -var spaces = require('space-separated-tokens').stringify; |
16 | | -var commas = require('comma-separated-tokens').stringify; |
17 | | -var information = require('property-information'); |
18 | | -var entities = require('stringify-entities'); |
19 | | -var kebab = require('kebab-case'); |
20 | | - |
21 | | -/* Methods. */ |
22 | | -var has = Object.prototype.hasOwnProperty; |
23 | | - |
24 | | -/* Handlers. */ |
25 | | -var handlers = {}; |
26 | | - |
27 | | -handlers.root = root; |
28 | | -handlers.element = element; |
29 | | -handlers.directive = directive; |
30 | | -handlers.comment = comment; |
31 | | -handlers.characterData = characterData; |
32 | | -handlers.text = text; |
33 | | -handlers.raw = raw; |
34 | | - |
35 | | -/** |
36 | | - * Check if content of `node` should be escaped. |
37 | | - * |
38 | | - * @param {Node} node - Node to check. |
39 | | - * @return {boolean} - Whether `node` should be escaped. |
40 | | - */ |
41 | | -function isLiteral(node) { |
42 | | - return node && (node.tagName === 'script' || node.tagName === 'style'); |
43 | | -} |
44 | | - |
45 | | -/** |
46 | | - * Stringify one attribute. |
47 | | - * |
48 | | - * @param {Object} ctx - Stringify configuration. |
49 | | - * @param {string} name - Attribute name. |
50 | | - * @param {*} value - Attribute value. |
51 | | - * @param {boolean} [isAttribute] - Whether `name` is |
52 | | - * an attribute. |
53 | | - * @return {string} - Stringified attribute. |
54 | | - */ |
55 | | -function attribute(ctx, name, value) { |
56 | | - var info = information(name) || {}; |
57 | | - var options = ctx.entities; |
58 | | - |
59 | | - if ( |
60 | | - (value === null || value === undefined || value !== value) || |
61 | | - (!value && info.boolean) || |
62 | | - (value === false && info.overloadedBoolean) |
63 | | - ) { |
64 | | - return ''; |
65 | | - } |
66 | | - |
67 | | - name = info.name || kebab(name); |
68 | | - |
69 | | - if ( |
70 | | - info.boolean || |
71 | | - (value === true && info.overloadedBoolean) |
72 | | - ) { |
73 | | - return entities(name, options); |
74 | | - } |
75 | | - |
76 | | - if (typeof value === 'object' && 'length' in value) { |
77 | | - value = (info.commaSeparated ? commas : spaces)(value); |
78 | | - } |
79 | | - |
80 | | - return entities(name, options) + '="' + |
81 | | - entities(String(value), options) + '"'; |
82 | | -} |
83 | | - |
84 | | -/** |
85 | | - * Stringify all attributes. |
86 | | - * |
87 | | - * @param {Object} ctx - Stringify configuration. |
88 | | - * @param {Object} props - Attributes. |
89 | | - * @return {string} - Stringified attributes. |
90 | | - */ |
91 | | -function attributes(ctx, props) { |
92 | | - var values = []; |
93 | | - var key; |
94 | | - var value; |
95 | | - var result; |
96 | | - |
97 | | - for (key in props) { |
98 | | - value = props[key]; |
99 | | - |
100 | | - if (value === null || value === undefined) { |
101 | | - continue; |
102 | | - } |
103 | | - |
104 | | - result = attribute(ctx, key, value); |
105 | | - |
106 | | - if (result) { |
107 | | - values.push(result); |
108 | | - } |
109 | | - } |
110 | | - |
111 | | - return values.join(' '); |
112 | | -} |
113 | | - |
114 | | -/** |
115 | | - * Stringify all children of `parent`. |
116 | | - * |
117 | | - * @param {Object} ctx - Stringify configuration. |
118 | | - * @param {HastNode} parent - Parent. |
119 | | - * @return {string} - Stringified children. |
120 | | - */ |
121 | | -function all(ctx, parent) { |
122 | | - var children = parent && parent.children; |
123 | | - var length = children && children.length; |
124 | | - var index = -1; |
125 | | - var results = []; |
126 | | - |
127 | | - while (++index < length) { |
128 | | - results[index] = one(ctx, children[index], parent); |
129 | | - } |
130 | | - |
131 | | - return results.join(''); |
132 | | -} |
133 | | - |
134 | | -/** |
135 | | - * Stringify `node`. |
136 | | - * |
137 | | - * @param {Object} ctx - Stringify configuration. |
138 | | - * @param {HastNode} node - Node. |
139 | | - * @param {HastNode?} [parent] - Parent of `node`, when |
140 | | - * applicable. |
141 | | - * @return {string} - Stringified `node`. |
142 | | - * @throws {Error} - When `node` cannot be stringified. |
143 | | - */ |
144 | | -function one(ctx, node, parent) { |
145 | | - var type = node && node.type; |
146 | | - |
147 | | - if (!type) { |
148 | | - throw new Error('Expected node, not `' + node + '`'); |
149 | | - } |
150 | | - |
151 | | - if (!has.call(handlers, type)) { |
152 | | - throw new Error('Cannot compile unknown node `' + type + '`'); |
153 | | - } |
154 | | - |
155 | | - return handlers[type](ctx, node, parent); |
156 | | -} |
157 | | - |
158 | | -/** |
159 | | - * Stringify a directive `node`. |
160 | | - * |
161 | | - * @param {Object} ctx - Stringify configuration. |
162 | | - * @param {HastDirective} node - Node. |
163 | | - * @return {string} - Stringified `node`. |
164 | | - */ |
165 | | -function directive(ctx, node) { |
166 | | - return '<' + node.value + '>'; |
167 | | -} |
168 | | - |
169 | | -/** |
170 | | - * Stringify a comment `node`. |
171 | | - * |
172 | | - * @param {Object} ctx - Stringify configuration. |
173 | | - * @param {HastComment} node - Node. |
174 | | - * @return {string} - Stringified `node`. |
175 | | - */ |
176 | | -function comment(ctx, node) { |
177 | | - return '<!--' + node.value + '-->'; |
178 | | -} |
179 | | - |
180 | | -/** |
181 | | - * Stringify `raw`. |
182 | | - * |
183 | | - * @param {Object} ctx - Stringify configuration. |
184 | | - * @param {HastCharacterData} node - Node. |
185 | | - * @return {string} - Stringified `node`. |
186 | | - */ |
187 | | -function raw(ctx, node) { |
188 | | - return ctx.dangerous ? node.value : text(ctx, node); |
189 | | -} |
190 | | - |
191 | | -/** |
192 | | - * Stringify a character-data `node`. |
193 | | - * |
194 | | - * @param {Object} ctx - Stringify configuration. |
195 | | - * @param {HastCharacterData} node - Node. |
196 | | - * @return {string} - Stringified `node`. |
197 | | - */ |
198 | | -function characterData(ctx, node) { |
199 | | - return '<![CDATA[' + node.value + ']]>'; |
200 | | -} |
201 | | - |
202 | | -/** |
203 | | - * Stringify a text `node`. |
204 | | - * |
205 | | - * @param {Object} ctx - Stringify configuration. |
206 | | - * @param {HastText} node - Node. |
207 | | - * @param {HastParent?} [parent] - Parent of `node`. |
208 | | - * @return {string} - Stringified `node`. |
209 | | - */ |
210 | | -function text(ctx, node, parent) { |
211 | | - return isLiteral(parent) ? node.value : entities(node.value, ctx.entities); |
212 | | -} |
213 | | - |
214 | | -/** |
215 | | - * Stringify a root `node`. |
216 | | - * |
217 | | - * @param {Object} ctx - Stringify configuration. |
218 | | - * @param {HastRoot} node - Node. |
219 | | - * @return {string} - Stringified `node`. |
220 | | - */ |
221 | | -function root(ctx, node) { |
222 | | - return all(ctx, node); |
223 | | -} |
224 | | - |
225 | | -/** |
226 | | - * Stringify an element `node`. |
227 | | - * |
228 | | - * @param {Object} ctx - Stringify configuration. |
229 | | - * @param {HastElement} node - Node. |
230 | | - * @return {string} - Stringified `node`. |
231 | | - */ |
232 | | -function element(ctx, node) { |
233 | | - var attrs = attributes(ctx, node.properties); |
234 | | - var content = all(ctx, node); |
235 | | - var name = node.tagName; |
236 | | - var value = '<' + name; |
237 | | - var selfClosing = ctx.voids.indexOf(name.toLowerCase()) !== -1; |
238 | | - |
239 | | - if (attrs) { |
240 | | - value += ' ' + attrs; |
241 | | - } |
242 | | - |
243 | | - if (selfClosing && ctx.closeSelfClosing) { |
244 | | - value += ' /'; |
245 | | - } |
246 | | - |
247 | | - value += '>' + content; |
248 | | - |
249 | | - if (!selfClosing) { |
250 | | - value += '</' + name + '>'; |
251 | | - } |
252 | | - |
253 | | - return value; |
254 | | -} |
255 | | - |
256 | | -/** |
257 | | - * Wrapper. |
258 | | - * |
259 | | - * @param {HastNode} node - Node. |
260 | | - * @param {Object} [options] - Configuration. |
261 | | - * @return {string} - Stringified `node`. |
262 | | - */ |
263 | | -function wrapper(node, options) { |
264 | | - var settings = options || {}; |
265 | | - var dangerous = settings.allowDangerousHTML; |
266 | | - |
267 | | - return one({ |
268 | | - dangerous: dangerous, |
269 | | - voids: settings.voids || voids.concat(), |
270 | | - entities: settings.entities || { escapeOnly: true }, |
271 | | - closeSelfClosing: settings.closeSelfClosing |
272 | | - }, node); |
273 | | -} |
274 | | - |
275 | 13 | /* Expose. */ |
276 | | -module.exports = wrapper; |
| 14 | +module.exports = require('./lib/index.js'); |
0 commit comments