@adobe/helix-html-pipeline 5.0.0 → 5.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 +14 -0
- package/package.json +5 -5
- package/src/steps/extract-metadata.js +69 -7
- package/src/steps/render.js +1 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [5.0.2](https://github.com/adobe/helix-html-pipeline/compare/v5.0.1...v5.0.2) (2023-09-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* supress empty non-fallback values ([#399](https://github.com/adobe/helix-html-pipeline/issues/399)) ([1e5629d](https://github.com/adobe/helix-html-pipeline/commit/1e5629d7cb08de210c713654479bd6d5301a905e))
|
|
7
|
+
|
|
8
|
+
## [5.0.1](https://github.com/adobe/helix-html-pipeline/compare/v5.0.0...v5.0.1) (2023-09-09)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* properly handle empty string ([#395](https://github.com/adobe/helix-html-pipeline/issues/395)) ([daac492](https://github.com/adobe/helix-html-pipeline/commit/daac49224642eeb69951ee68256fcb7f264f4f0c))
|
|
14
|
+
|
|
1
15
|
# [5.0.0](https://github.com/adobe/helix-html-pipeline/compare/v4.1.5...v5.0.0) (2023-09-09)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-html-pipeline",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "Helix HTML Pipeline",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"hast-util-to-html": "8.0.4",
|
|
54
54
|
"hast-util-to-string": "2.0.0",
|
|
55
55
|
"hastscript": "7.2.0",
|
|
56
|
-
"jose": "4.14.
|
|
56
|
+
"jose": "4.14.6",
|
|
57
57
|
"mdast-util-to-hast": "12.3.0",
|
|
58
58
|
"mdast-util-to-string": "4.0.0",
|
|
59
59
|
"mime": "3.0.0",
|
|
@@ -76,16 +76,16 @@
|
|
|
76
76
|
"@semantic-release/git": "10.0.1",
|
|
77
77
|
"@semantic-release/npm": "10.0.5",
|
|
78
78
|
"c8": "8.0.1",
|
|
79
|
-
"eslint": "8.
|
|
79
|
+
"eslint": "8.49.0",
|
|
80
80
|
"eslint-import-resolver-exports": "1.0.0-beta.5",
|
|
81
81
|
"eslint-plugin-header": "3.1.1",
|
|
82
82
|
"eslint-plugin-import": "2.28.1",
|
|
83
|
-
"esmock": "2.
|
|
83
|
+
"esmock": "2.4.1",
|
|
84
84
|
"husky": "8.0.3",
|
|
85
85
|
"js-yaml": "4.1.0",
|
|
86
86
|
"jsdom": "22.1.0",
|
|
87
87
|
"junit-report-builder": "3.0.1",
|
|
88
|
-
"lint-staged": "
|
|
88
|
+
"lint-staged": "14.0.1",
|
|
89
89
|
"mocha": "10.2.0",
|
|
90
90
|
"mocha-multi-reporters": "1.5.1",
|
|
91
91
|
"mocha-suppress-logs": "0.3.1",
|
|
@@ -142,12 +142,25 @@ function extractDescription(hast) {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
/**
|
|
145
|
-
* Extracts the metadata and stores it in the content
|
|
145
|
+
* Extracts the metadata from config and the metadata block and stores it in the content.meta.page:
|
|
146
|
+
* - all the non-empty values from the config metadata are applied.
|
|
147
|
+
* - config value with an empty string (explicit "") are removed from the result
|
|
148
|
+
* - all the values from the metadata block are applied. empty values remain empty for the
|
|
149
|
+
* properties that can have a default: 'title', 'description', 'image', 'image-alt', 'url'
|
|
150
|
+
* the others are removed.
|
|
151
|
+
* - the defaults for 'title', 'description', 'image', 'image-alt', 'url' are applied if missing
|
|
152
|
+
* - twitter: properties default to their og: counterparts if missing.
|
|
153
|
+
*
|
|
146
154
|
* @type PipelineStep
|
|
147
155
|
* @param {PipelineState} state
|
|
148
156
|
* @param {PipelineRequest} req
|
|
149
157
|
*/
|
|
150
158
|
export default function extractMetaData(state, req) {
|
|
159
|
+
const FIXED = new Set([
|
|
160
|
+
'title', 'description', 'image', 'image-alt', 'url',
|
|
161
|
+
'twitter:card', 'og:url', 'canonical',
|
|
162
|
+
]);
|
|
163
|
+
|
|
151
164
|
const { content } = state;
|
|
152
165
|
const { meta, hast } = content;
|
|
153
166
|
|
|
@@ -160,13 +173,19 @@ export default function extractMetaData(state, req) {
|
|
|
160
173
|
|
|
161
174
|
// prune empty values and explicit "" strings from sheet based metadata
|
|
162
175
|
Object.entries(metaConfig).forEach(([name, value]) => {
|
|
163
|
-
if (!value
|
|
176
|
+
if (!value) {
|
|
164
177
|
delete metaConfig[name];
|
|
178
|
+
} else if (value === '""') {
|
|
179
|
+
metaConfig[name] = undefined;
|
|
165
180
|
}
|
|
166
181
|
});
|
|
167
182
|
|
|
168
183
|
// apply document local overrides
|
|
169
|
-
Object.
|
|
184
|
+
Object.entries(getLocalMetadata(hast)).forEach(([name, value]) => {
|
|
185
|
+
if (value || FIXED.has(name)) {
|
|
186
|
+
metaConfig[name] = value;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
170
189
|
|
|
171
190
|
// first process supported metadata properties
|
|
172
191
|
[
|
|
@@ -191,9 +210,6 @@ export default function extractMetaData(state, req) {
|
|
|
191
210
|
meta['twitter:card'] = 'summary_large_image';
|
|
192
211
|
}
|
|
193
212
|
|
|
194
|
-
// add rest to meta.custom
|
|
195
|
-
meta.custom = metaConfig;
|
|
196
|
-
|
|
197
213
|
if (meta.keywords) {
|
|
198
214
|
meta.keywords = toList(meta.keywords).join(', ');
|
|
199
215
|
}
|
|
@@ -234,9 +250,55 @@ export default function extractMetaData(state, req) {
|
|
|
234
250
|
if (!('image' in meta)) {
|
|
235
251
|
meta.image = getAbsoluteUrl(
|
|
236
252
|
state,
|
|
237
|
-
optimizeMetaImage(state.info.path,
|
|
253
|
+
optimizeMetaImage(state.info.path, content.image || '/default-meta-image.png'),
|
|
238
254
|
);
|
|
239
255
|
}
|
|
240
256
|
|
|
241
257
|
meta.imageAlt = meta['image-alt'] ?? content.imageAlt;
|
|
258
|
+
|
|
259
|
+
// compute the final page metadata
|
|
260
|
+
const metadata = {
|
|
261
|
+
description: meta.description,
|
|
262
|
+
keywords: meta.keywords,
|
|
263
|
+
'og:title': meta.title,
|
|
264
|
+
'og:description': meta.description,
|
|
265
|
+
'og:url': meta.url,
|
|
266
|
+
'og:image': meta.image,
|
|
267
|
+
'og:image:secure_url': meta.image,
|
|
268
|
+
'og:image:alt': meta.imageAlt,
|
|
269
|
+
'og:updated_time': meta.modified_time,
|
|
270
|
+
'article:tag': meta.tags || [],
|
|
271
|
+
'article:section': meta.section,
|
|
272
|
+
'article:published_time': meta.published_time,
|
|
273
|
+
'article:modified_time': meta.modified_time,
|
|
274
|
+
'twitter:card': meta['twitter:card'],
|
|
275
|
+
'twitter:title': '',
|
|
276
|
+
'twitter:description': '',
|
|
277
|
+
'twitter:image': '',
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// append custom metadata
|
|
281
|
+
Object.assign(metadata, metaConfig);
|
|
282
|
+
|
|
283
|
+
// fallback for twitter
|
|
284
|
+
const FALLBACKS = [
|
|
285
|
+
['twitter:title', 'og:title'],
|
|
286
|
+
['twitter:description', 'og:description'],
|
|
287
|
+
['twitter:image', 'og:image'],
|
|
288
|
+
];
|
|
289
|
+
|
|
290
|
+
for (const [from, to] of FALLBACKS) {
|
|
291
|
+
if (!(from in metaConfig)) {
|
|
292
|
+
metadata[from] = metadata[to];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// remove undefined metadata
|
|
297
|
+
for (const name of Object.keys(metadata)) {
|
|
298
|
+
if (metadata[name] === undefined) {
|
|
299
|
+
delete metadata[name];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
meta.page = metadata;
|
|
242
304
|
}
|
package/src/steps/render.js
CHANGED
|
@@ -55,54 +55,9 @@ export default async function render(state, req, res) {
|
|
|
55
55
|
$head.children.push(h('title', meta.title));
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
// add meta
|
|
59
|
-
// (this is so complicated to keep the order backward compatible to make the diff tests happy)
|
|
60
|
-
const metadata = {
|
|
61
|
-
'og:title': meta.title,
|
|
62
|
-
'og:description': meta.description,
|
|
63
|
-
'og:url': meta.url,
|
|
64
|
-
'og:image': meta.image,
|
|
65
|
-
'og:image:secure_url': meta.image,
|
|
66
|
-
'og:image:alt': meta.imageAlt,
|
|
67
|
-
'og:updated_time': meta.modified_time,
|
|
68
|
-
'article:tag': meta.tags || [],
|
|
69
|
-
'article:section': meta.section,
|
|
70
|
-
'article:published_time': meta.published_time,
|
|
71
|
-
'article:modified_time': meta.modified_time,
|
|
72
|
-
'twitter:card': meta['twitter:card'],
|
|
73
|
-
'twitter:title': '',
|
|
74
|
-
'twitter:description': '',
|
|
75
|
-
'twitter:image': '',
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// append custom metadata
|
|
79
|
-
Object.assign(metadata, meta.custom);
|
|
80
|
-
|
|
81
|
-
// fallback for twitter
|
|
82
|
-
const FALLBACKS = [
|
|
83
|
-
['twitter:title', 'og:title'],
|
|
84
|
-
['twitter:description', 'og:description'],
|
|
85
|
-
['twitter:image', 'og:image'],
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
for (const [from, to] of FALLBACKS) {
|
|
89
|
-
if (!(from in meta.custom)) {
|
|
90
|
-
metadata[from] = metadata[to];
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// remove undefined metadata
|
|
95
|
-
for (const name of Object.keys(metadata)) {
|
|
96
|
-
if (metadata[name] === undefined) {
|
|
97
|
-
delete metadata[name];
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
58
|
appendElement($head, createElement('link', 'rel', 'canonical', 'href', meta.canonical));
|
|
102
|
-
appendElement($head, createElement('meta', 'name', 'description', 'content', meta.description));
|
|
103
|
-
appendElement($head, createElement('meta', 'name', 'keywords', 'content', meta.keywords));
|
|
104
59
|
|
|
105
|
-
for (const [name, value] of Object.entries(
|
|
60
|
+
for (const [name, value] of Object.entries(meta.page)) {
|
|
106
61
|
const attr = name.includes(':') && !name.startsWith('twitter:') ? 'property' : 'name';
|
|
107
62
|
if (Array.isArray(value)) {
|
|
108
63
|
for (const v of value) {
|