@adobe/helix-md2jcr 1.1.33 → 1.1.35
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/docs/field-hinting.md +190 -0
- package/package.json +5 -5
- package/src/mdast2jcr/hb/partials/grid-table.js +25 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.1.35](https://github.com/adobe/helix-md2jcr/compare/v1.1.34...v1.1.35) (2025-09-23)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* support html comments generated with createComment api ([#153](https://github.com/adobe/helix-md2jcr/issues/153)) ([dc8d06e](https://github.com/adobe/helix-md2jcr/commit/dc8d06e62643c738db639cc3276bd77f040d9ae7))
|
|
7
|
+
|
|
8
|
+
## [1.1.34](https://github.com/adobe/helix-md2jcr/compare/v1.1.33...v1.1.34) (2025-09-16)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **deps:** update adobe fixes ([#152](https://github.com/adobe/helix-md2jcr/issues/152)) ([cd12f99](https://github.com/adobe/helix-md2jcr/commit/cd12f99ec08e953a02769a5737cd2ab8081f8cc7))
|
|
14
|
+
|
|
1
15
|
## [1.1.33](https://github.com/adobe/helix-md2jcr/compare/v1.1.32...v1.1.33) (2025-09-03)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Modeling Guide
|
|
2
|
+
|
|
3
|
+
This document provides guidance on modeling content in the Helix MD2JCR system, with a focus on field hinting and its applications.
|
|
4
|
+
|
|
5
|
+
## Field Hinting
|
|
6
|
+
|
|
7
|
+
Field hinting is a powerful feature in the Helix MD2JCR system that allows you to explicitly specify which field in a component model should receive specific content from your markdown. This is particularly useful when the automatic field resolution doesn't match your intended content structure or when you need precise control over field mapping.
|
|
8
|
+
|
|
9
|
+
### Purpose of Field Hinting
|
|
10
|
+
|
|
11
|
+
Field hinting serves several important purposes:
|
|
12
|
+
|
|
13
|
+
1. **Precise Field Mapping**: When content doesn't naturally flow into the expected fields based on the model's field order, field hints allow you to explicitly direct content to specific fields.
|
|
14
|
+
|
|
15
|
+
2. **Content Structure Control**: In complex components with multiple fields of the same type (e.g., multiple text fields), field hints ensure content goes to the correct field.
|
|
16
|
+
|
|
17
|
+
3. **Sequential Field Mapping**: Field hints allow you to skip ahead to a specific field in the model's field sequence, but content must still be processed in the order it appears in the markdown.
|
|
18
|
+
|
|
19
|
+
### How Field Hinting Works
|
|
20
|
+
|
|
21
|
+
Field hints are implemented as HTML comments in your markdown content with the following syntax:
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<!-- field: fieldName -->
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The system recognizes these comments and uses them to direct the following content to the specified field. The field hint affects the next content node that would normally be processed.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
### Basic Blocks
|
|
33
|
+
|
|
34
|
+
Basic blocks typically have a simple field structure where each row corresponds to a single model field. Field hints are generally not useful for basic blocks since the automatic field resolution works well with this straightforward one-to-one mapping.
|
|
35
|
+
|
|
36
|
+
#### Example: Custom Block
|
|
37
|
+
|
|
38
|
+
Consider a custom block with the following model:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"id": "custom",
|
|
43
|
+
"fields": [
|
|
44
|
+
{
|
|
45
|
+
"component": "text",
|
|
46
|
+
"name": "classes"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"component": "richtext",
|
|
50
|
+
"name": "p_1"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"component": "reference",
|
|
54
|
+
"name": "p_2"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"component": "text",
|
|
58
|
+
"name": "p_2Alt"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"component": "text",
|
|
62
|
+
"name": "p_3"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Without field hints** (automatic resolution):
|
|
69
|
+
```markdown
|
|
70
|
+
+-------------------------------------------------------+
|
|
71
|
+
| Custom (greedy) |
|
|
72
|
+
+=======================================================+
|
|
73
|
+
| All text up to image is included: |
|
|
74
|
+
| ``` |
|
|
75
|
+
| console.log("hello") |
|
|
76
|
+
| ``` |
|
|
77
|
+
| <a href="www.google.com">Google</a> |
|
|
78
|
+
| |
|
|
79
|
+
| ![Image][image0] |
|
|
80
|
+
| |
|
|
81
|
+
| After image there's more text |
|
|
82
|
+
+-------------------------------------------------------+
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**With field hints** (explicit control skipping optional fields):
|
|
86
|
+
```markdown
|
|
87
|
+
+-------------------------------------------------------+
|
|
88
|
+
| Custom (greedy) |
|
|
89
|
+
+=======================================================+
|
|
90
|
+
| <!-- field: p_3 --> |
|
|
91
|
+
| After image there's more text |
|
|
92
|
+
+-------------------------------------------------------+
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Container Blocks
|
|
96
|
+
|
|
97
|
+
Container blocks are more complex and often benefit significantly from field hinting, especially when they have multiple fields of similar types.
|
|
98
|
+
|
|
99
|
+
#### Example: Teaser Component
|
|
100
|
+
|
|
101
|
+
Consider a teaser component with the following model:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"id": "teaser",
|
|
106
|
+
"fields": [
|
|
107
|
+
{
|
|
108
|
+
"component": "reference",
|
|
109
|
+
"name": "image",
|
|
110
|
+
"label": "Image"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"component": "text",
|
|
114
|
+
"name": "teaserText_subtitle",
|
|
115
|
+
"label": "Sub title"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"component": "text",
|
|
119
|
+
"name": "teaserText_title",
|
|
120
|
+
"label": "Title"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"component": "text",
|
|
124
|
+
"name": "teaserText_titleType",
|
|
125
|
+
"label": "Heading Type"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"component": "richtext",
|
|
129
|
+
"name": "teaserText_description",
|
|
130
|
+
"label": "Description"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"component": "text",
|
|
134
|
+
"name": "teaserText_cta",
|
|
135
|
+
"label": "CTA"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"component": "text",
|
|
139
|
+
"name": "teaserText_ctaText",
|
|
140
|
+
"label": "CTA Text"
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Without field hints** (automatic resolution):
|
|
147
|
+
```markdown
|
|
148
|
+
+-------------------------------------------------+
|
|
149
|
+
| Teaser |
|
|
150
|
+
+=================================================+
|
|
151
|
+
| ![A group of people sitting on a stage][image0] |
|
|
152
|
+
+-------------------------------------------------+
|
|
153
|
+
| Adobe Experience Cloud |
|
|
154
|
+
| ## Welcome to AEM |
|
|
155
|
+
| Join us in this ask me everything session ... |
|
|
156
|
+
+-------------------------------------------------+
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**With field hints** (explicit control):
|
|
160
|
+
```markdown
|
|
161
|
+
+-------------------------------------------------+
|
|
162
|
+
| Teaser |
|
|
163
|
+
+=================================================+
|
|
164
|
+
| ![A group of people sitting on a stage][image0] |
|
|
165
|
+
+-------------------------------------------------+
|
|
166
|
+
| <!-- field:teaserText_title --> |
|
|
167
|
+
| ## Welcome to AEM |
|
|
168
|
+
| Join us in this ask me everything session ... |
|
|
169
|
+
| <!-- field:teaserText_cta --> |
|
|
170
|
+
| **[Adobe](www.adobe.com)** |
|
|
171
|
+
+-------------------------------------------------+
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Best Practices
|
|
175
|
+
|
|
176
|
+
1. **Use field hints sparingly**: Only use field hints when automatic resolution doesn't work as expected or when you need precise control.
|
|
177
|
+
|
|
178
|
+
2. **Be explicit with field names**: Use the exact field names as defined in your model to avoid mapping errors.
|
|
179
|
+
|
|
180
|
+
3. **Consider content flow**: Must place field hints immediately before the content you want to map to that field.
|
|
181
|
+
|
|
182
|
+
4. **Test your mappings**: Verify that your field hints correctly map content to the intended fields by checking the generated JCR output.
|
|
183
|
+
|
|
184
|
+
### Common Use Cases
|
|
185
|
+
|
|
186
|
+
1. **Multiple text fields**: When a component has multiple text fields and you want to ensure content goes to the correct one.
|
|
187
|
+
|
|
188
|
+
2. **Rich text with mixed content**: When you have a rich text field that should contain specific content, followed by other field types.
|
|
189
|
+
|
|
190
|
+
Field hinting provides the flexibility and control needed to create complex, well-structured content while maintaining the simplicity of markdown authoring.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-md2jcr",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.35",
|
|
4
4
|
"description": "Helix Service that converts markdown to JCR content structure",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/adobe/helix-md2jcr#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@adobe/fetch": "4.2.
|
|
31
|
+
"@adobe/fetch": "4.2.3",
|
|
32
32
|
"@adobe/helix-markdown-support": "7.1.12",
|
|
33
33
|
"@adobe/helix-shared-process-queue": "3.1.3",
|
|
34
34
|
"@adobe/remark-gridtables": "3.0.14",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"xml-formatter": "^3.6.3"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@adobe/eslint-config-helix": "3.0.
|
|
58
|
-
"@adobe/helix-mediahandler": "2.
|
|
57
|
+
"@adobe/eslint-config-helix": "3.0.10",
|
|
58
|
+
"@adobe/helix-mediahandler": "2.9.2",
|
|
59
59
|
"@commitlint/cli": "^19.6.1",
|
|
60
60
|
"@commitlint/config-conventional": "^19.6.0",
|
|
61
61
|
"@semantic-release/changelog": "6.0.3",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@semantic-release/git": "10.0.1",
|
|
64
64
|
"c8": "10.1.3",
|
|
65
65
|
"chai": "^6.0.0",
|
|
66
|
-
"dotenv": "17.2.
|
|
66
|
+
"dotenv": "17.2.2",
|
|
67
67
|
"eslint": "^9.0.0",
|
|
68
68
|
"eslint-import-resolver-exports": "1.0.0-beta.5",
|
|
69
69
|
"eslint-plugin-header": "3.1.1",
|
|
@@ -197,8 +197,31 @@ function extractKeyValueProperties(row, model, fieldResolver, fieldGroup, proper
|
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Check if the node is a field name hint.
|
|
202
|
+
* @param {Node} node - the node to check
|
|
203
|
+
* @returns {boolean} - true if the node is a field name hint, false otherwise
|
|
204
|
+
*/
|
|
200
205
|
function isFieldNameHint(node) {
|
|
201
|
-
|
|
206
|
+
// get the node value and remove all whitespace from the value to test if it is a field name hint
|
|
207
|
+
if (node.type === 'html') {
|
|
208
|
+
const value = node.value.replace(/\s/g, '');
|
|
209
|
+
return value?.startsWith('<!--field:') && value?.endsWith('-->');
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get the field name hint value from the node.
|
|
216
|
+
* @param {Node} node - the node to get the field name hint value from
|
|
217
|
+
* @returns {string} - the field name hint value or null if the node is not a field name hint
|
|
218
|
+
*/
|
|
219
|
+
function fieldHintValue(node) {
|
|
220
|
+
if (node.type === 'html') {
|
|
221
|
+
const value = node.value.replace(/\s/g, '');
|
|
222
|
+
return value.split('<!--field:')[1].split('-->')[0].trim();
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
202
225
|
}
|
|
203
226
|
|
|
204
227
|
function processCell(cell, fieldGroup, fieldResolver, properties) {
|
|
@@ -223,7 +246,7 @@ function processCell(cell, fieldGroup, fieldResolver, properties) {
|
|
|
223
246
|
|
|
224
247
|
// if we see a property name hint, parse it and continue, unset it if not
|
|
225
248
|
if (isFieldNameHint(node)) {
|
|
226
|
-
nextFieldName = node
|
|
249
|
+
nextFieldName = fieldHintValue(node);
|
|
227
250
|
// eslint-disable-next-line no-continue
|
|
228
251
|
continue;
|
|
229
252
|
}
|