Skip to content

Commit f51cc91

Browse files
authored
fix: improve array handling for html2json (#193)
* chore: add tests for html2json & json2html * fix: improve support for empty arrays and objects * fix: implement support for nested arrays of primitives and objects * chore: cleanup
1 parent 6fd0829 commit f51cc91

11 files changed

Lines changed: 1513 additions & 13 deletions

File tree

nx/blocks/form/utils/html2json.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,22 @@ export default class HTMLConverter {
5757
* Find and convert a block to its basic JSON data
5858
* @param {String} searchTerm the block name or variation
5959
* @param {Boolean} searchRef if the variation should be used for search
60-
* @returns {Object} the JSON Object representing pug
60+
* @returns {Object|Array} the JSON Object or Array representing the block
6161
*/
6262
findAndConvert(searchTerm, searchRef) {
6363
return this.blocks.reduce((acc, block) => {
6464
// If we are looking for a reference,
6565
// use the variation, not the block name
6666
const idx = searchRef ? 1 : 0;
6767
if (block.properties.className[idx] === searchTerm) {
68-
return this.getProperties(block);
68+
const properties = this.getProperties(block);
69+
// If the block contains only @items, it represents an array
70+
// Return the array value directly instead of the object wrapper
71+
const keys = Object.keys(properties);
72+
if (keys.length === 1 && keys[0] === '@items') {
73+
return properties['@items'];
74+
}
75+
return properties;
6976
}
7077
return acc;
7178
}, {});

nx/blocks/form/utils/json2html.js

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,43 @@ function createNestedBlock(key, obj, nestedBlocks) {
4545
return guid;
4646
}
4747

48+
function createArrayBlock(key, arr, nestedBlocks) {
49+
const guid = Math.random().toString(36).substring(2, 8);
50+
const arrayBlock = createBlock(`${key} ${key}-${guid}`);
51+
52+
// Create a row with @items key, but process array items with original key
53+
const valCol = document.createElement('div');
54+
const ul = document.createElement('ul');
55+
56+
arr.forEach((item) => {
57+
if (Array.isArray(item)) {
58+
// Nested array within array
59+
const itemGuid = createArrayBlock(key, item, nestedBlocks);
60+
const li = document.createElement('li');
61+
li.textContent = `self://#${key}-${itemGuid}`;
62+
ul.append(li);
63+
} else if (typeof item === 'object' && item !== null) {
64+
// Object within array - use original key, not '@items'
65+
const itemGuid = createNestedBlock(key, item, nestedBlocks);
66+
const li = document.createElement('li');
67+
li.textContent = `self://#${key}-${itemGuid}`;
68+
ul.append(li);
69+
} else {
70+
// Primitive within array
71+
const li = document.createElement('li');
72+
li.textContent = item;
73+
ul.append(li);
74+
}
75+
});
76+
77+
valCol.append(ul);
78+
const row = createRow('@items', valCol);
79+
80+
arrayBlock.append(row);
81+
nestedBlocks.push(arrayBlock);
82+
return guid;
83+
}
84+
4885
function createValueCol(key, value, nestedBlocks) {
4986
const valCol = document.createElement('div');
5087

@@ -56,20 +93,27 @@ function createValueCol(key, value, nestedBlocks) {
5693
if (typeof value === 'object') {
5794
// Check if value is an array and create multiple nested blocks if needed
5895
if (Array.isArray(value)) {
59-
// If it's an array of objects, create a nested block for each object
60-
const ul = document.createElement('ul');
96+
// Skip empty arrays - don't create any HTML
6197
if (!value.length) {
62-
const li = document.createElement('li');
63-
ul.append(li);
98+
return null;
6499
}
100+
// Handle array items: could be arrays, objects, or primitives
101+
const ul = document.createElement('ul');
65102
value.forEach((item) => {
66-
if (typeof item === 'object' && item !== null) {
103+
if (Array.isArray(item)) {
104+
// Handle nested array (array within array)
105+
const guid = createArrayBlock(key, item, nestedBlocks);
106+
const li = document.createElement('li');
107+
li.textContent = `self://#${key}-${guid}`;
108+
ul.append(li);
109+
} else if (typeof item === 'object' && item !== null) {
110+
// Handle object within array
67111
const guid = createNestedBlock(key, item, nestedBlocks);
68112
const li = document.createElement('li');
69113
li.textContent = `self://#${key}-${guid}`;
70114
ul.append(li);
71115
} else {
72-
// If the array entry is a primitive, treat accordingly
116+
// Handle primitive within array
73117
const li = document.createElement('li');
74118
li.textContent = item;
75119
ul.append(li);
@@ -80,7 +124,10 @@ function createValueCol(key, value, nestedBlocks) {
80124
return valCol;
81125
}
82126

83-
// handle objects
127+
// handle objects - skip empty objects
128+
if (Object.keys(value).length === 0) {
129+
return null;
130+
}
84131
const guid = createNestedBlock(key, value, nestedBlocks);
85132
valPara.textContent = `self://#${key}-${guid}`;
86133
} else {
@@ -96,13 +143,16 @@ function createValueCol(key, value, nestedBlocks) {
96143
function getFormBlock(metadata, nestedBlocks) {
97144
const daForm = createBlock('da-form');
98145

99-
const rows = Object.entries(metadata).map((entry) => {
146+
const rows = Object.entries(metadata).flatMap((entry) => {
100147
const [key, value] = entry;
101148
const xKey = key === 'schemaName' ? 'x-schema-name' : key;
102149

103150
const valCol = createValueCol(key, value, nestedBlocks);
104151

105-
return createRow(xKey, valCol);
152+
// Skip if createValueCol returned null (empty array/object)
153+
if (!valCol) return [];
154+
155+
return [createRow(xKey, valCol)];
106156
});
107157

108158
daForm.append(...rows);
@@ -111,12 +161,15 @@ function getFormBlock(metadata, nestedBlocks) {
111161

112162
function getDataBlock(schemaName, data, nestedBlocks) {
113163
const dataBlock = createBlock(schemaName);
114-
const rows = Object.entries(data).map((entry) => {
164+
const rows = Object.entries(data).flatMap((entry) => {
115165
const [key, value] = entry;
116166

117167
const valCol = createValueCol(key, value, nestedBlocks);
118168

119-
return createRow(key, valCol);
169+
// Skip if createValueCol returned null (empty array/object)
170+
if (!valCol) return [];
171+
172+
return [createRow(key, valCol)];
120173
});
121174
dataBlock.append(...rows);
122175
return dataBlock;

0 commit comments

Comments
 (0)