@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.31",
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.7.23",
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": "^5.2.0",
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.5",
74
- "mocha": "11.7.1",
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
- // while the cell has children we need to process the fields in the fieldGroup
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
- const field = fieldResolver.resolve(node, fieldGroup);
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
- if (find(n, { type: 'image' })) {
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
- function extractProperties(mdast, model, mode, component, fields, properties) {
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' && classesField && (cells.length > modelFields.length)) {
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
  }