@adobe/helix-md2jcr 1.1.21 → 1.1.22
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,10 @@
|
|
|
1
|
+
## [1.1.22](https://github.com/adobe/helix-md2jcr/compare/v1.1.21...v1.1.22) (2025-06-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **103:** custom section metadata fields not being added to jcr result ([#104](https://github.com/adobe/helix-md2jcr/issues/104)) ([bd4b5e6](https://github.com/adobe/helix-md2jcr/commit/bd4b5e69287badbd1ccead61066472231390c9eb))
|
|
7
|
+
|
|
1
8
|
## [1.1.21](https://github.com/adobe/helix-md2jcr/compare/v1.1.20...v1.1.21) (2025-05-30)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-md2jcr",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.22",
|
|
4
4
|
"description": "Helix Service that converts markdown to JCR content structure",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@adobe/eslint-config-helix": "2.0.9",
|
|
58
|
-
"@adobe/helix-mediahandler": "2.7.
|
|
58
|
+
"@adobe/helix-mediahandler": "2.7.10",
|
|
59
59
|
"@commitlint/cli": "^19.6.1",
|
|
60
60
|
"@commitlint/config-conventional": "^19.6.0",
|
|
61
61
|
"@semantic-release/changelog": "6.0.3",
|
|
@@ -42,20 +42,18 @@ function getField(model, fieldName) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* Return a
|
|
46
|
-
*
|
|
47
|
-
* @
|
|
48
|
-
* @return {string}
|
|
45
|
+
* Return a list of field names in the model, excluding 'classes'.
|
|
46
|
+
* @param {Model} model The model.
|
|
47
|
+
* @return {Array<string>} An array of field names.
|
|
49
48
|
*/
|
|
50
|
-
function
|
|
49
|
+
function getModelFieldNames(model) {
|
|
51
50
|
return model.fields
|
|
52
51
|
.map((f) => f.name)
|
|
53
|
-
.filter((f) => f !== 'classes')
|
|
54
|
-
.join(',');
|
|
52
|
+
.filter((f) => f !== 'classes');
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
export {
|
|
58
56
|
getField,
|
|
59
57
|
findModelById,
|
|
60
|
-
|
|
58
|
+
getModelFieldNames,
|
|
61
59
|
};
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { find } from 'unist-util-find';
|
|
13
13
|
import { toString } from 'mdast-util-to-string';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
findModelById,
|
|
16
|
+
getField,
|
|
17
|
+
getModelFieldNames,
|
|
18
|
+
} from '../../domain/Models.js';
|
|
15
19
|
import { findAll } from '../../utils/mdast.js';
|
|
16
20
|
import { encodeHTMLEntities, stripNewlines } from '../../utils.js';
|
|
17
21
|
import link from '../partials/supports/link.js';
|
|
@@ -70,8 +74,8 @@ function buildPageMetadata(table, models) {
|
|
|
70
74
|
// we need to add a property called modelFields for the Universal Editor
|
|
71
75
|
// that has all the fields for the model
|
|
72
76
|
if (model) {
|
|
73
|
-
const fields =
|
|
74
|
-
mappedMetadata.modelFields = `[${fields}]`;
|
|
77
|
+
const fields = getModelFieldNames(model);
|
|
78
|
+
mappedMetadata.modelFields = `[${fields.join(',')}]`;
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
return mappedMetadata;
|
|
@@ -13,55 +13,168 @@ import Handlebars from 'handlebars';
|
|
|
13
13
|
import { find } from 'unist-util-find';
|
|
14
14
|
import { toString } from 'mdast-util-to-string';
|
|
15
15
|
import { findAll } from '../../utils/mdast.js';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
findModelById,
|
|
18
|
+
getField,
|
|
19
|
+
getModelFieldNames,
|
|
20
|
+
} from '../../domain/Models.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Normalizes strings by converting to lowercase and replacing spaces with hyphens
|
|
24
|
+
* @param {string} str
|
|
25
|
+
* @return {string}
|
|
26
|
+
*/
|
|
27
|
+
function normalizeString(str) {
|
|
28
|
+
return str.toLowerCase().replaceAll(' ', '-');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Helper function to find the section model ID from the grid table.
|
|
33
|
+
* @param {Node} tree
|
|
34
|
+
* @return {string|null}
|
|
35
|
+
*/
|
|
36
|
+
function getSectionModelId(tree) {
|
|
37
|
+
const blockModelIdCell = find(tree, { type: 'text', value: 'blockModelId' });
|
|
38
|
+
if (!blockModelIdCell) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const parentRow = find(tree, (node) => node.type === 'gtRow' && find(node, (child) => child === blockModelIdCell));
|
|
43
|
+
|
|
44
|
+
if (!parentRow) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const cells = findAll(parentRow, (node) => node.type === 'gtCell', true);
|
|
49
|
+
return cells.length > 1 ? toString(cells[1]) : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Processes metadata rows and extracts field values
|
|
54
|
+
* @param {Array} rows
|
|
55
|
+
* @param {Model} model
|
|
56
|
+
* @return {object} result with attributes and modelFields
|
|
57
|
+
*/
|
|
58
|
+
function processMetadataRows(rows, model) {
|
|
59
|
+
const attributes = {};
|
|
60
|
+
|
|
61
|
+
// always push the model fields so UE can use them, even if no attributes are found
|
|
62
|
+
const modelFields = getModelFieldNames(model);
|
|
63
|
+
|
|
64
|
+
for (const row of rows) {
|
|
65
|
+
const cells = findAll(row, (n) => n.type === 'gtCell', true);
|
|
66
|
+
if (cells.length < 2) {
|
|
67
|
+
// eslint-disable-next-line no-continue
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const key = toString(cells[0])?.trim();
|
|
72
|
+
const value = toString(cells[1])?.trim();
|
|
73
|
+
|
|
74
|
+
// Skip empty keys/values and the special blockModelId field
|
|
75
|
+
if (!key || !value || key === 'blockModelId') {
|
|
76
|
+
// eslint-disable-next-line no-continue
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const field = getField(model, key);
|
|
81
|
+
if (!field) {
|
|
82
|
+
// eslint-disable-next-line no-continue
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (field.component === 'multiselect') {
|
|
87
|
+
const multiValue = value.split(',')
|
|
88
|
+
.map((s) => s.trim())
|
|
89
|
+
.filter(Boolean);
|
|
90
|
+
attributes[key] = `[${multiValue.join(',')}]`;
|
|
91
|
+
} else {
|
|
92
|
+
attributes[key] = value;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { attributes, modelFields };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Finds and processes the section metadata table
|
|
101
|
+
* @param {Array} children
|
|
102
|
+
* @param {Array} models
|
|
103
|
+
* @return {object|null}
|
|
104
|
+
*/
|
|
105
|
+
function findSectionMetadata(children, models) {
|
|
106
|
+
for (const child of children) {
|
|
107
|
+
if (child.type !== 'gridTable') {
|
|
108
|
+
// eslint-disable-next-line no-continue
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const headerCell = find(child, { type: 'gtCell' });
|
|
113
|
+
if (!headerCell) {
|
|
114
|
+
// eslint-disable-next-line no-continue
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const isMetadata = normalizeString(toString(headerCell)) === 'section-metadata';
|
|
119
|
+
if (!isMetadata) {
|
|
120
|
+
// eslint-disable-next-line no-continue
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Found section metadata table
|
|
125
|
+
const sectionModelId = getSectionModelId(child) || 'section';
|
|
126
|
+
const model = findModelById(models, sectionModelId);
|
|
127
|
+
|
|
128
|
+
if (!model) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const [, ...rows] = findAll(child, (n) => n.type === 'gtRow', false);
|
|
133
|
+
|
|
134
|
+
const result = processMetadataRows(rows, model);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
attributes: result.attributes,
|
|
138
|
+
modelFields: result.modelFields,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// see if there is a global section model to use
|
|
143
|
+
const sectionModel = findModelById(models, 'section');
|
|
144
|
+
if (!sectionModel) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
modelFields: getModelFieldNames(sectionModel),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
17
152
|
|
|
18
153
|
function sectionHelper(index, children, options) {
|
|
19
|
-
const {
|
|
20
|
-
|
|
21
|
-
} = options.data.root;
|
|
154
|
+
const { models } = options.data.root;
|
|
155
|
+
const uniqueName = Handlebars.helpers.nameHelper.call(this, 'section');
|
|
22
156
|
|
|
23
|
-
const
|
|
157
|
+
const metadataResult = findSectionMetadata(children, models);
|
|
158
|
+
|
|
159
|
+
let attributes = {
|
|
24
160
|
'sling:resourceType': 'core/franklin/components/section/v1/section',
|
|
25
161
|
'jcr:primaryType': 'nt:unstructured',
|
|
26
162
|
};
|
|
163
|
+
let modelFields = [];
|
|
27
164
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
attributes.modelFields = `[${fields}]`;
|
|
165
|
+
if (metadataResult) {
|
|
166
|
+
attributes = { ...attributes, ...metadataResult.attributes };
|
|
167
|
+
modelFields = metadataResult.modelFields;
|
|
32
168
|
}
|
|
33
169
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// find the table that has a gtHeader that has a header value that contains 'section-metadata'
|
|
37
|
-
for (const child of children) {
|
|
38
|
-
if (child.type === 'gridTable') {
|
|
39
|
-
const cell = find(child, { type: 'gtCell' });
|
|
40
|
-
if (cell) {
|
|
41
|
-
const isMetadata = toString(cell).toLowerCase().replaceAll(' ', '-') === 'section-metadata';
|
|
42
|
-
if (isMetadata) {
|
|
43
|
-
const [, ...rows] = findAll(child, (n) => n.type === 'gtRow', false);
|
|
44
|
-
for (const row of rows) {
|
|
45
|
-
const cells = findAll(row, (n) => n.type === 'gtCell', true);
|
|
46
|
-
const key = toString(cells[0]);
|
|
47
|
-
const value = toString(cells[1]);
|
|
48
|
-
if (key.trim() !== '' && value.trim() !== '') {
|
|
49
|
-
const field = getField(model, key);
|
|
50
|
-
if (field?.component === 'multiselect') {
|
|
51
|
-
const multiValue = value.split(',').map((s) => s.trim()).filter(Boolean);
|
|
52
|
-
attributes[key.toLowerCase().replaceAll(' ', '-')] = `[${multiValue.join(',')}]`;
|
|
53
|
-
} else {
|
|
54
|
-
attributes[key.toLowerCase().replaceAll(' ', '-')] = value;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
170
|
+
if (modelFields.length > 0) {
|
|
171
|
+
attributes.modelFields = `[${modelFields.join(',')}]`;
|
|
62
172
|
}
|
|
63
173
|
|
|
64
|
-
const attributesStr = Object.entries(attributes)
|
|
174
|
+
const attributesStr = Object.entries(attributes)
|
|
175
|
+
.map(([k, v]) => `${k}="${v}"`)
|
|
176
|
+
.join(' ');
|
|
177
|
+
|
|
65
178
|
return `<section${uniqueName} ${attributesStr}>${options.fn(this)}</section${uniqueName}>`;
|
|
66
179
|
}
|
|
67
180
|
|
|
@@ -18,7 +18,8 @@ import { toHast } from 'mdast-util-to-hast';
|
|
|
18
18
|
import { toHtml } from 'hast-util-to-html';
|
|
19
19
|
import { getComponentById, getComponentByTitle, getModelId } from '../../domain/Definitions.js';
|
|
20
20
|
import {
|
|
21
|
-
findModelById,
|
|
21
|
+
findModelById,
|
|
22
|
+
getField, getModelFieldNames,
|
|
22
23
|
} from '../../domain/Models.js';
|
|
23
24
|
import { findAll } from '../../utils/mdast.js';
|
|
24
25
|
import link from './supports/link.js';
|
|
@@ -360,7 +361,7 @@ function getBlockItems(mdast, modelHelper, definitions, allowedComponents) {
|
|
|
360
361
|
const component = getComponentById(definitions, componentId);
|
|
361
362
|
const properties = {
|
|
362
363
|
...component.defaultFields,
|
|
363
|
-
modelFields: `[${
|
|
364
|
+
modelFields: `[${getModelFieldNames(fieldGroup.model).join(',')}]`,
|
|
364
365
|
};
|
|
365
366
|
|
|
366
367
|
extractProperties(row, fieldGroup.model, 'blockItem', component, fieldGroup.fields, properties);
|
|
@@ -428,7 +429,7 @@ function gridTablePartial(context) {
|
|
|
428
429
|
};
|
|
429
430
|
|
|
430
431
|
if (model) {
|
|
431
|
-
properties.modelFields = `[${
|
|
432
|
+
properties.modelFields = `[${getModelFieldNames(model).join(',')}]`;
|
|
432
433
|
}
|
|
433
434
|
|
|
434
435
|
let blockProperties = '';
|