@adobe/helix-html-pipeline 1.6.0 → 2.0.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/CHANGELOG.md +41 -2
- package/package.json +7 -7
- package/src/html-pipe.js +2 -2
- package/src/steps/create-page-blocks.js +6 -9
- package/src/steps/create-pictures.js +74 -15
- package/src/steps/get-metadata.js +4 -4
- package/src/steps/rewrite-icons.js +9 -10
- package/src/steps/{rewrite-blob-images.js → rewrite-urls.js} +22 -10
- package/src/steps/stringify-response.js +2 -25
- package/src/steps/utils.js +75 -18
- package/src/utils/heading-handler.js +1 -1
- package/src/utils/mdast-to-hast.js +0 -25
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,48 @@
|
|
|
1
|
-
|
|
1
|
+
## [2.0.2](https://github.com/adobe/helix-html-pipeline/compare/v2.0.1...v2.0.2) (2022-05-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** update external fixes ([#65](https://github.com/adobe/helix-html-pipeline/issues/65)) ([0994581](https://github.com/adobe/helix-html-pipeline/commit/09945810ee3969350b6053d49d1614c1e9051eba))
|
|
7
|
+
|
|
8
|
+
## [2.0.1](https://github.com/adobe/helix-html-pipeline/compare/v2.0.0...v2.0.1) (2022-05-25)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* querystring is deprecated ([d693319](https://github.com/adobe/helix-html-pipeline/commit/d6933197e928da452712bcfb2c8a42cdefe2bf2c))
|
|
14
|
+
* respect fragments and querystring during link-rewrite ([44e00d4](https://github.com/adobe/helix-html-pipeline/commit/44e00d49293df392f4dec7eafee1abc60743ff79))
|
|
15
|
+
|
|
16
|
+
# [2.0.0](https://github.com/adobe/helix-html-pipeline/compare/v1.5.8...v2.0.0) (2022-05-25)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* add link rewriting ([bde5fb6](https://github.com/adobe/helix-html-pipeline/commit/bde5fb6a15fcac24887897c0134d524677730741))
|
|
22
|
+
* clean up empty paragraphs ([30547b7](https://github.com/adobe/helix-html-pipeline/commit/30547b7cca7869bd791bfa0b5fee7b23d8548798))
|
|
23
|
+
* create <picture> tags ([88c1ab9](https://github.com/adobe/helix-html-pipeline/commit/88c1ab96c335a60092b8fcbe60de2d2e061809bf))
|
|
24
|
+
* detect and fix wrong dimensions fragment ([e0df3dc](https://github.com/adobe/helix-html-pipeline/commit/e0df3dc6bfa0c2f3acf771f8cea95f5237eddb00))
|
|
25
|
+
* improve block css class names ([ff05d3c](https://github.com/adobe/helix-html-pipeline/commit/ff05d3c38d92126ea65573d33639453ea5aaa5e6))
|
|
26
|
+
* preserve table-cell align attributes as data-attribures ([c5a5c1a](https://github.com/adobe/helix-html-pipeline/commit/c5a5c1aea3148c7ad44e44f40e7dd7b8eca19566))
|
|
27
|
+
* pretty-print html ([529facf](https://github.com/adobe/helix-html-pipeline/commit/529facf416a07e8a5050ec1a614eec23f9249efc))
|
|
28
|
+
* replace icon svgs with spans ([55aeeeb](https://github.com/adobe/helix-html-pipeline/commit/55aeeeb03578eef0ece877669969729e1ce68855))
|
|
29
|
+
* unwrap img inside em/strong ([dbc6a82](https://github.com/adobe/helix-html-pipeline/commit/dbc6a8204193aa7c79fda05024fe3d8f40093443))
|
|
2
30
|
|
|
3
31
|
|
|
4
32
|
### Features
|
|
5
33
|
|
|
6
|
-
*
|
|
34
|
+
* Breaking changes for 2022-05 ([f2d1523](https://github.com/adobe/helix-html-pipeline/commit/f2d1523d21eb2b9a57bdd658526c7a9ee8bd8056))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### BREAKING CHANGES
|
|
38
|
+
|
|
39
|
+
* icons: are now replaced with <span> elements
|
|
40
|
+
* the format of the css class names changed
|
|
41
|
+
* dom changes
|
|
42
|
+
* picture dom changed
|
|
43
|
+
* all links to media and same hlx sites are relativized
|
|
44
|
+
* empty <p></p> tags now properly sourround the following element, eg pictures
|
|
45
|
+
* inter-element whitespace changes
|
|
7
46
|
|
|
8
47
|
## [1.5.8](https://github.com/adobe/helix-html-pipeline/compare/v1.5.7...v1.5.8) (2022-05-19)
|
|
9
48
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-html-pipeline",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Helix HTML Pipeline",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@adobe/helix-shared-utils": "2.0.10",
|
|
35
35
|
"github-slugger": "1.4.0",
|
|
36
36
|
"hast-util-raw": "7.2.1",
|
|
37
|
-
"hast-util-select": "5.0.
|
|
37
|
+
"hast-util-select": "5.0.2",
|
|
38
38
|
"hast-util-to-html": "8.0.3",
|
|
39
39
|
"hast-util-to-string": "2.0.0",
|
|
40
40
|
"hastscript": "7.0.2",
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"micromark-util-combine-extensions": "1.0.0",
|
|
53
53
|
"mime": "3.0.0",
|
|
54
54
|
"rehype-format": "4.0.1",
|
|
55
|
-
"rehype-minify-whitespace": "5.0.1",
|
|
56
55
|
"rehype-parse": "8.0.4",
|
|
57
56
|
"remark-parse": "10.0.1",
|
|
58
57
|
"strip-markdown": "5.0.0",
|
|
@@ -61,7 +60,8 @@
|
|
|
61
60
|
"unist-util-remove": "3.1.0",
|
|
62
61
|
"unist-util-remove-position": "4.0.1",
|
|
63
62
|
"unist-util-select": "4.0.1",
|
|
64
|
-
"unist-util-visit": "4.1.0"
|
|
63
|
+
"unist-util-visit": "4.1.0",
|
|
64
|
+
"unist-util-visit-parents": "5.1.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@adobe/eslint-config-helix": "1.3.2",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"@semantic-release/changelog": "6.0.1",
|
|
70
70
|
"@semantic-release/git": "10.0.1",
|
|
71
71
|
"@semantic-release/npm": "9.0.1",
|
|
72
|
-
"c8": "7.11.
|
|
73
|
-
"eslint": "8.
|
|
72
|
+
"c8": "7.11.3",
|
|
73
|
+
"eslint": "8.16.0",
|
|
74
74
|
"eslint-plugin-header": "3.1.1",
|
|
75
75
|
"eslint-plugin-import": "2.26.0",
|
|
76
76
|
"esmock": "1.7.5",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"jsdoc-to-markdown": "7.1.1",
|
|
80
80
|
"jsdom": "19.0.0",
|
|
81
81
|
"junit-report-builder": "3.0.0",
|
|
82
|
-
"lint-staged": "12.4.
|
|
82
|
+
"lint-staged": "12.4.2",
|
|
83
83
|
"mocha": "10.0.0",
|
|
84
84
|
"mocha-multi-reporters": "1.5.1",
|
|
85
85
|
"remark-gfm": "3.0.1",
|
package/src/html-pipe.js
CHANGED
|
@@ -25,7 +25,7 @@ import parseMarkdown from './steps/parse-markdown.js';
|
|
|
25
25
|
import removeHlxProps from './steps/removeHlxProps.js';
|
|
26
26
|
import render from './steps/render.js';
|
|
27
27
|
import renderCode from './steps/render-code.js';
|
|
28
|
-
import
|
|
28
|
+
import rewriteUrls from './steps/rewrite-urls.js';
|
|
29
29
|
import rewriteIcons from './steps/rewrite-icons.js';
|
|
30
30
|
import setXSurrogateKeyHeader from './steps/set-x-surrogate-key-header.js';
|
|
31
31
|
import setCustomResponseHeaders from './steps/set-custom-response-headers.js';
|
|
@@ -94,7 +94,7 @@ export async function htmlPipe(state, req) {
|
|
|
94
94
|
await getMetadata(state); // this one extracts the metadata from the mdast
|
|
95
95
|
await unwrapSoleImages(state);
|
|
96
96
|
await html(state);
|
|
97
|
-
await
|
|
97
|
+
await rewriteUrls(state);
|
|
98
98
|
await rewriteIcons(state);
|
|
99
99
|
await fixSections(state);
|
|
100
100
|
await createPageBlocks(state);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { h } from 'hastscript';
|
|
13
13
|
import { selectAll, select } from 'hast-util-select';
|
|
14
14
|
import { toString } from 'hast-util-to-string';
|
|
15
|
-
import {
|
|
15
|
+
import { toBlockCSSClassNames } from './utils.js';
|
|
16
16
|
import { replace, childNodes } from '../utils/hast-utils.js';
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -44,20 +44,17 @@ function tableToDivs($table) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// get columns names
|
|
47
|
-
|
|
48
|
-
.map((e) => toClassName(toString(e)))
|
|
49
|
-
.filter((c) => !!c)
|
|
50
|
-
.join('-');
|
|
51
|
-
if (clazz) {
|
|
52
|
-
$cards.properties.className = [clazz];
|
|
53
|
-
}
|
|
47
|
+
$cards.properties.className = toBlockCSSClassNames(toString($headerCols[0]));
|
|
54
48
|
|
|
55
49
|
// construct page block
|
|
56
50
|
for (const $row of $rows) {
|
|
57
51
|
const $card = h('div');
|
|
58
52
|
for (const $cell of childNodes($row)) {
|
|
59
53
|
// convert to div
|
|
60
|
-
$card.children.push(h('div',
|
|
54
|
+
$card.children.push(h('div', {
|
|
55
|
+
'data-align': $cell.properties.align,
|
|
56
|
+
'data-valign': $cell.properties.vAlign,
|
|
57
|
+
}, $cell.children));
|
|
61
58
|
}
|
|
62
59
|
$cards.children.push($card);
|
|
63
60
|
}
|
|
@@ -9,10 +9,65 @@
|
|
|
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 mime from 'mime';
|
|
12
13
|
import { h } from 'hastscript';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
import { visitParents } from 'unist-util-visit-parents';
|
|
15
|
+
|
|
16
|
+
const BREAK_POINTS = [
|
|
17
|
+
{ media: '(min-width: 400px)', width: '2000' },
|
|
18
|
+
{ width: '750' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export function createOptimizedPicture(src, alt = '', eager = false) {
|
|
22
|
+
const url = new URL(src, 'https://localhost/');
|
|
23
|
+
const { pathname, hash = '' } = url;
|
|
24
|
+
const props = new URLSearchParams(hash.substring(1));
|
|
25
|
+
// detect bug in media handler that created fragments like `width=800&width=600`
|
|
26
|
+
// eslint-disable-next-line prefer-const
|
|
27
|
+
let [width, height] = props.getAll('width');
|
|
28
|
+
if (props.has('height')) {
|
|
29
|
+
height = props.get('height');
|
|
30
|
+
}
|
|
31
|
+
const ext = pathname.substring(pathname.lastIndexOf('.') + 1);
|
|
32
|
+
const type = mime.getType(pathname);
|
|
33
|
+
|
|
34
|
+
const variants = [
|
|
35
|
+
...BREAK_POINTS.map((br) => ({
|
|
36
|
+
...br,
|
|
37
|
+
ext: 'webply',
|
|
38
|
+
type: 'image/webp',
|
|
39
|
+
})),
|
|
40
|
+
...BREAK_POINTS.map((br) => ({
|
|
41
|
+
...br,
|
|
42
|
+
ext,
|
|
43
|
+
type,
|
|
44
|
+
}))];
|
|
45
|
+
|
|
46
|
+
const sources = variants.map((v, i) => {
|
|
47
|
+
const srcset = `.${pathname}?width=${v.width}&format=${v.ext}&optimize=medium`;
|
|
48
|
+
if (i < variants.length - 1) {
|
|
49
|
+
return h('source', {
|
|
50
|
+
type: v.type,
|
|
51
|
+
srcset,
|
|
52
|
+
media: v.media,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return h('img', {
|
|
56
|
+
loading: eager ? 'eager' : 'lazy',
|
|
57
|
+
alt,
|
|
58
|
+
type: v.type,
|
|
59
|
+
src: srcset,
|
|
60
|
+
width,
|
|
61
|
+
height,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return h('picture', sources);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isMediaImage(node) {
|
|
69
|
+
return node.tagName === 'img' && node.properties?.src.startsWith('./media_');
|
|
70
|
+
}
|
|
16
71
|
|
|
17
72
|
/**
|
|
18
73
|
* Converts imgs to pictures
|
|
@@ -22,18 +77,22 @@ import { optimizeImageURL } from './utils.js';
|
|
|
22
77
|
export default async function createPictures({ content }) {
|
|
23
78
|
const { hast } = content;
|
|
24
79
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const { src } = img.properties;
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
source.properties.srcset = optimizeImageURL(src, 750);
|
|
31
|
-
|
|
32
|
-
const picture = h('picture', source);
|
|
33
|
-
img.properties.loading = i > 0 ? 'lazy' : 'eager';
|
|
34
|
-
img.properties.src = optimizeImageURL(src, 2000);
|
|
80
|
+
let first = true;
|
|
81
|
+
visitParents(hast, isMediaImage, (img, parents) => {
|
|
82
|
+
const { src, alt } = img.properties;
|
|
83
|
+
const picture = createOptimizedPicture(src, alt, first);
|
|
84
|
+
first = false;
|
|
35
85
|
|
|
36
|
-
|
|
37
|
-
|
|
86
|
+
// check if parent has style and unwrap if needed
|
|
87
|
+
const parent = parents[parents.length - 1];
|
|
88
|
+
const parentTag = parent.tagName;
|
|
89
|
+
if (parentTag === 'em' || parentTag === 'strong') {
|
|
90
|
+
const grand = parents[parents.length - 2];
|
|
91
|
+
const idx = grand.children.indexOf(parent);
|
|
92
|
+
grand.children[idx] = picture;
|
|
93
|
+
} else {
|
|
94
|
+
const idx = parent.children.indexOf(img);
|
|
95
|
+
parent.children[idx] = picture;
|
|
96
|
+
}
|
|
38
97
|
});
|
|
39
98
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { select, selectAll } from 'unist-util-select';
|
|
13
13
|
import { toString as plain } from 'mdast-util-to-string';
|
|
14
|
-
import {
|
|
14
|
+
import { rewriteUrl } from './utils.js';
|
|
15
15
|
|
|
16
16
|
function yaml(section) {
|
|
17
17
|
section.meta = selectAll('yaml', section)
|
|
@@ -35,12 +35,12 @@ function intro(section) {
|
|
|
35
35
|
section.intro = para ? plain(para) : '';
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
function image(section) {
|
|
38
|
+
function image(section, state) {
|
|
39
39
|
// selects the most prominent image of the section
|
|
40
40
|
// TODO: get a better measure of prominence than "first"
|
|
41
41
|
const img = select('image', section);
|
|
42
42
|
if (img) {
|
|
43
|
-
section.image =
|
|
43
|
+
section.image = rewriteUrl(state, img.url);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -157,7 +157,7 @@ export default function getMetadata(state) {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
[yaml, title, intro, image, sectiontype, fallback].forEach((fn) => {
|
|
160
|
-
sections.forEach(fn);
|
|
160
|
+
sections.forEach((section) => fn(section, state));
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
const img = sections.filter((section) => section.image)[0];
|
|
@@ -10,15 +10,16 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
/* eslint-disable no-param-reassign */
|
|
13
|
-
import { h
|
|
13
|
+
import { h } from 'hastscript';
|
|
14
14
|
import { CONTINUE, visit } from 'unist-util-visit';
|
|
15
15
|
|
|
16
|
-
const REGEXP_ICON = /:(#?[a-
|
|
16
|
+
const REGEXP_ICON = /:(#?[a-z_-]+[a-z\d]*):/gi;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Create a <
|
|
20
|
-
*
|
|
21
|
-
* `<
|
|
19
|
+
* Create a <span> icon element:
|
|
20
|
+
*
|
|
21
|
+
* `<span class="icon icon-smile"></span>`
|
|
22
|
+
*
|
|
22
23
|
* @param {string} value the identifier of the icon
|
|
23
24
|
*/
|
|
24
25
|
function createIcon(value) {
|
|
@@ -26,14 +27,12 @@ function createIcon(value) {
|
|
|
26
27
|
|
|
27
28
|
// icon starts with #
|
|
28
29
|
if (name.startsWith('%23')) {
|
|
30
|
+
// todo: still support sprite sheets?
|
|
29
31
|
name = name.substring(3);
|
|
30
|
-
return s('svg', { class: `icon icon-${name}` }, [
|
|
31
|
-
s('use', { href: `/icons.svg#${name}` }),
|
|
32
|
-
]);
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
// create normal
|
|
36
|
-
return h('
|
|
34
|
+
// create normal span
|
|
35
|
+
return h('span', { className: ['icon', `icon-${name}`] });
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
/**
|
|
@@ -9,18 +9,30 @@
|
|
|
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
|
-
import {
|
|
12
|
+
|
|
13
|
+
import { CONTINUE, visit } from 'unist-util-visit';
|
|
14
|
+
import { rewriteUrl } from './utils.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @type PipelineStep
|
|
19
|
-
* @param content
|
|
17
|
+
* Rewrites all A and IMG urls
|
|
18
|
+
* @param {PipelineState} state
|
|
20
19
|
*/
|
|
21
|
-
export default function
|
|
22
|
-
const { hast } =
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
export default async function rewriteUrls(state) {
|
|
21
|
+
const { content: { hast } } = state;
|
|
22
|
+
|
|
23
|
+
const els = {
|
|
24
|
+
a: 'href',
|
|
25
|
+
img: 'src',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
visit(hast, (node) => {
|
|
29
|
+
if (node.type !== 'element') {
|
|
30
|
+
return CONTINUE;
|
|
31
|
+
}
|
|
32
|
+
const attr = els[node.tagName];
|
|
33
|
+
if (attr) {
|
|
34
|
+
node.properties[attr] = rewriteUrl(state, node.properties[attr]);
|
|
35
|
+
}
|
|
36
|
+
return CONTINUE;
|
|
25
37
|
});
|
|
26
38
|
}
|
|
@@ -10,9 +10,7 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import { toHtml } from 'hast-util-to-html';
|
|
13
|
-
|
|
14
|
-
import rehypeMinifyWhitespace from 'rehype-minify-whitespace';
|
|
15
|
-
import { visit } from 'unist-util-visit';
|
|
13
|
+
import rehypeFormat from 'rehype-format';
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
16
|
* Serializes the response document to HTML
|
|
@@ -30,28 +28,7 @@ export default function stringify(state, req, res) {
|
|
|
30
28
|
if (!doc) {
|
|
31
29
|
throw Error('no response document');
|
|
32
30
|
}
|
|
33
|
-
|
|
34
|
-
// TODO: for the next breaking release, pretty print the HTML with rehypeFormat.
|
|
35
|
-
// TODO: but for backward compatibility, output all on 1 line.
|
|
36
|
-
// rehypeFormat()(doc);
|
|
37
|
-
|
|
38
|
-
// due to a bug in rehype-minify-whitespace, script content is also minified to 1 line, which
|
|
39
|
-
// can result in errors https://github.com/rehypejs/rehype-minify/issues/44
|
|
40
|
-
// so we 'save' all text first and revert it afterwards
|
|
41
|
-
visit(doc, (node) => {
|
|
42
|
-
if (node.tagName === 'script' && node.children[0]?.type === 'text') {
|
|
43
|
-
node.children[0].savedValue = node.children[0].value;
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
rehypeMinifyWhitespace()(doc);
|
|
48
|
-
|
|
49
|
-
visit(doc, (node) => {
|
|
50
|
-
if (node.tagName === 'script' && node.children[0]?.type === 'text') {
|
|
51
|
-
node.children[0].value = node.children[0].savedValue;
|
|
52
|
-
delete node.children[0].savedValue;
|
|
53
|
-
}
|
|
54
|
-
});
|
|
31
|
+
rehypeFormat()(doc);
|
|
55
32
|
|
|
56
33
|
res.body = toHtml(doc, {
|
|
57
34
|
upperDoctype: true,
|
package/src/steps/utils.js
CHANGED
|
@@ -14,6 +14,8 @@ const AZURE_BLOB_REGEXP = /^https:\/\/hlx\.blob\.core\.windows\.net\/external\//
|
|
|
14
14
|
|
|
15
15
|
const MEDIA_BLOB_REGEXP = /^https:\/\/.*\.hlx3?\.(live|page)\/media_.*/;
|
|
16
16
|
|
|
17
|
+
const HELIX_URL_REGEXP = /^https:\/\/.*\.hlx3?\.(live|page)\/.*/;
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* Returns the original host name from the request to the outer CDN.
|
|
19
21
|
* @param {object} headers The request headers
|
|
@@ -64,15 +66,39 @@ export function wrapContent($parent, $node) {
|
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
|
-
* Converts
|
|
69
|
+
* Converts the given text to an array of CSS class names:
|
|
70
|
+
* - extracts the list of options (given as CSV in braces at the end)
|
|
71
|
+
* - collapses all consecutive invalid-css name characters to a single `-`
|
|
72
|
+
* - removes leading and trailing `-`
|
|
73
|
+
* - converts all names to lowercase
|
|
74
|
+
*
|
|
75
|
+
* @examples
|
|
76
|
+
* Columns (fullsize center) --> columns fullsize-center
|
|
77
|
+
* Columns (fullsize, center) --> columns fullsize center
|
|
78
|
+
* Joe's Pizza! (small) -> joe-s-pizza small
|
|
79
|
+
*
|
|
68
80
|
* @param {string} text input text
|
|
69
|
-
* @returns {string} the
|
|
81
|
+
* @returns {string[]} the array of CSS class names
|
|
70
82
|
*/
|
|
71
|
-
export function
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
export function toBlockCSSClassNames(text) {
|
|
84
|
+
if (!text) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const names = [];
|
|
88
|
+
const idx = text.lastIndexOf('(');
|
|
89
|
+
if (idx >= 0) {
|
|
90
|
+
names.push(text.substring(0, idx));
|
|
91
|
+
names.push(...text.substring(idx + 1).split(','));
|
|
92
|
+
} else {
|
|
93
|
+
names.push(text);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return names.map((name) => name
|
|
74
97
|
.toLowerCase()
|
|
75
|
-
.replace(/[^0-9a-z]
|
|
98
|
+
.replace(/[^0-9a-z]+/g, '-')
|
|
99
|
+
.replace(/^-+/, '')
|
|
100
|
+
.replace(/-+$/, ''))
|
|
101
|
+
.filter((name) => !!name);
|
|
76
102
|
}
|
|
77
103
|
|
|
78
104
|
/**
|
|
@@ -150,19 +176,50 @@ export function getAbsoluteUrl(headers, url) {
|
|
|
150
176
|
}
|
|
151
177
|
|
|
152
178
|
/**
|
|
153
|
-
*
|
|
154
|
-
* @param {
|
|
155
|
-
* @
|
|
179
|
+
* Rewrites the media, helix or external url. Returns the original if not rewritten.
|
|
180
|
+
* @param {PipelineState} state
|
|
181
|
+
* @param {string} url
|
|
182
|
+
* @returns {string|null}
|
|
156
183
|
*/
|
|
157
|
-
export function
|
|
158
|
-
if (
|
|
159
|
-
|
|
184
|
+
export function rewriteUrl(state, url) {
|
|
185
|
+
if (!url) {
|
|
186
|
+
return url;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (AZURE_BLOB_REGEXP.test(url)) {
|
|
190
|
+
const { pathname, hash } = new URL(url);
|
|
160
191
|
const filename = pathname.split('/').pop();
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return `.${pathname}`; // don't append fragment until picture tag supports width/height
|
|
192
|
+
const [name, props] = hash.split('?');
|
|
193
|
+
const extension = name.split('.').pop() || 'jpg';
|
|
194
|
+
const newHash = props ? `#${props}` : '';
|
|
195
|
+
return `./media_${filename}.${extension}${newHash}`;
|
|
166
196
|
}
|
|
167
|
-
|
|
197
|
+
|
|
198
|
+
if (MEDIA_BLOB_REGEXP.test(url)) {
|
|
199
|
+
const { pathname, hash } = new URL(url);
|
|
200
|
+
return `.${pathname}${hash}`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (HELIX_URL_REGEXP.test(url)) {
|
|
204
|
+
const { pathname, hash, search } = new URL(url);
|
|
205
|
+
if (hash && pathname === state.info?.path) {
|
|
206
|
+
return hash;
|
|
207
|
+
}
|
|
208
|
+
return `${pathname}${search}${hash}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// todo: read host from contentbus config
|
|
212
|
+
if (state.config?.host) {
|
|
213
|
+
const {
|
|
214
|
+
host, pathname, search, hash,
|
|
215
|
+
} = new URL(url);
|
|
216
|
+
if (host === state.config.host) {
|
|
217
|
+
if (hash && pathname === state.info?.path) {
|
|
218
|
+
return hash;
|
|
219
|
+
}
|
|
220
|
+
return `${pathname}${search}${hash}`;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return url;
|
|
168
225
|
}
|
|
@@ -14,7 +14,7 @@ import { toString } from 'mdast-util-to-string';
|
|
|
14
14
|
import strip from 'strip-markdown';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
*Injects heading identifiers during the MDAST to VDOM transformation.
|
|
17
|
+
* Injects heading identifiers during the MDAST to VDOM transformation.
|
|
18
18
|
*/
|
|
19
19
|
export default function heading(slugger) {
|
|
20
20
|
return function handler(h, node) {
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { toHast as mdast2hast, defaultHandlers } from 'mdast-util-to-hast';
|
|
13
13
|
import { raw } from 'hast-util-raw';
|
|
14
|
-
import { visit, CONTINUE } from 'unist-util-visit';
|
|
15
14
|
|
|
16
15
|
import section from './section-handler.js';
|
|
17
16
|
import heading from './heading-handler.js';
|
|
@@ -32,29 +31,5 @@ export default function getHast(mdast, slugger) {
|
|
|
32
31
|
allowDangerousHtml: true,
|
|
33
32
|
});
|
|
34
33
|
|
|
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
34
|
return raw(hast);
|
|
60
35
|
}
|