json-to-spec 19.1.0
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/README.md +118 -0
- package/docs/demo.html +426 -0
- package/docs/dist/min.js +164 -0
- package/docs/dist/v1/min.js +124 -0
- package/docs/dist/v17/min.js +355 -0
- package/docs/dist/v18/min.js +160 -0
- package/docs/dist/v19/min.js +164 -0
- package/docs/dist/v2/min.js +129 -0
- package/docs/dist/v3/min.js +201 -0
- package/docs/index.html +248 -0
- package/docs/pages/architecture.html +115 -0
- package/docs/pages/how-it-works.html +125 -0
- package/docs/pages/what-not.html +100 -0
- package/docs/pages/what.html +105 -0
- package/docs/pages/why.html +88 -0
- package/docs/samples/form.html +265 -0
- package/docs/samples/index.html +112 -0
- package/docs/samples/table.html +306 -0
- package/index.js +2 -0
- package/package.json +50 -0
- package/samples/dataList/index.html +31 -0
- package/samples/dataList/index.js +62 -0
- package/samples/dataList/input/data.json +5043 -0
- package/samples/dataList/input/structure.json +38 -0
- package/samples/dataList copy/index.html +30 -0
- package/samples/dataList copy/index.js +61 -0
- package/samples/dataList copy/input/data.json +35307 -0
- package/samples/dataList copy/input/structure.json +18 -0
- package/samples/form/index.html +29 -0
- package/samples/form/index.js +64 -0
- package/samples/form/input/data.json +9 -0
- package/samples/form/input/structure.json +192 -0
- package/samples/form-/data.json +42 -0
- package/samples/form-/structure.json +110 -0
- package/samples/select/index.html +31 -0
- package/samples/select/index.js +61 -0
- package/samples/select/input/data.json +35287 -0
- package/samples/select/input/select.json +18 -0
- package/samples/select/input/structure.json +47 -0
- package/samples/table/index.html +29 -0
- package/samples/table/index.js +61 -0
- package/samples/table/input/data.json +35287 -0
- package/samples/table/input/structure copy.json +47 -0
- package/samples/table/input/structure.json +86 -0
- package/samples/table/input/table.json +135 -0
- package/samples/table-/data.json +68 -0
- package/samples/table-/structure.json +235 -0
- package/src/index.js +2 -0
- package/src/v10/index.js +96 -0
- package/src/v10/instructionEngine/compile/compileTree.js +191 -0
- package/src/v10/instructionEngine/compileTree.js +1 -0
- package/src/v10/instructionEngine/expandIteration.js +1 -0
- package/src/v10/instructionEngine/index.js +29 -0
- package/src/v10/instructionEngine/interpolate.js +2 -0
- package/src/v10/instructionEngine/iteration/expandIteration.js +95 -0
- package/src/v10/instructionEngine/operation/operation.js +237 -0
- package/src/v10/instructionEngine/other/other.js +150 -0
- package/src/v10/instructionEngine/pipeline/pipeline.js +47 -0
- package/src/v10/instructionEngine/replace/replace.js +173 -0
- package/src/v10/instructionEngine/resolve/resolvePath.js +18 -0
- package/src/v10/instructionEngine/resolve/resolveTokenValue.js +22 -0
- package/src/v10/instructionEngine/resolvePath.js +1 -0
- package/src/v10/instructionEngine/resolveTokenValue.js +1 -0
- package/src/v10/instructionEngine/story/storyInjector.js +50 -0
- package/src/v10/instructionEngine/storyInjector.js +1 -0
- package/src/v10/instructionEngine/value/interpolate.js +38 -0
- package/src/v11/index.js +116 -0
- package/src/v11/iterate.js +270 -0
- package/src/v11/replace.js +169 -0
- package/src/v11/resolvePath.js +29 -0
- package/src/v12/index.js +122 -0
- package/src/v12/iterate/bindFormValues.js +74 -0
- package/src/v12/iterate/expandIteration.js +181 -0
- package/src/v12/iterate/index.js +10 -0
- package/src/v12/iterate/iterate.js +56 -0
- package/src/v12/iterate/iterateNode.js +86 -0
- package/src/v12/iterate/resolveCollection.js +37 -0
- package/src/v12/iterate.js +270 -0
- package/src/v12/replace.js +169 -0
- package/src/v12/resolvePath.js +29 -0
- package/src/v13/index.js +110 -0
- package/src/v13/iterate/bindFormValues.js +74 -0
- package/src/v13/iterate/expandIteration.js +188 -0
- package/src/v13/iterate/index.js +9 -0
- package/src/v13/iterate/iterate.js +32 -0
- package/src/v13/iterate/iterateNode.js +86 -0
- package/src/v13/iterate/resolveCollection.js +37 -0
- package/src/v13/iterate/walk.js +90 -0
- package/src/v13/iterate.js +270 -0
- package/src/v13/replace.js +169 -0
- package/src/v13/resolvePath.js +29 -0
- package/src/v14/index.js +112 -0
- package/src/v14/iterate/bindFormValues.js +74 -0
- package/src/v14/iterate/expandIteration.js +188 -0
- package/src/v14/iterate/index.js +9 -0
- package/src/v14/iterate/iterate.js +32 -0
- package/src/v14/iterate/resolveCollection.js +37 -0
- package/src/v14/iterate/walk/walk copy 2.js +114 -0
- package/src/v14/iterate/walk/walk copy.js +90 -0
- package/src/v14/iterate/walk/walk.js +98 -0
- package/src/v14/iterate.js +270 -0
- package/src/v14/replace/index.js +16 -0
- package/src/v14/replace/walk.js +90 -0
- package/src/v14/replace.js +153 -0
- package/src/v14/resolvePath.js +29 -0
- package/src/v15/index.js +123 -0
- package/src/v15/iterate/bindFormValues.js +74 -0
- package/src/v15/iterate/expandIteration.js +188 -0
- package/src/v15/iterate/index.js +9 -0
- package/src/v15/iterate/iterate.js +32 -0
- package/src/v15/iterate/resolveCollection.js +37 -0
- package/src/v15/iterate/walk/walk copy 2.js +114 -0
- package/src/v15/iterate/walk/walk copy.js +90 -0
- package/src/v15/iterate/walk/walk.js +195 -0
- package/src/v15/iterate.js +270 -0
- package/src/v15/replace/index.js +16 -0
- package/src/v15/replace/walk.js +90 -0
- package/src/v15/replace.js +155 -0
- package/src/v15/resolvePath.js +29 -0
- package/src/v16/index.js +129 -0
- package/src/v16/iterate/bindFormValues.js +74 -0
- package/src/v16/iterate/expandIteration.js +188 -0
- package/src/v16/iterate/index.js +9 -0
- package/src/v16/iterate/iterate.js +32 -0
- package/src/v16/iterate/resolveCollection.js +37 -0
- package/src/v16/iterate/walk/walk copy 2.js +114 -0
- package/src/v16/iterate/walk/walk copy.js +90 -0
- package/src/v16/iterate/walk/walk.js +196 -0
- package/src/v16/iterate.js +270 -0
- package/src/v16/replace/index.js +16 -0
- package/src/v16/replace/walk.js +90 -0
- package/src/v16/replace.js +155 -0
- package/src/v16/resolvePath.js +29 -0
- package/src/v17/index.js +119 -0
- package/src/v17/iterate/bindFormValues.js +74 -0
- package/src/v17/iterate/expandIteration.js +188 -0
- package/src/v17/iterate/index.js +9 -0
- package/src/v17/iterate/iterate.js +32 -0
- package/src/v17/iterate/resolveCollection.js +37 -0
- package/src/v17/iterate/walk/iterateDo.js +42 -0
- package/src/v17/iterate/walk/replaceWithData.js +60 -0
- package/src/v17/iterate/walk/walk.js +94 -0
- package/src/v17/iterate.js +270 -0
- package/src/v17/replace/index.js +16 -0
- package/src/v17/replace/walk.js +90 -0
- package/src/v17/replace.js +160 -0
- package/src/v17/resolvePath.js +29 -0
- package/src/v18/index.js +66 -0
- package/src/v18/meta.js +7 -0
- package/src/v18/registerGlobal.js +17 -0
- package/src/v18/replace.js +18 -0
- package/src/v18/resolvePath.js +29 -0
- package/src/v18/walk/iterate/v1/index.js +42 -0
- package/src/v18/walk/iterate/v2/index.js +32 -0
- package/src/v18/walk/iterate/v3/index.js +46 -0
- package/src/v18/walk/iterate/v4/createChildren.js +24 -0
- package/src/v18/walk/iterate/v4/index.js +25 -0
- package/src/v18/walk/replaceWithData/v1/index.js +42 -0
- package/src/v18/walk/replaceWithData/v1/replaceCommon.js +21 -0
- package/src/v18/walk/replaceWithData/v2/index.js +105 -0
- package/src/v18/walk/replaceWithData/v2/replaceCommon.js +21 -0
- package/src/v18/walk/replaceWithData/v3/index.js +15 -0
- package/src/v18/walk/replaceWithData/v3/replaceAttributes.js +29 -0
- package/src/v18/walk/replaceWithData/v3/replaceCommon.js +23 -0
- package/src/v18/walk/replaceWithData/v3/replaceNodeValue.js +27 -0
- package/src/v18/walk/walk.js +94 -0
- package/src/v19/index.js +55 -0
- package/src/v19/meta.js +7 -0
- package/src/v19/registerGlobal.js +17 -0
- package/src/v19/replace.js +18 -0
- package/src/v19/resolvePath.js +29 -0
- package/src/v19/walk/iterate/v1/index.js +42 -0
- package/src/v19/walk/iterate/v2/index.js +32 -0
- package/src/v19/walk/iterate/v3/index.js +46 -0
- package/src/v19/walk/iterate/v4/createChildren.js +27 -0
- package/src/v19/walk/iterate/v4/index.js +25 -0
- package/src/v19/walk/replaceWithData/v1/index.js +42 -0
- package/src/v19/walk/replaceWithData/v1/replaceCommon.js +21 -0
- package/src/v19/walk/replaceWithData/v2/index.js +105 -0
- package/src/v19/walk/replaceWithData/v2/replaceCommon.js +21 -0
- package/src/v19/walk/replaceWithData/v3/index.js +15 -0
- package/src/v19/walk/replaceWithData/v3/replaceAttributes.js +29 -0
- package/src/v19/walk/replaceWithData/v3/replaceCommon.js +23 -0
- package/src/v19/walk/replaceWithData/v3/replaceNodeValue.js +27 -0
- package/src/v19/walk/walk.js +97 -0
- package/src/v8/index.js +69 -0
- package/src/v8/instructionEngine/compile/compileTree.js +191 -0
- package/src/v8/instructionEngine/compileTree.js +1 -0
- package/src/v8/instructionEngine/expandIteration.js +1 -0
- package/src/v8/instructionEngine/index.js +16 -0
- package/src/v8/instructionEngine/interpolate.js +2 -0
- package/src/v8/instructionEngine/iteration/expandIteration.js +95 -0
- package/src/v8/instructionEngine/resolve/resolvePath.js +18 -0
- package/src/v8/instructionEngine/resolve/resolveTokenValue.js +22 -0
- package/src/v8/instructionEngine/resolvePath.js +1 -0
- package/src/v8/instructionEngine/resolveTokenValue.js +1 -0
- package/src/v8/instructionEngine/story/storyInjector.js +50 -0
- package/src/v8/instructionEngine/storyInjector.js +1 -0
- package/src/v8/instructionEngine/value/interpolate.js +38 -0
- package/src/v9/index.js +96 -0
- package/src/v9/instructionEngine/compile/compileTree.js +191 -0
- package/src/v9/instructionEngine/compileTree.js +1 -0
- package/src/v9/instructionEngine/expandIteration.js +1 -0
- package/src/v9/instructionEngine/index.js +29 -0
- package/src/v9/instructionEngine/interpolate.js +2 -0
- package/src/v9/instructionEngine/iteration/expandIteration.js +95 -0
- package/src/v9/instructionEngine/operation/operation.js +237 -0
- package/src/v9/instructionEngine/other/other.js +150 -0
- package/src/v9/instructionEngine/pipeline/pipeline.js +47 -0
- package/src/v9/instructionEngine/replace/replace.js +173 -0
- package/src/v9/instructionEngine/resolve/resolvePath.js +18 -0
- package/src/v9/instructionEngine/resolve/resolveTokenValue.js +22 -0
- package/src/v9/instructionEngine/resolvePath.js +1 -0
- package/src/v9/instructionEngine/resolveTokenValue.js +1 -0
- package/src/v9/instructionEngine/story/storyInjector.js +50 -0
- package/src/v9/instructionEngine/storyInjector.js +1 -0
- package/src/v9/instructionEngine/value/interpolate.js +38 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import resolveCollection from "./resolveCollection.js";
|
|
2
|
+
import bindFormValues from "./bindFormValues.js";
|
|
3
|
+
import { replaceNode } from "../replace.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Expands a single iteration directive into an array of
|
|
7
|
+
* specification nodes.
|
|
8
|
+
*/
|
|
9
|
+
const expandIteration = ({
|
|
10
|
+
inNode,
|
|
11
|
+
inContext,
|
|
12
|
+
inData,
|
|
13
|
+
iterateNode
|
|
14
|
+
}) => {
|
|
15
|
+
|
|
16
|
+
const localNode = inNode;
|
|
17
|
+
const localContext = inContext;
|
|
18
|
+
const localData = inData;
|
|
19
|
+
|
|
20
|
+
const instruction = localNode && (
|
|
21
|
+
localNode.jsonToSpec ||
|
|
22
|
+
(localNode.operation ? localNode : null)
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
if (!instruction) return undefined;
|
|
26
|
+
|
|
27
|
+
const operationType = instruction.operation;
|
|
28
|
+
|
|
29
|
+
if (
|
|
30
|
+
operationType !== "iterate" &&
|
|
31
|
+
!instruction.source &&
|
|
32
|
+
!instruction.$iterate
|
|
33
|
+
) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const sourceKey =
|
|
38
|
+
instruction.source ||
|
|
39
|
+
instruction.iterateOn ||
|
|
40
|
+
instruction.$iterate;
|
|
41
|
+
|
|
42
|
+
const collection = resolveCollection({
|
|
43
|
+
inNode: localNode,
|
|
44
|
+
inContext: localContext,
|
|
45
|
+
inData: localData
|
|
46
|
+
}) || [];
|
|
47
|
+
|
|
48
|
+
if (!Array.isArray(collection)) {
|
|
49
|
+
if (localNode && localNode.tagName) {
|
|
50
|
+
const cloned = { ...localNode };
|
|
51
|
+
delete cloned.jsonToSpec;
|
|
52
|
+
cloned.children = [];
|
|
53
|
+
return cloned;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const template =
|
|
60
|
+
instruction.template ||
|
|
61
|
+
instruction.item ||
|
|
62
|
+
{};
|
|
63
|
+
|
|
64
|
+
const filter = instruction.filter;
|
|
65
|
+
|
|
66
|
+
const filtered = collection.filter(item => {
|
|
67
|
+
if (!item || typeof item !== "object") {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (filter && typeof filter === "object") {
|
|
72
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
73
|
+
if (item[key] !== value) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (item.isVisible === false) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return true;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const expandedChildren = [];
|
|
87
|
+
|
|
88
|
+
filtered.forEach((item, index) => {
|
|
89
|
+
const itemContext = {
|
|
90
|
+
...localContext,
|
|
91
|
+
item,
|
|
92
|
+
...(typeof item === "object" && item !== null ? item : {}),
|
|
93
|
+
$index: index,
|
|
94
|
+
$number: index + 1
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
if (
|
|
98
|
+
sourceKey === "rows" ||
|
|
99
|
+
sourceKey.endsWith(".rows") ||
|
|
100
|
+
sourceKey === "items" ||
|
|
101
|
+
sourceKey.endsWith("Rows")
|
|
102
|
+
) {
|
|
103
|
+
itemContext.row = item;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
localContext.row &&
|
|
108
|
+
(item.field || item.columnName || item.name)
|
|
109
|
+
) {
|
|
110
|
+
const fieldKey =
|
|
111
|
+
item.field ||
|
|
112
|
+
item.columnName ||
|
|
113
|
+
item.name;
|
|
114
|
+
|
|
115
|
+
const cellValue = localContext.row[fieldKey];
|
|
116
|
+
|
|
117
|
+
if (cellValue !== undefined) {
|
|
118
|
+
itemContext.cellValue = cellValue;
|
|
119
|
+
itemContext.value = cellValue;
|
|
120
|
+
|
|
121
|
+
if (
|
|
122
|
+
typeof item === "object" &&
|
|
123
|
+
item !== null &&
|
|
124
|
+
item.value === undefined
|
|
125
|
+
) {
|
|
126
|
+
item.value = cellValue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const rawTemplate =
|
|
132
|
+
typeof template === "object" &&
|
|
133
|
+
template !== null
|
|
134
|
+
? JSON.parse(JSON.stringify(template))
|
|
135
|
+
: {
|
|
136
|
+
tagName: "span",
|
|
137
|
+
textContent: template
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const iteratedTemplate = iterateNode({
|
|
141
|
+
inNode: rawTemplate,
|
|
142
|
+
inContext: itemContext,
|
|
143
|
+
inData: localData
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const replacedTemplate = replaceNode({
|
|
147
|
+
inNode: iteratedTemplate,
|
|
148
|
+
inContext: itemContext,
|
|
149
|
+
inData: localData
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
bindFormValues({
|
|
153
|
+
inNode: replacedTemplate,
|
|
154
|
+
inItem: item,
|
|
155
|
+
inData: localData
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (Array.isArray(replacedTemplate)) {
|
|
159
|
+
expandedChildren.push(...replacedTemplate);
|
|
160
|
+
} else if (
|
|
161
|
+
replacedTemplate !== null &&
|
|
162
|
+
replacedTemplate !== undefined
|
|
163
|
+
) {
|
|
164
|
+
expandedChildren.push(replacedTemplate);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (localNode && localNode.tagName) {
|
|
169
|
+
const cloned = { ...localNode };
|
|
170
|
+
|
|
171
|
+
delete cloned.jsonToSpec;
|
|
172
|
+
|
|
173
|
+
cloned.children = expandedChildren;
|
|
174
|
+
|
|
175
|
+
return cloned;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return expandedChildren;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export default expandIteration;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import iterateNode from "./iterateNode.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Main iterate operation.
|
|
5
|
+
*
|
|
6
|
+
* Input:
|
|
7
|
+
* structure + data
|
|
8
|
+
*
|
|
9
|
+
* Output:
|
|
10
|
+
* expanded structure
|
|
11
|
+
*/
|
|
12
|
+
export const iterate = (inStructureOrOptions, inData = {}) => {
|
|
13
|
+
let localStructure = inStructureOrOptions;
|
|
14
|
+
let localData = inData;
|
|
15
|
+
let localContext = {};
|
|
16
|
+
|
|
17
|
+
if (
|
|
18
|
+
inStructureOrOptions &&
|
|
19
|
+
typeof inStructureOrOptions === "object" &&
|
|
20
|
+
!Array.isArray(inStructureOrOptions)
|
|
21
|
+
) {
|
|
22
|
+
if (
|
|
23
|
+
"inStructure" in inStructureOrOptions ||
|
|
24
|
+
"inTree" in inStructureOrOptions ||
|
|
25
|
+
"inNode" in inStructureOrOptions
|
|
26
|
+
) {
|
|
27
|
+
localStructure =
|
|
28
|
+
inStructureOrOptions.inStructure ||
|
|
29
|
+
inStructureOrOptions.inTree ||
|
|
30
|
+
inStructureOrOptions.inNode;
|
|
31
|
+
|
|
32
|
+
localData =
|
|
33
|
+
inStructureOrOptions.inData || localData;
|
|
34
|
+
|
|
35
|
+
localContext =
|
|
36
|
+
inStructureOrOptions.inContext || localContext;
|
|
37
|
+
|
|
38
|
+
} else if ("structure" in inStructureOrOptions) {
|
|
39
|
+
localStructure = inStructureOrOptions.structure;
|
|
40
|
+
localData =
|
|
41
|
+
inStructureOrOptions.data || localData;
|
|
42
|
+
localContext =
|
|
43
|
+
inStructureOrOptions.context || localContext;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return iterateNode({
|
|
48
|
+
inNode: localStructure,
|
|
49
|
+
inContext: localContext,
|
|
50
|
+
inData: localData
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const operation = iterate;
|
|
55
|
+
|
|
56
|
+
export default iterate;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import expandIteration from "./expandIteration.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Recursively walks a JSON structure and resolves
|
|
5
|
+
* jsonToSpec iteration directives.
|
|
6
|
+
*/
|
|
7
|
+
const iterateNode = ({
|
|
8
|
+
inNode,
|
|
9
|
+
inContext = {},
|
|
10
|
+
inData = {}
|
|
11
|
+
} = {}) => {
|
|
12
|
+
const localNode = inNode;
|
|
13
|
+
const localContext = inContext;
|
|
14
|
+
const localData = inData;
|
|
15
|
+
|
|
16
|
+
if (localNode === null || localNode === undefined) {
|
|
17
|
+
return localNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (Array.isArray(localNode)) {
|
|
21
|
+
const flattened = [];
|
|
22
|
+
|
|
23
|
+
for (const child of localNode) {
|
|
24
|
+
const processed = iterateNode({
|
|
25
|
+
inNode: child,
|
|
26
|
+
inContext: localContext,
|
|
27
|
+
inData: localData
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (Array.isArray(processed)) {
|
|
31
|
+
flattened.push(...processed);
|
|
32
|
+
} else if (
|
|
33
|
+
processed !== null &&
|
|
34
|
+
processed !== undefined
|
|
35
|
+
) {
|
|
36
|
+
flattened.push(processed);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return flattened;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof localNode !== "object") {
|
|
44
|
+
return localNode;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const iterationResult = expandIteration({
|
|
48
|
+
inNode: localNode,
|
|
49
|
+
inContext: localContext,
|
|
50
|
+
inData: localData,
|
|
51
|
+
iterateNode
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (iterationResult !== undefined) {
|
|
55
|
+
return iterationResult;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const clone = { ...localNode };
|
|
59
|
+
|
|
60
|
+
if (Array.isArray(clone.children)) {
|
|
61
|
+
const processedChildren = [];
|
|
62
|
+
|
|
63
|
+
for (const child of clone.children) {
|
|
64
|
+
const processed = iterateNode({
|
|
65
|
+
inNode: child,
|
|
66
|
+
inContext: localContext,
|
|
67
|
+
inData: localData
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (Array.isArray(processed)) {
|
|
71
|
+
processedChildren.push(...processed);
|
|
72
|
+
} else if (
|
|
73
|
+
processed !== null &&
|
|
74
|
+
processed !== undefined
|
|
75
|
+
) {
|
|
76
|
+
processedChildren.push(processed);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
clone.children = processedChildren;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return clone;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export default iterateNode;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import resolvePath from "../resolvePath.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the collection array targeted by an iteration instruction.
|
|
5
|
+
*/
|
|
6
|
+
const resolveCollection = ({ inNode, inContext, inData }) => {
|
|
7
|
+
const localNode = inNode;
|
|
8
|
+
const localContext = inContext;
|
|
9
|
+
const localData = inData;
|
|
10
|
+
|
|
11
|
+
const instruction = localNode && (
|
|
12
|
+
localNode.jsonToSpec ||
|
|
13
|
+
(localNode.operation ? localNode : null)
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (!instruction) return undefined;
|
|
17
|
+
|
|
18
|
+
const sourceKey =
|
|
19
|
+
instruction.source ||
|
|
20
|
+
instruction.iterateOn ||
|
|
21
|
+
instruction.$iterate;
|
|
22
|
+
|
|
23
|
+
if (!sourceKey) return undefined;
|
|
24
|
+
|
|
25
|
+
return resolvePath({
|
|
26
|
+
inData: localData,
|
|
27
|
+
inPath: sourceKey
|
|
28
|
+
})
|
|
29
|
+
|| (localData && localData[sourceKey])
|
|
30
|
+
|| resolvePath({
|
|
31
|
+
inData: localContext,
|
|
32
|
+
inPath: sourceKey
|
|
33
|
+
})
|
|
34
|
+
|| (localContext && localContext[sourceKey]);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default resolveCollection;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import resolvePath from "./resolvePath.js";
|
|
2
|
+
import { replaceNode } from "./replace.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the collection array targeted by an iteration instruction.
|
|
6
|
+
*/
|
|
7
|
+
const resolveCollection = ({ inNode, inContext, inData }) => {
|
|
8
|
+
const localNode = inNode;
|
|
9
|
+
const localContext = inContext;
|
|
10
|
+
const localData = inData;
|
|
11
|
+
|
|
12
|
+
const instruction = localNode && (localNode.jsonToSpec || (localNode.operation ? localNode : null));
|
|
13
|
+
if (!instruction) return undefined;
|
|
14
|
+
|
|
15
|
+
const sourceKey = instruction.source || instruction.iterateOn || instruction.$iterate;
|
|
16
|
+
if (!sourceKey) return undefined;
|
|
17
|
+
|
|
18
|
+
return resolvePath({ inData: localData, inPath: sourceKey })
|
|
19
|
+
|| (localData && localData[sourceKey])
|
|
20
|
+
|| resolvePath({ inData: localContext, inPath: sourceKey })
|
|
21
|
+
|| (localContext && localContext[sourceKey]);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Recursively binds form field values into input, textarea, select, option nodes.
|
|
26
|
+
*/
|
|
27
|
+
const bindFormValues = ({ inNode, inItem, inData }) => {
|
|
28
|
+
const localNode = inNode;
|
|
29
|
+
const localItem = inItem;
|
|
30
|
+
const localData = inData;
|
|
31
|
+
|
|
32
|
+
if (!localNode || typeof localNode !== "object") return localNode;
|
|
33
|
+
|
|
34
|
+
if (localNode.attributes) {
|
|
35
|
+
const isFormField = ["input", "textarea", "select", "option"].includes(localNode.tagName?.toLowerCase());
|
|
36
|
+
if (isFormField) {
|
|
37
|
+
const fieldName = localItem.field || localItem.columnName || localItem.name;
|
|
38
|
+
if (localItem.value !== undefined && localItem.value !== null) {
|
|
39
|
+
localNode.attributes.value = String(localItem.value);
|
|
40
|
+
if (localNode.tagName === "textarea" && !localNode.textContent) {
|
|
41
|
+
localNode.textContent = String(localItem.value);
|
|
42
|
+
}
|
|
43
|
+
} else if (fieldName && localData[fieldName] !== undefined && localData[fieldName] !== null) {
|
|
44
|
+
localNode.attributes.value = String(localData[fieldName]);
|
|
45
|
+
if (localNode.tagName === "textarea" && !localNode.textContent) {
|
|
46
|
+
localNode.textContent = String(localData[fieldName]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (Array.isArray(localNode.children)) {
|
|
53
|
+
localNode.children.forEach(child => bindFormValues({ inNode: child, inItem: localItem, inData: localData }));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return localNode;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Expands a single iteration directive into an array of DOM element nodes.
|
|
61
|
+
*/
|
|
62
|
+
const expandIteration = ({ inNode, inContext, inData }) => {
|
|
63
|
+
const localNode = inNode;
|
|
64
|
+
const localContext = inContext;
|
|
65
|
+
const localData = inData;
|
|
66
|
+
|
|
67
|
+
const instruction = localNode && (localNode.jsonToSpec || (localNode.operation ? localNode : null));
|
|
68
|
+
if (!instruction) return undefined;
|
|
69
|
+
|
|
70
|
+
const operationType = instruction.operation;
|
|
71
|
+
if (operationType !== "iterate" && !instruction.source && !instruction.$iterate) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const sourceKey = instruction.source || instruction.iterateOn || instruction.$iterate;
|
|
76
|
+
const collection = resolveCollection({
|
|
77
|
+
inNode: localNode,
|
|
78
|
+
inContext: localContext,
|
|
79
|
+
inData: localData
|
|
80
|
+
}) || [];
|
|
81
|
+
|
|
82
|
+
if (!Array.isArray(collection)) {
|
|
83
|
+
if (localNode && localNode.tagName) {
|
|
84
|
+
const cloned = { ...localNode };
|
|
85
|
+
delete cloned.jsonToSpec;
|
|
86
|
+
cloned.children = [];
|
|
87
|
+
return cloned;
|
|
88
|
+
}
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const template = instruction.template || instruction.item || {};
|
|
93
|
+
const filter = instruction.filter;
|
|
94
|
+
|
|
95
|
+
const filtered = collection.filter(item => {
|
|
96
|
+
if (!item || typeof item !== "object") return true;
|
|
97
|
+
if (filter && typeof filter === "object") {
|
|
98
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
99
|
+
if (item[key] !== value) return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (item.isVisible === false) return false;
|
|
103
|
+
return true;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const expandedChildren = [];
|
|
107
|
+
filtered.forEach((item, index) => {
|
|
108
|
+
const itemContext = {
|
|
109
|
+
...localContext,
|
|
110
|
+
item,
|
|
111
|
+
...(typeof item === "object" && item !== null ? item : {}),
|
|
112
|
+
$index: index,
|
|
113
|
+
$number: index + 1
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (sourceKey === "rows" || sourceKey.endsWith(".rows") || sourceKey === "items" || sourceKey.endsWith("Rows")) {
|
|
117
|
+
itemContext.row = item;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (localContext.row && (item.field || item.columnName || item.name)) {
|
|
121
|
+
const fieldKey = item.field || item.columnName || item.name;
|
|
122
|
+
const cellValue = localContext.row[fieldKey];
|
|
123
|
+
if (cellValue !== undefined) {
|
|
124
|
+
itemContext.cellValue = cellValue;
|
|
125
|
+
itemContext.value = cellValue;
|
|
126
|
+
if (typeof item === "object" && item !== null && item.value === undefined) {
|
|
127
|
+
item.value = cellValue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 1. Clone the template
|
|
133
|
+
const rawTemplate = typeof template === "object" && template !== null
|
|
134
|
+
? JSON.parse(JSON.stringify(template))
|
|
135
|
+
: { tagName: "span", textContent: template };
|
|
136
|
+
|
|
137
|
+
// 2. Expand any nested iterations within the template
|
|
138
|
+
const iteratedTemplate = iterateNode({
|
|
139
|
+
inNode: rawTemplate,
|
|
140
|
+
inContext: itemContext,
|
|
141
|
+
inData: localData
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// 3. Replace item-level tokens in the template
|
|
145
|
+
const replacedTemplate = replaceNode({
|
|
146
|
+
inNode: iteratedTemplate,
|
|
147
|
+
inContext: itemContext,
|
|
148
|
+
inData: localData
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
bindFormValues({
|
|
152
|
+
inNode: replacedTemplate,
|
|
153
|
+
inItem: item,
|
|
154
|
+
inData: localData
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (Array.isArray(replacedTemplate)) {
|
|
158
|
+
expandedChildren.push(...replacedTemplate);
|
|
159
|
+
} else if (replacedTemplate !== null && replacedTemplate !== undefined) {
|
|
160
|
+
expandedChildren.push(replacedTemplate);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// If jsonToSpec was a sibling on a container node (e.g. <div class="row" jsonToSpec="...">)
|
|
165
|
+
if (localNode && localNode.tagName) {
|
|
166
|
+
const cloned = { ...localNode };
|
|
167
|
+
delete cloned.jsonToSpec;
|
|
168
|
+
cloned.children = expandedChildren;
|
|
169
|
+
return cloned;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return expandedChildren;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Recursively walks a JSON tree and resolves all jsonToSpec iteration directives.
|
|
177
|
+
*/
|
|
178
|
+
export const iterateNode = ({ inNode, inContext = {}, inData = {} } = {}) => {
|
|
179
|
+
const localNode = inNode;
|
|
180
|
+
const localContext = inContext;
|
|
181
|
+
const localData = inData;
|
|
182
|
+
|
|
183
|
+
if (localNode === null || localNode === undefined) return localNode;
|
|
184
|
+
|
|
185
|
+
if (Array.isArray(localNode)) {
|
|
186
|
+
const flattened = [];
|
|
187
|
+
for (const child of localNode) {
|
|
188
|
+
const processed = iterateNode({
|
|
189
|
+
inNode: child,
|
|
190
|
+
inContext: localContext,
|
|
191
|
+
inData: localData
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (Array.isArray(processed)) {
|
|
195
|
+
flattened.push(...processed);
|
|
196
|
+
} else if (processed !== null && processed !== undefined) {
|
|
197
|
+
flattened.push(processed);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return flattened;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (typeof localNode !== "object") {
|
|
204
|
+
return localNode;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Check if current node is or has an iteration directive
|
|
208
|
+
const iterationResult = expandIteration({
|
|
209
|
+
inNode: localNode,
|
|
210
|
+
inContext: localContext,
|
|
211
|
+
inData: localData
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
if (iterationResult !== undefined) {
|
|
215
|
+
return iterationResult;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Standard node: recursively process children
|
|
219
|
+
const clone = { ...localNode };
|
|
220
|
+
|
|
221
|
+
if (Array.isArray(clone.children)) {
|
|
222
|
+
const processedChildren = [];
|
|
223
|
+
for (const child of clone.children) {
|
|
224
|
+
const processed = iterateNode({
|
|
225
|
+
inNode: child,
|
|
226
|
+
inContext: localContext,
|
|
227
|
+
inData: localData
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (Array.isArray(processed)) {
|
|
231
|
+
processedChildren.push(...processed);
|
|
232
|
+
} else if (processed !== null && processed !== undefined) {
|
|
233
|
+
processedChildren.push(processed);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
clone.children = processedChildren;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return clone;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Main iterate/operation function: (structure, data) -> expanded JSON specification
|
|
244
|
+
*/
|
|
245
|
+
export const iterate = (inStructureOrOptions, inData = {}) => {
|
|
246
|
+
let localStructure = inStructureOrOptions;
|
|
247
|
+
let localData = inData;
|
|
248
|
+
let localContext = {};
|
|
249
|
+
|
|
250
|
+
if (inStructureOrOptions && typeof inStructureOrOptions === "object" && !Array.isArray(inStructureOrOptions)) {
|
|
251
|
+
if ("inStructure" in inStructureOrOptions || "inTree" in inStructureOrOptions || "inNode" in inStructureOrOptions) {
|
|
252
|
+
localStructure = inStructureOrOptions.inStructure || inStructureOrOptions.inTree || inStructureOrOptions.inNode;
|
|
253
|
+
localData = inStructureOrOptions.inData || localData;
|
|
254
|
+
localContext = inStructureOrOptions.inContext || localContext;
|
|
255
|
+
} else if ("structure" in inStructureOrOptions) {
|
|
256
|
+
localStructure = inStructureOrOptions.structure;
|
|
257
|
+
localData = inStructureOrOptions.data || localData;
|
|
258
|
+
localContext = inStructureOrOptions.context || localContext;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return iterateNode({
|
|
263
|
+
inNode: localStructure,
|
|
264
|
+
inContext: localContext,
|
|
265
|
+
inData: localData
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export const operation = iterate;
|
|
270
|
+
export default iterate;
|