@adobe/helix-md2jcr 1.1.31 → 1.1.33
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
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.1.33](https://github.com/adobe/helix-md2jcr/compare/v1.1.32...v1.1.33) (2025-09-03)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* container blocks fail to parse correctly when no class is provided ([#147](https://github.com/adobe/helix-md2jcr/issues/147)) ([846f281](https://github.com/adobe/helix-md2jcr/commit/846f281509f47ddeb228a6cda9d6252e42861b74))
|
|
7
|
+
|
|
8
|
+
## [1.1.32](https://github.com/adobe/helix-md2jcr/compare/v1.1.31...v1.1.32) (2025-08-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **143:** support for field name hints ([8dbe511](https://github.com/adobe/helix-md2jcr/commit/8dbe511651f2d3f6e1b4a322eeb1ea91a83048a9))
|
|
14
|
+
|
|
1
15
|
## [1.1.31](https://github.com/adobe/helix-md2jcr/compare/v1.1.30...v1.1.31) (2025-08-17)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-md2jcr",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.33",
|
|
4
4
|
"description": "Helix Service that converts markdown to JCR content structure",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -55,14 +55,14 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@adobe/eslint-config-helix": "3.0.9",
|
|
58
|
-
"@adobe/helix-mediahandler": "2.
|
|
58
|
+
"@adobe/helix-mediahandler": "2.8.2",
|
|
59
59
|
"@commitlint/cli": "^19.6.1",
|
|
60
60
|
"@commitlint/config-conventional": "^19.6.0",
|
|
61
61
|
"@semantic-release/changelog": "6.0.3",
|
|
62
62
|
"@semantic-release/exec": "7.1.0",
|
|
63
63
|
"@semantic-release/git": "10.0.1",
|
|
64
64
|
"c8": "10.1.3",
|
|
65
|
-
"chai": "^
|
|
65
|
+
"chai": "^6.0.0",
|
|
66
66
|
"dotenv": "17.2.1",
|
|
67
67
|
"eslint": "^9.0.0",
|
|
68
68
|
"eslint-import-resolver-exports": "1.0.0-beta.5",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"eslint-plugin-import": "2.32.0",
|
|
71
71
|
"husky": "^9.1.7",
|
|
72
72
|
"junit-report-builder": "5.1.1",
|
|
73
|
-
"lint-staged": "16.1.
|
|
74
|
-
"mocha": "11.7.
|
|
73
|
+
"lint-staged": "16.1.6",
|
|
74
|
+
"mocha": "11.7.2",
|
|
75
75
|
"mocha-multi-reporters": "1.5.1",
|
|
76
76
|
"nock": "13.5.6",
|
|
77
77
|
"semantic-release": "24.2.7",
|
|
@@ -47,13 +47,23 @@ class FieldGroupFieldResolver {
|
|
|
47
47
|
* @param {{isGrouped: boolean, name: string, fields: [],
|
|
48
48
|
* collapsed: [{isGrouped: boolean, name: string, fields: []}]}} fieldGroup - the field group
|
|
49
49
|
*/
|
|
50
|
-
resolve(node, fieldGroup) {
|
|
50
|
+
resolve(node, fieldGroup, hint) {
|
|
51
51
|
const { fields } = fieldGroup;
|
|
52
52
|
if (fields === undefined) {
|
|
53
53
|
// throw an Error indicating the issue
|
|
54
54
|
throw new Error(`Field group ${fieldGroup.name} does not have any fields defined.`);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// if a hint is provided, then we need to find the field that matches the hint
|
|
58
|
+
if (hint) {
|
|
59
|
+
const fieldIndex = fields.findIndex((field) => field.name === hint);
|
|
60
|
+
if (fieldIndex !== -1) {
|
|
61
|
+
const field = fields[fieldIndex];
|
|
62
|
+
fields.splice(0, fieldIndex + 1);
|
|
63
|
+
return field;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
57
67
|
let foundField = fields.find((field) => {
|
|
58
68
|
if (node.type === 'heading' && field.collapsed?.find((c) => c.name.endsWith('Type'))) {
|
|
59
69
|
// try to find a field that matches the heading depth, if we have one
|
|
@@ -197,14 +197,19 @@ function extractKeyValueProperties(row, model, fieldResolver, fieldGroup, proper
|
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
function isFieldNameHint(node) {
|
|
201
|
+
return node.type === 'html' && node.value?.startsWith('<!-- field:') && node.value?.endsWith(' -->');
|
|
202
|
+
}
|
|
203
|
+
|
|
200
204
|
function processCell(cell, fieldGroup, fieldResolver, properties) {
|
|
201
205
|
const cellChildren = cell.children;
|
|
202
206
|
|
|
203
207
|
if (cellChildren.length !== 0) {
|
|
204
|
-
|
|
205
|
-
// if we run out of fields but there are still more nodes, then we need to throw an error
|
|
206
|
-
// because the model does not map correctly to the content
|
|
208
|
+
let nextFieldName;
|
|
207
209
|
while (cellChildren.length > 0) {
|
|
210
|
+
// while the cell has children we need to process the fields in the fieldGroup
|
|
211
|
+
// if we run out of fields but there are still more nodes, then we need to throw an error
|
|
212
|
+
// because the model does not map correctly to the content
|
|
208
213
|
const node = cellChildren.shift();
|
|
209
214
|
|
|
210
215
|
// have we run out of fields?
|
|
@@ -216,7 +221,14 @@ function processCell(cell, fieldGroup, fieldResolver, properties) {
|
|
|
216
221
|
throw new Error(errorMsg);
|
|
217
222
|
}
|
|
218
223
|
|
|
219
|
-
|
|
224
|
+
// if we see a property name hint, parse it and continue, unset it if not
|
|
225
|
+
if (isFieldNameHint(node)) {
|
|
226
|
+
nextFieldName = node.value.split('<!-- field:')[1].split(' -->')[0].trim();
|
|
227
|
+
// eslint-disable-next-line no-continue
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const field = fieldResolver.resolve(node, fieldGroup, nextFieldName);
|
|
220
232
|
|
|
221
233
|
let pWrapper;
|
|
222
234
|
if (field.component === 'richtext') {
|
|
@@ -231,7 +243,9 @@ function processCell(cell, fieldGroup, fieldResolver, properties) {
|
|
|
231
243
|
const n = cellChildren.shift();
|
|
232
244
|
if (!n) break;
|
|
233
245
|
|
|
234
|
-
|
|
246
|
+
// richtexts are greedy:
|
|
247
|
+
// they will consume all the children until they hit an image or a named field
|
|
248
|
+
if (find(n, { type: 'image' }) || isFieldNameHint(n)) {
|
|
235
249
|
cellChildren.unshift(n);
|
|
236
250
|
searching = false;
|
|
237
251
|
}
|
|
@@ -243,15 +257,36 @@ function processCell(cell, fieldGroup, fieldResolver, properties) {
|
|
|
243
257
|
pWrapper = node;
|
|
244
258
|
}
|
|
245
259
|
extractPropertiesForNode(field, pWrapper, properties);
|
|
260
|
+
|
|
261
|
+
nextFieldName = null;
|
|
246
262
|
}
|
|
247
263
|
}
|
|
248
264
|
}
|
|
249
265
|
|
|
250
|
-
|
|
266
|
+
/**
|
|
267
|
+
* Extract the properties for the block item.
|
|
268
|
+
* @param {*} mdast - The mdast tree.
|
|
269
|
+
* @param {*} model - The model.
|
|
270
|
+
* @param {*} mode - The mode, either 'blockItem' or 'keyValue' or 'simple'.
|
|
271
|
+
* @param {*} component - The component.
|
|
272
|
+
* @param {*} fields - The fields.
|
|
273
|
+
* @param {*} properties - The properties.
|
|
274
|
+
* @param {*} skipFirstCell - Use to tell the function to skip the first cell when
|
|
275
|
+
* processing the block item. This is only applicable when mode is 'blockItem' and
|
|
276
|
+
* when there is a component id specified in the first cell of the row for the block item.
|
|
277
|
+
*/
|
|
278
|
+
function extractProperties(
|
|
279
|
+
mdast,
|
|
280
|
+
model,
|
|
281
|
+
mode,
|
|
282
|
+
component,
|
|
283
|
+
fields,
|
|
284
|
+
properties,
|
|
285
|
+
skipFirstCell,
|
|
286
|
+
) {
|
|
251
287
|
const fieldsCloned = structuredClone(fields);
|
|
252
288
|
|
|
253
289
|
// the first cells is the header row, so we skip it
|
|
254
|
-
// const nodes = findAll(mdast, (node) => node.type === 'gtCell', true);
|
|
255
290
|
const rows = findAll(mdast, (node) => node.type === 'gtRow', false);
|
|
256
291
|
let classesField;
|
|
257
292
|
if (mode === 'blockItem') {
|
|
@@ -298,7 +333,7 @@ function extractProperties(mdast, model, mode, component, fields, properties) {
|
|
|
298
333
|
// We then want to throw away the first cell as it is the class field
|
|
299
334
|
// EC currently does not add the classes field therefore more cells than model fields
|
|
300
335
|
// See container-block.md for an example of more cells than model fields (second table)
|
|
301
|
-
if (mode === 'blockItem' &&
|
|
336
|
+
if (mode === 'blockItem' && (skipFirstCell) && (cells.length > modelFields.length)) {
|
|
302
337
|
cells.shift();
|
|
303
338
|
}
|
|
304
339
|
|
|
@@ -366,12 +401,14 @@ function getBlockItems(mdast, modelHelper, definitions, allowedComponents) {
|
|
|
366
401
|
|
|
367
402
|
// the first cell may be defined as the component id (with optional classes)
|
|
368
403
|
let componentId = cellText.split(',').shift().trim();
|
|
369
|
-
|
|
404
|
+
let skipFirstCell = false;
|
|
370
405
|
// if we can't find the component id in the allowed components it means
|
|
371
406
|
// the user has not specified what component to use therefore we fall back
|
|
372
407
|
// to the first allowed component.
|
|
373
408
|
if (allowedComponents.indexOf(componentId) === -1) {
|
|
374
409
|
[componentId] = allowedComponents;
|
|
410
|
+
} else {
|
|
411
|
+
skipFirstCell = true;
|
|
375
412
|
}
|
|
376
413
|
|
|
377
414
|
// check to see if we can use this component
|
|
@@ -384,7 +421,7 @@ function getBlockItems(mdast, modelHelper, definitions, allowedComponents) {
|
|
|
384
421
|
modelFields: `[${getModelFieldNames(fieldGroup.model).join(',')}]`,
|
|
385
422
|
};
|
|
386
423
|
|
|
387
|
-
extractProperties(row, fieldGroup.model, 'blockItem', component, fieldGroup.fields, properties);
|
|
424
|
+
extractProperties(row, fieldGroup.model, 'blockItem', component, fieldGroup.fields, properties, skipFirstCell);
|
|
388
425
|
items.push(`<item_${items.length} jcr:primaryType="nt:unstructured" sling:resourceType="core/franklin/components/block/v1/block/item" name="${fieldGroup.model.id}" ${Object.entries(properties).map(([k, v]) => `${k}="${v}"`).join(' ')}></item_${items.length}>`);
|
|
389
426
|
}
|
|
390
427
|
}
|