@adobe/helix-html-pipeline 1.1.3 → 1.3.0
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/CHANGELOG.md +21 -0
- package/package.json +12 -10
- package/src/PipelineContent.d.ts +8 -7
- package/src/PipelineContent.js +2 -0
- package/src/PipelineResponse.d.ts +6 -1
- package/src/PipelineState.d.ts +3 -1
- package/src/PipelineState.js +1 -0
- package/src/forms-pipe.js +160 -0
- package/src/html-pipe.js +7 -0
- package/src/index.d.ts +13 -0
- package/src/index.js +2 -0
- package/src/options-pipe.js +37 -0
- package/src/steps/add-heading-ids.js +14 -13
- package/src/steps/create-page-blocks.js +28 -27
- package/src/steps/create-pictures.js +16 -12
- package/src/steps/extract-metadata.js +61 -44
- package/src/steps/fix-sections.js +8 -9
- package/src/steps/get-metadata.js +5 -4
- package/src/steps/make-html.js +3 -14
- package/src/steps/removeHlxProps.js +9 -10
- package/src/steps/render.js +68 -116
- package/src/steps/rewrite-blob-images.js +6 -24
- package/src/steps/rewrite-icons.js +30 -44
- package/src/steps/stringify-response.js +11 -11
- package/src/steps/utils.js +26 -4
- package/src/utils/{table-handler.js → hast-utils.js} +13 -15
- package/src/utils/heading-handler.js +11 -24
- package/src/utils/mdast-to-hast.js +60 -0
- package/src/utils/path.js +4 -1
- package/src/utils/section-handler.js +6 -4
- package/src/utils/hast-util-to-dom.js +0 -190
- package/src/utils/icon-handler.js +0 -40
- package/src/utils/link-handler.js +0 -25
- package/src/utils/mdast-to-vdom.js +0 -323
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
12
|
/* eslint-disable no-param-reassign */
|
|
13
|
+
import { h, s } from 'hastscript';
|
|
14
|
+
import { CONTINUE, visit } from 'unist-util-visit';
|
|
14
15
|
|
|
15
16
|
const REGEXP_ICON = /:(#?[a-zA-Z_-]+[a-zA-Z0-9]*):/g;
|
|
16
17
|
|
|
@@ -18,55 +19,48 @@ const REGEXP_ICON = /:(#?[a-zA-Z_-]+[a-zA-Z0-9]*):/g;
|
|
|
18
19
|
* Create a <img> or <svg> icon dom element eg:
|
|
19
20
|
* `<img class="icon icon-smile" src="/icons/smile.svg"/>` or
|
|
20
21
|
* `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-smile"><use href="/icons.svg#smile"></use></svg>`
|
|
21
|
-
* @param {Document} document the dom document
|
|
22
22
|
* @param {string} value the identifier of the icon
|
|
23
23
|
*/
|
|
24
|
-
function createIcon(
|
|
25
|
-
|
|
24
|
+
function createIcon(value) {
|
|
25
|
+
let name = encodeURIComponent(value);
|
|
26
26
|
|
|
27
27
|
// icon starts with #
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
$use.setAttribute('href', `/icons.svg#${value}`);
|
|
34
|
-
$el.appendChild($use);
|
|
35
|
-
return $el;
|
|
28
|
+
if (name.startsWith('%23')) {
|
|
29
|
+
name = name.substring(3);
|
|
30
|
+
return s('svg', { class: `icon icon-${name}` }, [
|
|
31
|
+
s('use', { href: `/icons.svg#${name}` }),
|
|
32
|
+
]);
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
// create normal image
|
|
39
|
-
|
|
40
|
-
$el.classList.add('icon', `icon-${value}`);
|
|
41
|
-
$el.setAttribute('src', `/icons/${value}.svg`);
|
|
42
|
-
$el.setAttribute('alt', `${value} icon`);
|
|
43
|
-
return $el;
|
|
36
|
+
return h('img', { class: `icon icon-${name}`, src: `/icons/${name}.svg`, alt: `${name} icon` });
|
|
44
37
|
}
|
|
45
38
|
|
|
46
39
|
/**
|
|
47
40
|
* Rewrite :icons:
|
|
48
41
|
*
|
|
49
|
-
* @
|
|
42
|
+
* @type PipelineStep
|
|
43
|
+
* @param content
|
|
50
44
|
*/
|
|
51
|
-
function
|
|
52
|
-
const {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
let textNode;
|
|
59
|
-
// eslint-disable-next-line no-cond-assign
|
|
60
|
-
while (textNode = nodeIterator.nextNode()) {
|
|
61
|
-
const text = textNode.data;
|
|
45
|
+
export default function rewrite({ content }) {
|
|
46
|
+
const { hast } = content;
|
|
47
|
+
visit(hast, (node, idx, parent) => {
|
|
48
|
+
if (node.type !== 'text') {
|
|
49
|
+
return CONTINUE;
|
|
50
|
+
}
|
|
51
|
+
const text = node.value;
|
|
62
52
|
let lastIdx = 0;
|
|
63
53
|
for (const match of text.matchAll(REGEXP_ICON)) {
|
|
64
54
|
const [matched, icon] = match;
|
|
65
55
|
const before = text.substring(lastIdx, match.index);
|
|
66
56
|
if (before) {
|
|
67
|
-
textNode.parentNode.insertBefore(document.createTextNode(before), textNode);
|
|
57
|
+
// textNode.parentNode.insertBefore(document.createTextNode(before), textNode);
|
|
58
|
+
parent.children.splice(idx, 0, { type: 'text', value: before });
|
|
59
|
+
idx += 1;
|
|
68
60
|
}
|
|
69
|
-
textNode.parentNode.insertBefore(createIcon(document, icon), textNode);
|
|
61
|
+
// textNode.parentNode.insertBefore(createIcon(document, icon), textNode);
|
|
62
|
+
parent.children.splice(idx, 0, createIcon(icon));
|
|
63
|
+
idx += 1;
|
|
70
64
|
lastIdx = match.index + matched.length;
|
|
71
65
|
}
|
|
72
66
|
|
|
@@ -74,20 +68,12 @@ function rewriteIcons(document) {
|
|
|
74
68
|
// there is still some text left
|
|
75
69
|
const after = text.substring(lastIdx);
|
|
76
70
|
if (after) {
|
|
77
|
-
|
|
71
|
+
node.value = after;
|
|
78
72
|
} else {
|
|
79
|
-
|
|
73
|
+
parent.children.splice(idx, 1);
|
|
74
|
+
idx -= 1;
|
|
80
75
|
}
|
|
81
76
|
}
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* @type PipelineStep
|
|
87
|
-
* @param content
|
|
88
|
-
*/
|
|
89
|
-
export default function rewrite({ content }) {
|
|
90
|
-
if (content.document) {
|
|
91
|
-
rewriteIcons(content.document);
|
|
92
|
-
}
|
|
77
|
+
return idx + 1;
|
|
78
|
+
});
|
|
93
79
|
}
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
+
import { toHtml } from 'hast-util-to-html';
|
|
13
|
+
// import rehypeFormat from 'rehype-format';
|
|
14
|
+
import rehypeMinifyWhitespace from 'rehype-minify-whitespace';
|
|
12
15
|
/**
|
|
13
16
|
* Serializes the response document to HTML
|
|
14
17
|
* @param {PipelineState} state
|
|
@@ -25,15 +28,12 @@ export default function stringify(state, req, res) {
|
|
|
25
28
|
if (!doc) {
|
|
26
29
|
throw Error('no response document');
|
|
27
30
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} else {
|
|
37
|
-
throw Error(`unexpected context.response.document: ${doc}`);
|
|
38
|
-
}
|
|
31
|
+
|
|
32
|
+
// TODO: for the next breaking release, pretty print the HTML with rehypeFormat.
|
|
33
|
+
// TODO: but for backward compatibility, output all on 1 line.
|
|
34
|
+
// rehypeFormat()(doc);
|
|
35
|
+
rehypeMinifyWhitespace()(doc);
|
|
36
|
+
res.body = toHtml(doc, {
|
|
37
|
+
upperDoctype: true,
|
|
38
|
+
});
|
|
39
39
|
}
|
package/src/steps/utils.js
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
const AZURE_BLOB_REGEXP = /^https:\/\/hlx\.blob\.core\.windows\.net\/external\//;
|
|
14
|
+
|
|
15
|
+
const MEDIA_BLOB_REGEXP = /^https:\/\/.*\.hlx3?\.(live|page)\/media_.*/;
|
|
16
|
+
|
|
13
17
|
/**
|
|
14
18
|
* Returns the original host name from the request to the outer CDN.
|
|
15
19
|
* @param {object} headers The request headers
|
|
@@ -51,12 +55,12 @@ export function makeCanonicalHtmlUrl(url) {
|
|
|
51
55
|
/**
|
|
52
56
|
* Wraps the content of $node with a new $parent node and then appends the new parent to the node.
|
|
53
57
|
*
|
|
54
|
-
* @param {
|
|
55
|
-
* @param {
|
|
58
|
+
* @param {Element} $node The content of the node to wrap
|
|
59
|
+
* @param {Element} $parent The new parent node
|
|
56
60
|
*/
|
|
57
61
|
export function wrapContent($parent, $node) {
|
|
58
|
-
$parent.
|
|
59
|
-
$node.
|
|
62
|
+
$parent.children.push(...$node.children);
|
|
63
|
+
$node.children = [$parent];
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
/**
|
|
@@ -143,3 +147,21 @@ export function getAbsoluteUrl(headers, url) {
|
|
|
143
147
|
}
|
|
144
148
|
return resolveUrl(`https://${getOriginalHost(headers)}/`, url);
|
|
145
149
|
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Rewrite a blog image link. if the link is not a blog image link, it is returned as-is.
|
|
153
|
+
* @param {string} src the image source
|
|
154
|
+
* @returns {string} the new source
|
|
155
|
+
*/
|
|
156
|
+
export function rewriteBlobLink(src) {
|
|
157
|
+
if (AZURE_BLOB_REGEXP.test(src)) {
|
|
158
|
+
const { pathname, hash } = new URL(src);
|
|
159
|
+
const filename = pathname.split('/').pop();
|
|
160
|
+
const extension = hash.split('?').shift().split('.').pop() || 'jpg';
|
|
161
|
+
return `./media_${filename}.${extension}`;
|
|
162
|
+
} else if (MEDIA_BLOB_REGEXP.test(src)) {
|
|
163
|
+
const { pathname } = new URL(src);
|
|
164
|
+
return `.${pathname}`; // don't append fragment until picture tag supports width/height
|
|
165
|
+
}
|
|
166
|
+
return src;
|
|
167
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -9,19 +9,17 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { EXIT, visit } from 'unist-util-visit';
|
|
13
13
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return fallback(h, node);
|
|
26
|
-
};
|
|
14
|
+
export function replace(tree, oldNode, newNode) {
|
|
15
|
+
// $table.parentNode.replaceChild($div, $table);
|
|
16
|
+
// replace child in parent
|
|
17
|
+
visit(tree, oldNode, (node, idx, parent) => {
|
|
18
|
+
parent.children[idx] = newNode;
|
|
19
|
+
return EXIT;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function childNodes(node) {
|
|
24
|
+
return node.children.filter((n) => n.type === 'element');
|
|
27
25
|
}
|
|
@@ -9,34 +9,21 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { defaultHandlers } from 'mdast-util-to-hast';
|
|
13
13
|
import { toString } from 'mdast-util-to-string';
|
|
14
14
|
import strip from 'strip-markdown';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
*Injects heading identifiers during the MDAST to VDOM transformation.
|
|
18
18
|
*/
|
|
19
|
-
export default
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
constructor(slugger) {
|
|
24
|
-
this.slugger = slugger;
|
|
25
|
-
}
|
|
19
|
+
export default function heading(slugger) {
|
|
20
|
+
return function handler(h, node) {
|
|
21
|
+
// Prepare the heading id
|
|
22
|
+
const headingIdentifier = slugger.slug(toString(strip()(node)).trim());
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Prepare the heading id
|
|
33
|
-
const headingIdentifier = this.slugger.slug(toString(strip()(node)));
|
|
34
|
-
|
|
35
|
-
// Inject the id after transformation
|
|
36
|
-
const n = { ...node };
|
|
37
|
-
const el = fallback(h, n);
|
|
38
|
-
el.properties.id = el.properties.id || headingIdentifier;
|
|
39
|
-
return el;
|
|
40
|
-
};
|
|
41
|
-
}
|
|
24
|
+
// Inject the id after transformation
|
|
25
|
+
const el = defaultHandlers.heading(h, node);
|
|
26
|
+
el.properties.id = el.properties.id || headingIdentifier;
|
|
27
|
+
return el;
|
|
28
|
+
};
|
|
42
29
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2018 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
import { toHast as mdast2hast, defaultHandlers } from 'mdast-util-to-hast';
|
|
13
|
+
import { raw } from 'hast-util-raw';
|
|
14
|
+
import { visit, CONTINUE } from 'unist-util-visit';
|
|
15
|
+
|
|
16
|
+
import section from './section-handler.js';
|
|
17
|
+
import heading from './heading-handler.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Turns the MDAST into a HAST structure
|
|
21
|
+
* @param {Node} mdast mdast tree
|
|
22
|
+
* @param {GithubSlugger} slugger github slugger for the heading ids
|
|
23
|
+
* @returns {Root} the HAST document
|
|
24
|
+
*/
|
|
25
|
+
export default function getHast(mdast, slugger) {
|
|
26
|
+
const hast = mdast2hast(mdast, {
|
|
27
|
+
handlers: {
|
|
28
|
+
...defaultHandlers,
|
|
29
|
+
section: section(),
|
|
30
|
+
heading: heading(slugger),
|
|
31
|
+
},
|
|
32
|
+
allowDangerousHtml: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// TODO: remove for cleanup
|
|
36
|
+
// the following recreates a bug with the old vdom transformer that would create a
|
|
37
|
+
// <p></p> for all raw `<p>` before a block with void elements.
|
|
38
|
+
visit(hast, (node, idx, parent) => {
|
|
39
|
+
if (node.type !== 'raw' || node.value !== '<p>') {
|
|
40
|
+
return CONTINUE;
|
|
41
|
+
}
|
|
42
|
+
// check if any other raw empty nodes follow until the </p>
|
|
43
|
+
for (let i = idx + 1; i < parent.children.length; i += 1) {
|
|
44
|
+
const next = parent.children[i];
|
|
45
|
+
if (next.type === 'raw') {
|
|
46
|
+
if (next.value === '</p>') {
|
|
47
|
+
return i + 1;
|
|
48
|
+
}
|
|
49
|
+
if (next.value === '<br>' || next.value.startsWith('<img ')) {
|
|
50
|
+
node.value = '<p></p>';
|
|
51
|
+
return i + 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/* c8 ignore next */
|
|
56
|
+
return CONTINUE;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return raw(hast);
|
|
60
|
+
}
|
package/src/utils/path.js
CHANGED
|
@@ -20,7 +20,10 @@ export function getPathInfo(path) {
|
|
|
20
20
|
// eslint-disable-next-line no-param-reassign
|
|
21
21
|
path = '/';
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
if (path.match(/\/\/+/)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const segs = path.split('/');
|
|
24
27
|
segs.shift(); // remove _emptyness_ before first slash
|
|
25
28
|
if (segs.length < 1) {
|
|
26
29
|
return null;
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import { all } from 'mdast-util-to-hast';
|
|
13
|
-
import { wrap } from 'mdast-util-to-hast/lib/wrap.js';
|
|
14
13
|
|
|
15
14
|
const HELIX_NAMESPACE = 'hlx-';
|
|
16
15
|
const DEFAULT_SECTION_TAG = 'div';
|
|
@@ -61,9 +60,12 @@ export default function sectionHandler() {
|
|
|
61
60
|
|
|
62
61
|
const tagName = getTagName(n);
|
|
63
62
|
const props = getAttributes(n);
|
|
64
|
-
props.
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
props.className = [DEFAULT_SECTION_CLASS];
|
|
64
|
+
if (props.class) {
|
|
65
|
+
props.className.push(...props.class.split(/\s+/));
|
|
66
|
+
}
|
|
67
|
+
delete props.class;
|
|
68
|
+
const children = all(h, n);
|
|
67
69
|
return h(node, tagName, props, children);
|
|
68
70
|
};
|
|
69
71
|
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* (ISC License)
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) 2018 Keith McKnight <keith@mcknig.ht>
|
|
5
|
-
*
|
|
6
|
-
* Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
7
|
-
* with or without fee is hereby granted, provided that the above copyright notice
|
|
8
|
-
* and this permission notice appear in all copies.
|
|
9
|
-
*
|
|
10
|
-
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
11
|
-
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
12
|
-
* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
13
|
-
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
14
|
-
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
15
|
-
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
16
|
-
* THIS SOFTWARE.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
// This was copied from https://github.com/syntax-tree/hast-util-to-dom/blob/master/src/index.js
|
|
20
|
-
// and adapted so that it can be used with JSDOM
|
|
21
|
-
// TODO: contribute back to original
|
|
22
|
-
|
|
23
|
-
/* eslint-disable header/header */
|
|
24
|
-
import { find as infoFind, html as infoHtml } from 'property-information';
|
|
25
|
-
|
|
26
|
-
const ns = {
|
|
27
|
-
html: 'http://www.w3.org/1999/xhtml',
|
|
28
|
-
};
|
|
29
|
-
/* istanbul ignore next */
|
|
30
|
-
const wrap = (document) => {
|
|
31
|
-
// Add all children.
|
|
32
|
-
function appendAll(node, children, options) {
|
|
33
|
-
const childrenLength = children.length;
|
|
34
|
-
|
|
35
|
-
for (let i = 0; i < childrenLength; i += 1) {
|
|
36
|
-
// eslint-disable-next-line no-use-before-define
|
|
37
|
-
node.appendChild(transform(children[i], options));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return node;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Create a document.
|
|
44
|
-
function root(node, options) {
|
|
45
|
-
const { fragment, namespace: optionsNamespace } = options;
|
|
46
|
-
const { children = [] } = node;
|
|
47
|
-
const { length: childrenLength } = children;
|
|
48
|
-
|
|
49
|
-
let namespace = optionsNamespace;
|
|
50
|
-
let rootIsDocument = childrenLength === 0;
|
|
51
|
-
|
|
52
|
-
for (let i = 0; i < childrenLength; i += 1) {
|
|
53
|
-
const { tagName, properties = {} } = children[i];
|
|
54
|
-
|
|
55
|
-
/* c8 ignore start */
|
|
56
|
-
if (tagName === 'html') {
|
|
57
|
-
// If we have a root HTML node, we don’t need to render as a fragment.
|
|
58
|
-
rootIsDocument = true;
|
|
59
|
-
|
|
60
|
-
// Take namespace of the first child.
|
|
61
|
-
if (typeof optionsNamespace === 'undefined') {
|
|
62
|
-
namespace = properties.xmlns || ns.html;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/* c8 ignore end */
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// The root node will be a Document, DocumentFragment, or HTMLElement.
|
|
69
|
-
let el;
|
|
70
|
-
|
|
71
|
-
if (rootIsDocument) {
|
|
72
|
-
el = document.implementation.createDocument(namespace, '', null);
|
|
73
|
-
} else if (fragment) {
|
|
74
|
-
el = document.createDocumentFragment();
|
|
75
|
-
} else {
|
|
76
|
-
/* c8 ignore next */
|
|
77
|
-
el = document.createElement('html');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return appendAll(el, children, { fragment, namespace, ...options });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Create a `doctype`.
|
|
84
|
-
function doctype(node) {
|
|
85
|
-
return document.implementation.createDocumentType(
|
|
86
|
-
node.name || 'html',
|
|
87
|
-
node.public || '',
|
|
88
|
-
node.system || '',
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Create a `text`.
|
|
93
|
-
function text(node) {
|
|
94
|
-
return document.createTextNode(node.value);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Create a `comment`.
|
|
98
|
-
function comment(node) {
|
|
99
|
-
return document.createComment(node.value);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Create an `element`.
|
|
103
|
-
function element(node, options) {
|
|
104
|
-
const { namespace } = options;
|
|
105
|
-
// TODO: use `g` in SVG space.
|
|
106
|
-
const { tagName = 'div', properties = {}, children = [] } = node;
|
|
107
|
-
const el = typeof namespace !== 'undefined'
|
|
108
|
-
? document.createElementNS(namespace, tagName)
|
|
109
|
-
: document.createElement(tagName);
|
|
110
|
-
|
|
111
|
-
// Add HTML attributes.
|
|
112
|
-
const props = Object.keys(properties);
|
|
113
|
-
const { length } = props;
|
|
114
|
-
|
|
115
|
-
for (let i = 0; i < length; i += 1) {
|
|
116
|
-
const key = props[i];
|
|
117
|
-
|
|
118
|
-
const {
|
|
119
|
-
attribute,
|
|
120
|
-
property,
|
|
121
|
-
// `mustUseAttribute`,
|
|
122
|
-
mustUseProperty,
|
|
123
|
-
boolean,
|
|
124
|
-
booleanish,
|
|
125
|
-
overloadedBoolean,
|
|
126
|
-
// `number`,
|
|
127
|
-
// `defined`,
|
|
128
|
-
commaSeparated,
|
|
129
|
-
// `spaceSeparated`,
|
|
130
|
-
// `commaOrSpaceSeparated`,
|
|
131
|
-
} = infoFind(infoHtml, key);
|
|
132
|
-
|
|
133
|
-
let value = properties[key];
|
|
134
|
-
|
|
135
|
-
if (Array.isArray(value)) {
|
|
136
|
-
value = value.join(commaSeparated ? ', ' : ' ');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (mustUseProperty) {
|
|
140
|
-
el[property] = value;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (boolean || (overloadedBoolean && typeof value === 'boolean')) {
|
|
144
|
-
if (value) {
|
|
145
|
-
el.setAttribute(attribute, '');
|
|
146
|
-
} else {
|
|
147
|
-
el.removeAttribute(attribute);
|
|
148
|
-
}
|
|
149
|
-
} else if (booleanish) {
|
|
150
|
-
el.setAttribute(attribute, value);
|
|
151
|
-
} else if (value === true) {
|
|
152
|
-
el.setAttribute(attribute, '');
|
|
153
|
-
} else if (value || value === 0 || value === '') {
|
|
154
|
-
el.setAttribute(attribute, value);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return appendAll(el, children, options);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// the raw node is stored in the value directly
|
|
162
|
-
function raw(node) {
|
|
163
|
-
return node.frag;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function transform(node, options) {
|
|
167
|
-
switch (node.type) {
|
|
168
|
-
case 'root':
|
|
169
|
-
return root(node, options);
|
|
170
|
-
case 'text':
|
|
171
|
-
return text(node);
|
|
172
|
-
case 'element':
|
|
173
|
-
return element(node, options);
|
|
174
|
-
case 'doctype':
|
|
175
|
-
return doctype(node);
|
|
176
|
-
case 'comment':
|
|
177
|
-
return comment(node);
|
|
178
|
-
case 'raw':
|
|
179
|
-
return raw(node);
|
|
180
|
-
default:
|
|
181
|
-
return element(node, options);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return transform;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
export default function toDOM(document, hast, options = {}) {
|
|
189
|
-
return wrap(document)(hast, options);
|
|
190
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2019 Adobe. All rights reserved.
|
|
3
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
*
|
|
7
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
-
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
-
* governing permissions and limitations under the License.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Handles `icon` MDAST nodes by converting them into `img` or `<svg>` tags, e.g.
|
|
15
|
-
* `<img class="icon icon-smile" src="/icons/smile.svg"/>` or
|
|
16
|
-
* `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-smile"><use href="/icons.svg#smile"></use></svg>`
|
|
17
|
-
* @param {string} id the identifier of the icon
|
|
18
|
-
*/
|
|
19
|
-
export default function icon() {
|
|
20
|
-
return function handler(h, node) {
|
|
21
|
-
let { value } = node;
|
|
22
|
-
value = encodeURIComponent(value);
|
|
23
|
-
if (value.startsWith('%23')) {
|
|
24
|
-
// icon starts with #
|
|
25
|
-
value = value.substring(3);
|
|
26
|
-
return [h(node, 'svg', {
|
|
27
|
-
xmlns: 'http://www.w3.org/2000/svg',
|
|
28
|
-
className: `icon icon-${value}`,
|
|
29
|
-
}, [h(node, 'use', {
|
|
30
|
-
href: `/icons.svg#${value}`,
|
|
31
|
-
})])];
|
|
32
|
-
} else {
|
|
33
|
-
return [h(node, 'img', {
|
|
34
|
-
className: `icon icon-${value}`,
|
|
35
|
-
src: `/icons/${value}.svg`,
|
|
36
|
-
alt: `${value} icon`,
|
|
37
|
-
})];
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2018 Adobe. All rights reserved.
|
|
3
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
*
|
|
7
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
-
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
-
* governing permissions and limitations under the License.
|
|
11
|
-
*/
|
|
12
|
-
import { link as fallback } from 'mdast-util-to-hast/lib/handlers/link.js';
|
|
13
|
-
import { parse, serialize } from 'uri-js';
|
|
14
|
-
|
|
15
|
-
export default function link({ extension = 'html' } = {}) {
|
|
16
|
-
return function handler(h, node) {
|
|
17
|
-
const n = { ...node };
|
|
18
|
-
const uriParts = parse(n.url);
|
|
19
|
-
if (!uriParts.scheme && uriParts.path) {
|
|
20
|
-
uriParts.path = uriParts.path.replace(/\.md$/, `.${extension}`);
|
|
21
|
-
n.url = serialize(uriParts, { absolutePath: true });
|
|
22
|
-
}
|
|
23
|
-
return fallback(h, n);
|
|
24
|
-
};
|
|
25
|
-
}
|