pict-section-form 1.0.143 → 1.0.145
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/.config/code-server/config.yaml +4 -0
- package/.vscode/settings.json +1 -1
- package/Dockerfile_LUXURYCode +31 -0
- package/debug/BuildHarnessTestApp.sh +1 -0
- package/debug/Harness.js +3 -2
- package/debug/PICTSection-TabularManifests.json +65 -22
- package/debug/Step-4-ConvertToCSV.js +3 -0
- package/debug/TabularManifestCSV.csv +9 -9
- package/debug/data/DefaultFormManifest.json +65 -22
- package/debug/data/MathExampleForm-Reconstituted.csv +69 -0
- package/debug/data/MathExampleForm.json +65 -22
- package/package.json +7 -4
- package/source/Pict-Section-Form.js +1 -0
- package/source/global.d.ts +8 -0
- package/source/services/ManifestConversionToCSV.js +653 -0
- package/source/services/ManifestFactory.js +24 -1
- package/source/views/Pict-View-Form-Metacontroller.js +3 -0
- package/source/views/support/Pict-View-PSF-Solver-Visualization.js +2 -1
- package/types/source/Pict-Section-Form.d.ts +1 -0
- package/types/source/providers/inputs/Pict-Provider-Input-Chart.d.ts +1 -0
- package/types/source/providers/inputs/Pict-Provider-Input-Chart.d.ts.map +1 -1
- package/types/source/services/ManifestConversionToCSV.d.ts +17 -0
- package/types/source/services/ManifestConversionToCSV.d.ts.map +1 -0
- package/types/source/services/ManifestFactory.d.ts.map +1 -1
- package/types/source/views/Pict-View-Form-Metacontroller.d.ts.map +1 -1
- package/types/source/views/support/Pict-View-PSF-Solver-Visualization.d.ts.map +1 -1
- package/utility/csvparser/ParseCSV-Program.js +2 -1
- package/utility/csvparser/ParseJSON-Command-GenerateCSV.js +116 -0
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
2
|
+
|
|
3
|
+
class ManifestConversionToCSV extends libFableServiceProviderBase
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pOptions, pServiceHash);
|
|
8
|
+
|
|
9
|
+
/** @type {import('pict') & { instantiateServiceProviderWithoutRegistration: (hash: string, options?: any, uuid?: string) => any }} */
|
|
10
|
+
this.fable;
|
|
11
|
+
/** @type {any} */
|
|
12
|
+
this.log;
|
|
13
|
+
/** @type {string} */
|
|
14
|
+
this.UUID;
|
|
15
|
+
|
|
16
|
+
this.CSV_HEADER = [
|
|
17
|
+
"Form",
|
|
18
|
+
"Form Name",
|
|
19
|
+
"SubManifest",
|
|
20
|
+
"DataOnly",
|
|
21
|
+
"Section Name",
|
|
22
|
+
"Section Hash",
|
|
23
|
+
"Group Name",
|
|
24
|
+
"Group Hash",
|
|
25
|
+
"Group Layout",
|
|
26
|
+
"Group CSS",
|
|
27
|
+
"Group Show Title",
|
|
28
|
+
"Row",
|
|
29
|
+
"Width",
|
|
30
|
+
"Minimum Row Count",
|
|
31
|
+
"Maximum Row Count",
|
|
32
|
+
"Input Address",
|
|
33
|
+
"Input Name",
|
|
34
|
+
"Input Hash",
|
|
35
|
+
"Input Extra",
|
|
36
|
+
"Units",
|
|
37
|
+
"DataType",
|
|
38
|
+
"Decimal Precision",
|
|
39
|
+
"InputType",
|
|
40
|
+
"Equation",
|
|
41
|
+
"Equation Ordinal",
|
|
42
|
+
"Default",
|
|
43
|
+
"Description",
|
|
44
|
+
"Tooltip",
|
|
45
|
+
"Input Notes",
|
|
46
|
+
"Entity",
|
|
47
|
+
"EntityColumnFilter",
|
|
48
|
+
"EntityDestination",
|
|
49
|
+
"SingleRecord",
|
|
50
|
+
"TriggerGroup",
|
|
51
|
+
"TriggerAddress",
|
|
52
|
+
"TriggerAllInputs",
|
|
53
|
+
"MarshalEmptyValues",
|
|
54
|
+
"ChartType",
|
|
55
|
+
"ChartLabelsAddress",
|
|
56
|
+
"ChartLabelsSolver",
|
|
57
|
+
"ChartDatasetsAddress",
|
|
58
|
+
"ChartDatasetsLabel",
|
|
59
|
+
"ChartDatasetsSolvers"
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// Generate the header to column mapping
|
|
63
|
+
this.CSV_COLUMN_MAP = {};
|
|
64
|
+
for (let i = 0; i < this.CSV_HEADER.length; i++)
|
|
65
|
+
{
|
|
66
|
+
let tmpColumnName = this.CSV_HEADER[i];
|
|
67
|
+
this.CSV_COLUMN_MAP[tmpColumnName] = i;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getRowFromDescriptor(pForm, pDescriptorKey, pDescriptor)
|
|
72
|
+
{
|
|
73
|
+
let tmpRow = new Array(this.CSV_HEADER.length).fill('');
|
|
74
|
+
|
|
75
|
+
if ((!pDescriptor) || (typeof(pDescriptor) !== 'object') || !pDescriptorKey || (typeof(pDescriptorKey) !== 'string'))
|
|
76
|
+
{
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let tmpPictForm = pDescriptor.PictForm;
|
|
81
|
+
|
|
82
|
+
tmpRow[this.CSV_COLUMN_MAP["Form"]] = pForm;
|
|
83
|
+
tmpRow[this.CSV_COLUMN_MAP["Form Name"]] = pDescriptor.FormName || '';
|
|
84
|
+
tmpRow[this.CSV_COLUMN_MAP["SubManifest"]] = '';
|
|
85
|
+
tmpRow[this.CSV_COLUMN_MAP["DataOnly"]] = (typeof(tmpPictForm) === 'undefined') ? '1' : '';
|
|
86
|
+
tmpRow[this.CSV_COLUMN_MAP["Section Name"]] = '';
|
|
87
|
+
tmpRow[this.CSV_COLUMN_MAP["Section Hash"]] = (tmpPictForm && tmpPictForm.Section) ? tmpPictForm.Section
|
|
88
|
+
: (pDescriptor.FormSection) ? pDescriptor.FormSection
|
|
89
|
+
: '';
|
|
90
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Name"]] = '';
|
|
91
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Hash"]] = (tmpPictForm && tmpPictForm.Group) ? tmpPictForm.Group
|
|
92
|
+
: (pDescriptor.FormGroup) ? pDescriptor.FormGroup
|
|
93
|
+
: '';
|
|
94
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Layout"]] = '';
|
|
95
|
+
tmpRow[this.CSV_COLUMN_MAP["Group CSS"]] = '';
|
|
96
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Show Title"]] = '';
|
|
97
|
+
tmpRow[this.CSV_COLUMN_MAP["Row"]] = (tmpPictForm && tmpPictForm.Row) ? tmpPictForm.Row : '';
|
|
98
|
+
tmpRow[this.CSV_COLUMN_MAP["Width"]] = (tmpPictForm && tmpPictForm.Width) ? tmpPictForm.Width : '';
|
|
99
|
+
tmpRow[this.CSV_COLUMN_MAP["Minimum Row Count"]] = '';
|
|
100
|
+
tmpRow[this.CSV_COLUMN_MAP["Maximum Row Count"]] = '';
|
|
101
|
+
tmpRow[this.CSV_COLUMN_MAP["Input Address"]] = (pDescriptor.DataAddress) ? pDescriptor.DataAddress : pDescriptorKey;
|
|
102
|
+
tmpRow[this.CSV_COLUMN_MAP["Input Name"]] = pDescriptor.Name || pDescriptor.DataAddress || pDescriptorKey;
|
|
103
|
+
tmpRow[this.CSV_COLUMN_MAP["Input Hash"]] = pDescriptor.Hash || pDescriptorKey;
|
|
104
|
+
tmpRow[this.CSV_COLUMN_MAP["Input Extra"]] = '';
|
|
105
|
+
tmpRow[this.CSV_COLUMN_MAP["Units"]] = (tmpPictForm && tmpPictForm.Units) ? tmpPictForm.Units : '';
|
|
106
|
+
tmpRow[this.CSV_COLUMN_MAP["DataType"]] = pDescriptor.DataType || 'String';
|
|
107
|
+
tmpRow[this.CSV_COLUMN_MAP["Decimal Precision"]] = (tmpPictForm && tmpPictForm.DecimalPrecision) ? tmpPictForm.DecimalPrecision : '';
|
|
108
|
+
tmpRow[this.CSV_COLUMN_MAP["InputType"]] = (tmpPictForm && tmpPictForm.InputType) ? tmpPictForm.InputType : '';
|
|
109
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation"]] = '';
|
|
110
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = '';
|
|
111
|
+
tmpRow[this.CSV_COLUMN_MAP["Default"]] = (pDescriptor.Default !== undefined) ? pDescriptor.Default : '';
|
|
112
|
+
tmpRow[this.CSV_COLUMN_MAP["Description"]] = (pDescriptor.Description) ? pDescriptor.Description : '';
|
|
113
|
+
tmpRow[this.CSV_COLUMN_MAP["Tooltip"]] = (tmpPictForm && tmpPictForm.Tooltip) ? tmpPictForm.Tooltip : '';
|
|
114
|
+
tmpRow[this.CSV_COLUMN_MAP["Input Notes"]] = (tmpPictForm && tmpPictForm.SpreadsheetNotes) ? tmpPictForm.SpreadsheetNotes : '';
|
|
115
|
+
|
|
116
|
+
tmpRow[this.CSV_COLUMN_MAP["Entity"]] = '';
|
|
117
|
+
tmpRow[this.CSV_COLUMN_MAP["EntityColumnFilter"]] = '';
|
|
118
|
+
tmpRow[this.CSV_COLUMN_MAP["EntityDestination"]] = '';
|
|
119
|
+
tmpRow[this.CSV_COLUMN_MAP["SingleRecord"]] = '';
|
|
120
|
+
/**
|
|
121
|
+
tmpDescriptor.PictForm.EntitiesBundle = [
|
|
122
|
+
{
|
|
123
|
+
"Entity": tmpRecord.Entity,
|
|
124
|
+
"Filter": `FBV~${tmpRecord.EntityColumnFilter}~EQ~{~D:Record.Value~}`,
|
|
125
|
+
"Destination": tmpRecord.EntityDestination,
|
|
126
|
+
// This marshals a single record
|
|
127
|
+
"SingleRecord": tmpRecord.EntitySingleRecord ? true : false
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
*/
|
|
131
|
+
if (tmpPictForm && tmpPictForm.EntitiesBundle && Array.isArray(tmpPictForm.EntitiesBundle) && tmpPictForm.EntitiesBundle.length > 0)
|
|
132
|
+
{
|
|
133
|
+
let tmpEntityBundle = tmpPictForm.EntitiesBundle[0];
|
|
134
|
+
if (tmpEntityBundle.Entity)
|
|
135
|
+
{
|
|
136
|
+
tmpRow[this.CSV_COLUMN_MAP["Entity"]] = tmpEntityBundle.Entity;
|
|
137
|
+
}
|
|
138
|
+
// Pull the filter column out if we can; we only want what's between "FBV~" and "~EQ~"
|
|
139
|
+
if (tmpEntityBundle.Filter)
|
|
140
|
+
{
|
|
141
|
+
let tmpFilter = tmpEntityBundle.Filter;
|
|
142
|
+
let tmpFilterStart = tmpFilter.indexOf('FBV~');
|
|
143
|
+
let tmpFilterEnd = tmpFilter.indexOf('~EQ~');
|
|
144
|
+
if ((tmpFilterStart >= 0) && (tmpFilterEnd > tmpFilterStart))
|
|
145
|
+
{
|
|
146
|
+
let tmpColumnFilter = tmpFilter.substring(tmpFilterStart + 4, tmpFilterEnd);
|
|
147
|
+
tmpRow[this.CSV_COLUMN_MAP["EntityColumnFilter"]] = tmpColumnFilter;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (tmpEntityBundle.Destination)
|
|
151
|
+
{
|
|
152
|
+
tmpRow[this.CSV_COLUMN_MAP["EntityDestination"]] = tmpEntityBundle.Destination;
|
|
153
|
+
}
|
|
154
|
+
if (tmpEntityBundle.SingleRecord)
|
|
155
|
+
{
|
|
156
|
+
tmpRow[this.CSV_COLUMN_MAP["SingleRecord"]] = 'true';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
tmpRow[this.CSV_COLUMN_MAP["TriggerGroup"]] = '';
|
|
161
|
+
tmpRow[this.CSV_COLUMN_MAP["TriggerAddress"]] = '';
|
|
162
|
+
tmpRow[this.CSV_COLUMN_MAP["TriggerAllInputs"]] = '';
|
|
163
|
+
tmpRow[this.CSV_COLUMN_MAP["MarshalEmptyValues"]] = '';
|
|
164
|
+
if (tmpPictForm && tmpPictForm.AutofillTriggerGroup)
|
|
165
|
+
{
|
|
166
|
+
// Grab the first trigger group and put it in here.
|
|
167
|
+
let tmpTriggerGroup;
|
|
168
|
+
if (Array.isArray(tmpPictForm.AutofillTriggerGroup) && tmpPictForm.AutofillTriggerGroup.length > 0)
|
|
169
|
+
{
|
|
170
|
+
tmpTriggerGroup = tmpPictForm.AutofillTriggerGroup[0];
|
|
171
|
+
}
|
|
172
|
+
else if (typeof(tmpPictForm.AutofillTriggerGroup) === 'object')
|
|
173
|
+
{
|
|
174
|
+
tmpTriggerGroup = tmpPictForm.AutofillTriggerGroup;
|
|
175
|
+
}
|
|
176
|
+
if (tmpTriggerGroup)
|
|
177
|
+
{
|
|
178
|
+
if (tmpTriggerGroup.TriggerGroupHash)
|
|
179
|
+
{
|
|
180
|
+
tmpRow[this.CSV_COLUMN_MAP["TriggerGroup"]] = tmpTriggerGroup.TriggerGroupHash;
|
|
181
|
+
}
|
|
182
|
+
if (tmpTriggerGroup.TriggerAllInputs)
|
|
183
|
+
{
|
|
184
|
+
tmpRow[this.CSV_COLUMN_MAP["TriggerAllInputs"]] = 'true';
|
|
185
|
+
}
|
|
186
|
+
if (tmpTriggerGroup.TriggerAddress)
|
|
187
|
+
{
|
|
188
|
+
tmpRow[this.CSV_COLUMN_MAP["TriggerAddress"]] = tmpTriggerGroup.TriggerAddress;
|
|
189
|
+
}
|
|
190
|
+
if (tmpTriggerGroup.MarshalEmptyValues)
|
|
191
|
+
{
|
|
192
|
+
tmpRow[this.CSV_COLUMN_MAP["MarshalEmptyValues"]] = 'true';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
tmpRow[this.CSV_COLUMN_MAP["ChartType"]] = (tmpPictForm && tmpPictForm.ChartType) ? tmpPictForm.ChartType : '';
|
|
197
|
+
tmpRow[this.CSV_COLUMN_MAP["ChartLabelsAddress"]] = (tmpPictForm && tmpPictForm.ChartLabelsAddress) ? tmpPictForm.ChartLabelsAddress : '';
|
|
198
|
+
tmpRow[this.CSV_COLUMN_MAP["ChartLabelsSolver"]] = (tmpPictForm && tmpPictForm.ChartLabelsSolver) ? tmpPictForm.ChartLabelsSolver : '';
|
|
199
|
+
tmpRow[this.CSV_COLUMN_MAP["ChartDatasetsAddress"]] = (tmpPictForm && tmpPictForm.ChartDatasetsAddress) ? tmpPictForm.ChartDatasetsAddress : '';
|
|
200
|
+
tmpRow[this.CSV_COLUMN_MAP["ChartDatasetsLabel"]] = (tmpPictForm && tmpPictForm.ChartDatasetsSolvers && Array.isArray(tmpPictForm.ChartDatasetsSolvers) && tmpPictForm.ChartDatasetsSolvers.length > 0) ? tmpPictForm.ChartDatasetsSolvers[0].Label : '';
|
|
201
|
+
tmpRow[this.CSV_COLUMN_MAP["ChartDatasetsSolvers"]] = (tmpPictForm && tmpPictForm.ChartDatasetsSolvers && Array.isArray(tmpPictForm.ChartDatasetsSolvers) && tmpPictForm.ChartDatasetsSolvers.length > 0) ? tmpPictForm.ChartDatasetsSolvers[0].DataSolver : '';
|
|
202
|
+
|
|
203
|
+
if (tmpPictForm && (tmpPictForm.InputType == 'Option') && tmpPictForm.SelectOptions && Array.isArray(tmpPictForm.SelectOptions))
|
|
204
|
+
{
|
|
205
|
+
// Pull the select options into the Input Extra field as a comma-delimited list
|
|
206
|
+
let tmpInputExtraOptions = '';
|
|
207
|
+
|
|
208
|
+
for (let i = 0; i < tmpPictForm.SelectOptions.length; i++)
|
|
209
|
+
{
|
|
210
|
+
let tmpOption = tmpPictForm.SelectOptions[i];
|
|
211
|
+
|
|
212
|
+
if (tmpOption.id && tmpOption.text)
|
|
213
|
+
{
|
|
214
|
+
if (tmpInputExtraOptions.length > 0)
|
|
215
|
+
{
|
|
216
|
+
tmpInputExtraOptions += ',';
|
|
217
|
+
}
|
|
218
|
+
tmpInputExtraOptions += `${tmpOption.id}^${tmpOption.text}`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
tmpRow[this.CSV_COLUMN_MAP["Input Extra"]] = tmpInputExtraOptions;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return tmpRow;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
createTabularArrayFromManifests(pManifest)
|
|
229
|
+
{
|
|
230
|
+
// CSV_COLUMN_MAP is already initialized in constructor
|
|
231
|
+
|
|
232
|
+
// Convert the manifest to an array of CSV rows
|
|
233
|
+
let tmpCSVRows = [];
|
|
234
|
+
|
|
235
|
+
// Figure out the form
|
|
236
|
+
let tmpForm = 'Default';
|
|
237
|
+
if ((pManifest) && (pManifest.Scope) && (typeof(pManifest.Scope) === 'string'))
|
|
238
|
+
{
|
|
239
|
+
tmpForm = pManifest.Scope;
|
|
240
|
+
}
|
|
241
|
+
if ((pManifest) && (pManifest.Form) && (typeof(pManifest.Form) === 'string'))
|
|
242
|
+
{
|
|
243
|
+
tmpForm = pManifest.Form;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Add the header row
|
|
247
|
+
tmpCSVRows.push(this.CSV_HEADER);
|
|
248
|
+
|
|
249
|
+
if (typeof(pManifest) !== 'object')
|
|
250
|
+
{
|
|
251
|
+
this.log.error('ManifestConversionToCSV: Provided manifest is not an object; cannot convert to CSV.');
|
|
252
|
+
return tmpCSVRows;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!pManifest.Descriptors || (typeof(pManifest.Descriptors) !== 'object'))
|
|
256
|
+
{
|
|
257
|
+
this.log.error('ManifestConversionToCSV: Provided manifest does not have a valid Descriptors property; cannot convert to CSV.');
|
|
258
|
+
return tmpCSVRows;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let tmpDescriptorKeys = Object.keys(pManifest.Descriptors);
|
|
262
|
+
for (let i = 0; i < tmpDescriptorKeys.length; i++)
|
|
263
|
+
{
|
|
264
|
+
let tmpDescriptorKey = tmpDescriptorKeys[i];
|
|
265
|
+
let tmpDescriptor = pManifest.Descriptors[tmpDescriptorKey];
|
|
266
|
+
|
|
267
|
+
if ((!tmpDescriptor) || (typeof(tmpDescriptor) !== 'object'))
|
|
268
|
+
{
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
let tmpCSVRow = this.getRowFromDescriptor(tmpForm, tmpDescriptorKey, tmpDescriptor);
|
|
273
|
+
if (tmpCSVRow)
|
|
274
|
+
{
|
|
275
|
+
tmpCSVRows.push(tmpCSVRow);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
for (let i = 0; i < pManifest.Sections.length; i++)
|
|
280
|
+
{
|
|
281
|
+
let tmpSection = pManifest.Sections[i];
|
|
282
|
+
let tmpSectionHash = tmpSection.Hash || 'DEFAULT_SECTION_HASH';
|
|
283
|
+
|
|
284
|
+
if ((!tmpSection) || (typeof(tmpSection) !== 'object'))
|
|
285
|
+
{
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// See if the group has a name and decorate the manifest entry with the group name
|
|
290
|
+
if (tmpSection.Groups && Array.isArray(tmpSection.Groups))
|
|
291
|
+
{
|
|
292
|
+
for (let j = 0; j < tmpSection.Groups.length; j++)
|
|
293
|
+
{
|
|
294
|
+
let tmpGroup = tmpSection.Groups[j];
|
|
295
|
+
let tmpGroupHash = tmpGroup.Hash;
|
|
296
|
+
|
|
297
|
+
if ((tmpGroup.Layout == 'Tabular') || (tmpGroup.Layout == 'RecordSet'))
|
|
298
|
+
{
|
|
299
|
+
// Pull in the reference manifest for this tabular set
|
|
300
|
+
/*
|
|
301
|
+
{
|
|
302
|
+
"Name": "Boxes",
|
|
303
|
+
"Hash": "BoxCollGrp",
|
|
304
|
+
"Rows": [],
|
|
305
|
+
"RecordSetSolvers": [
|
|
306
|
+
"BoxFloorspace = BoxWidth * BoxDepth",
|
|
307
|
+
"BoxVolume = BoxFloorspace * BoxHeight"
|
|
308
|
+
],
|
|
309
|
+
"MinimumRowCount": 3,
|
|
310
|
+
"MaximumRowCount": 10,
|
|
311
|
+
"ShowTitle": true,
|
|
312
|
+
"Layout": "Tabular",
|
|
313
|
+
"RecordSetAddress": "Boxes",
|
|
314
|
+
"RecordManifest": "BoxCollectionData"
|
|
315
|
+
}
|
|
316
|
+
*/
|
|
317
|
+
// Validate there is a RecordSetAddress and RecordManifest
|
|
318
|
+
if (tmpGroup.RecordSetAddress && tmpGroup.RecordManifest)
|
|
319
|
+
{
|
|
320
|
+
// Find the Array placeholder in the CSV
|
|
321
|
+
let tmpGroupArrayPlaceholderIndex = -1;
|
|
322
|
+
for (let k = 0; k < tmpCSVRows.length; k++)
|
|
323
|
+
{
|
|
324
|
+
let tmpRow = tmpCSVRows[k];
|
|
325
|
+
if ((tmpRow) && (Array.isArray(tmpRow)) && (tmpRow.length >= this.CSV_HEADER.length))
|
|
326
|
+
{
|
|
327
|
+
let tmpRowSectionHash = tmpRow[this.CSV_COLUMN_MAP["Section Hash"]];
|
|
328
|
+
let tmpRowGroupHash = tmpRow[this.CSV_COLUMN_MAP["Group Hash"]];
|
|
329
|
+
if ((tmpRowSectionHash === tmpSectionHash) && (tmpRowGroupHash === tmpGroupHash))
|
|
330
|
+
{
|
|
331
|
+
// This is the row for this group
|
|
332
|
+
tmpGroupArrayPlaceholderIndex = k;
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Try to match on the Input Address as a fallback
|
|
337
|
+
let tmpRowInputAddress = tmpRow[this.CSV_COLUMN_MAP["Input Address"]];
|
|
338
|
+
if (tmpRowInputAddress === tmpGroup.RecordSetAddress)
|
|
339
|
+
{
|
|
340
|
+
// Set the section and group hash here, this is an old manifest
|
|
341
|
+
tmpRow[this.CSV_COLUMN_MAP["Section Hash"]] = tmpSectionHash;
|
|
342
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Hash"]] = tmpGroupHash;
|
|
343
|
+
tmpGroupArrayPlaceholderIndex = k;
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (tmpGroupArrayPlaceholderIndex >= 0)
|
|
349
|
+
{
|
|
350
|
+
let tmpRow = tmpCSVRows[tmpGroupArrayPlaceholderIndex];
|
|
351
|
+
|
|
352
|
+
// Set the SubManifest on the placeholder row
|
|
353
|
+
tmpRow[this.CSV_COLUMN_MAP["SubManifest"]] = tmpGroup.RecordManifest;
|
|
354
|
+
|
|
355
|
+
// Now set the Minimum and Maximum Row Counts
|
|
356
|
+
if (tmpGroup.MinimumRowCount)
|
|
357
|
+
{
|
|
358
|
+
tmpRow[this.CSV_COLUMN_MAP["Minimum Row Count"]] = tmpGroup.MinimumRowCount;
|
|
359
|
+
}
|
|
360
|
+
if (tmpGroup.MaximumRowCount)
|
|
361
|
+
{
|
|
362
|
+
tmpRow[this.CSV_COLUMN_MAP["Maximum Row Count"]] = tmpGroup.MaximumRowCount;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Find the reference manifest, pull in the descriptors, and create rows for each
|
|
366
|
+
let tmpReferenceManifest = pManifest.ReferenceManifests[tmpGroup.RecordManifest];
|
|
367
|
+
let tmpReferenceManifestDescriptorKeys = Object.keys(tmpReferenceManifest.Descriptors);
|
|
368
|
+
for (let m = 0; m < tmpReferenceManifestDescriptorKeys.length; m++)
|
|
369
|
+
{
|
|
370
|
+
let tmpReferenceDescriptorKey = tmpReferenceManifestDescriptorKeys[m];
|
|
371
|
+
let tmpReferenceDescriptor = tmpReferenceManifest.Descriptors[tmpReferenceDescriptorKey];
|
|
372
|
+
|
|
373
|
+
if ((!tmpReferenceDescriptor) || (typeof(tmpReferenceDescriptor) !== 'object'))
|
|
374
|
+
{
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
let tmpReferenceCSVRow = this.getRowFromDescriptor(tmpForm, tmpReferenceDescriptorKey, tmpReferenceDescriptor);
|
|
379
|
+
if (tmpReferenceCSVRow)
|
|
380
|
+
{
|
|
381
|
+
// Set the Section and Group Hashes on this row
|
|
382
|
+
tmpReferenceCSVRow[this.CSV_COLUMN_MAP["Section Hash"]] = tmpSectionHash;
|
|
383
|
+
tmpReferenceCSVRow[this.CSV_COLUMN_MAP["Group Hash"]] = tmpGroupHash;
|
|
384
|
+
|
|
385
|
+
// Set the SubManifest on this row
|
|
386
|
+
tmpReferenceCSVRow[this.CSV_COLUMN_MAP["SubManifest"]] = tmpGroup.RecordManifest;
|
|
387
|
+
|
|
388
|
+
// Insert this row after the placeholder
|
|
389
|
+
tmpCSVRows.splice(tmpGroupArrayPlaceholderIndex + 1, 0, tmpReferenceCSVRow);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (tmpGroupHash)
|
|
397
|
+
{
|
|
398
|
+
for (let k = 0; k < tmpCSVRows.length; k++)
|
|
399
|
+
{
|
|
400
|
+
let tmpRow = tmpCSVRows[k];
|
|
401
|
+
if ((tmpRow) && (Array.isArray(tmpRow)) && (tmpRow.length >= this.CSV_HEADER.length))
|
|
402
|
+
{
|
|
403
|
+
let tmpRowGroupHash = tmpRow[this.CSV_COLUMN_MAP["Group Hash"]];
|
|
404
|
+
if (tmpRowGroupHash === tmpGroupHash)
|
|
405
|
+
{
|
|
406
|
+
// This is the row for this group
|
|
407
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Name"]] = tmpGroup.Name || tmpGroupHash;
|
|
408
|
+
if (tmpGroup.Layout)
|
|
409
|
+
{
|
|
410
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Layout"]] = tmpGroup.Layout;
|
|
411
|
+
}
|
|
412
|
+
if (tmpGroup.hasOwnProperty('ShowTitle'))
|
|
413
|
+
{
|
|
414
|
+
tmpRow[this.CSV_COLUMN_MAP["Group Show Title"]] = tmpGroup.ShowTitle;
|
|
415
|
+
}
|
|
416
|
+
if (tmpGroup.hasOwnProperty('CSSClass'))
|
|
417
|
+
{
|
|
418
|
+
tmpRow[this.CSV_COLUMN_MAP["Group CSS"]] = tmpGroup.CSSClass;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// See if there is a section name and decorate the manifest entries with the name
|
|
428
|
+
for (let j = 0; j < tmpCSVRows.length; j++)
|
|
429
|
+
{
|
|
430
|
+
let tmpRow = tmpCSVRows[j];
|
|
431
|
+
if ((tmpRow) && (Array.isArray(tmpRow)) && (tmpRow.length >= this.CSV_HEADER.length))
|
|
432
|
+
{
|
|
433
|
+
let tmpRowSectionHash = tmpRow[this.CSV_COLUMN_MAP["Section Hash"]];
|
|
434
|
+
if (tmpRowSectionHash === tmpSectionHash)
|
|
435
|
+
{
|
|
436
|
+
// This is the row for this section
|
|
437
|
+
tmpRow[this.CSV_COLUMN_MAP["Section Name"]] = tmpSection.Name || tmpSectionHash;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Now go through the section and group solvers, and decorate the appropriate rows
|
|
443
|
+
if (tmpSection.Solvers && Array.isArray(tmpSection.Solvers))
|
|
444
|
+
{
|
|
445
|
+
for (let j = 0; j < tmpSection.Solvers.length; j++)
|
|
446
|
+
{
|
|
447
|
+
let tmpSolver = tmpSection.Solvers[j];
|
|
448
|
+
let tmpSolverAssigned = false;
|
|
449
|
+
|
|
450
|
+
// find an unused row in this section to decorate
|
|
451
|
+
for (let k = 0; k < tmpCSVRows.length; k++)
|
|
452
|
+
{
|
|
453
|
+
let tmpRow = tmpCSVRows[k];
|
|
454
|
+
if ((tmpRow) && (Array.isArray(tmpRow)) && (tmpRow.length >= this.CSV_HEADER.length))
|
|
455
|
+
{
|
|
456
|
+
let tmpRowSectionHash = tmpRow[this.CSV_COLUMN_MAP["Section Hash"]];
|
|
457
|
+
let tmpRowEquation = tmpRow[this.CSV_COLUMN_MAP["Equation"]];
|
|
458
|
+
let tmpRowSubManifest = tmpRow[this.CSV_COLUMN_MAP["SubManifest"]];
|
|
459
|
+
// If it's in the section
|
|
460
|
+
if ((tmpRowSectionHash === tmpSectionHash)
|
|
461
|
+
// And it isn't a tabular row
|
|
462
|
+
&& (!tmpRowSubManifest || (tmpRowSubManifest == ''))
|
|
463
|
+
// And an equation hasn't been set already
|
|
464
|
+
&& (!tmpRowEquation || (tmpRowEquation.length == 0)))
|
|
465
|
+
{
|
|
466
|
+
// This is an unused row for this section
|
|
467
|
+
if (typeof(tmpSolver) === 'string')
|
|
468
|
+
{
|
|
469
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver;
|
|
470
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = 1;
|
|
471
|
+
}
|
|
472
|
+
else if (typeof(tmpSolver) === 'object' && tmpSolver.Expression)
|
|
473
|
+
{
|
|
474
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver.Expression;
|
|
475
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = tmpSolver.Ordinal || 1;
|
|
476
|
+
}
|
|
477
|
+
tmpSolverAssigned = true;
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
// If the solver wasn't assigned, we have to create a hidden data only row for it and splice it in
|
|
483
|
+
if (!tmpSolverAssigned)
|
|
484
|
+
{
|
|
485
|
+
let tmpHiddenSolverRow = new Array(this.CSV_HEADER.length).fill('');
|
|
486
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Form"]] = tmpForm;
|
|
487
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Section Hash"]] = tmpSectionHash;
|
|
488
|
+
// Set DataOnly
|
|
489
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["DataOnly"]] = '1';
|
|
490
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["DataType"]] = 'String';
|
|
491
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["InputType"]] = 'Hidden';
|
|
492
|
+
// Generate an input hash and name that show its for a solver
|
|
493
|
+
let tmpSolverInputHash = `Solver_for_${tmpSectionHash}_${j + 1}`;
|
|
494
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Input Hash"]] = tmpSolverInputHash;
|
|
495
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Input Name"]] = `Auto gen hidden solver entry for ${tmpSection.Name || tmpSectionHash} #${j + 1}`;
|
|
496
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Input Address"]] = tmpSolverInputHash;
|
|
497
|
+
if (typeof(tmpSolver) === 'string')
|
|
498
|
+
{
|
|
499
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver;
|
|
500
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = 1;
|
|
501
|
+
}
|
|
502
|
+
else if (typeof(tmpSolver) === 'object' && tmpSolver.Expression)
|
|
503
|
+
{
|
|
504
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver.Expression;
|
|
505
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = tmpSolver.Ordinal || 1;
|
|
506
|
+
}
|
|
507
|
+
// Splice this row after the last row for this section
|
|
508
|
+
let tmpLastSectionRowIndex = -1;
|
|
509
|
+
for (let k = 0; k < tmpCSVRows.length; k++)
|
|
510
|
+
{
|
|
511
|
+
let tmpRow = tmpCSVRows[k];
|
|
512
|
+
if ((tmpRow) && (Array.isArray(tmpRow)) && (tmpRow.length >= this.CSV_HEADER.length))
|
|
513
|
+
{
|
|
514
|
+
let tmpRowSectionHash = tmpRow[this.CSV_COLUMN_MAP["Section Hash"]];
|
|
515
|
+
if (tmpRowSectionHash === tmpSectionHash)
|
|
516
|
+
{
|
|
517
|
+
tmpLastSectionRowIndex = k;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (tmpLastSectionRowIndex >= 0)
|
|
522
|
+
{
|
|
523
|
+
tmpCSVRows.splice(tmpLastSectionRowIndex + 1, 0, tmpHiddenSolverRow);
|
|
524
|
+
}
|
|
525
|
+
else
|
|
526
|
+
{
|
|
527
|
+
// Just push it on the end
|
|
528
|
+
tmpCSVRows.push(tmpHiddenSolverRow);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Lastly enumerate the group solvers
|
|
535
|
+
if (tmpSection.Groups && Array.isArray(tmpSection.Groups))
|
|
536
|
+
{
|
|
537
|
+
for (let j = 0; j < tmpSection.Groups.length; j++)
|
|
538
|
+
{
|
|
539
|
+
let tmpGroup = tmpSection.Groups[j];
|
|
540
|
+
let tmpGroupHash = tmpGroup.Hash;
|
|
541
|
+
|
|
542
|
+
if (tmpGroup.RecordSetSolvers && Array.isArray(tmpGroup.RecordSetSolvers))
|
|
543
|
+
{
|
|
544
|
+
for (let m = 0; m < tmpGroup.RecordSetSolvers.length; m++)
|
|
545
|
+
{
|
|
546
|
+
let tmpSolver = tmpGroup.RecordSetSolvers[m];
|
|
547
|
+
let tmpSolverAssigned = false;
|
|
548
|
+
|
|
549
|
+
// find an unused row in this group to decorate
|
|
550
|
+
for (let k = 0; k < tmpCSVRows.length; k++)
|
|
551
|
+
{
|
|
552
|
+
let tmpRow = tmpCSVRows[k];
|
|
553
|
+
if ((tmpRow) && (Array.isArray(tmpRow)) && (tmpRow.length >= this.CSV_HEADER.length))
|
|
554
|
+
{
|
|
555
|
+
let tmpRowGroupHash = tmpRow[this.CSV_COLUMN_MAP["Group Hash"]];
|
|
556
|
+
let tmpRowEquation = tmpRow[this.CSV_COLUMN_MAP["Equation"]];
|
|
557
|
+
let tmpRowSubManifest = tmpRow[this.CSV_COLUMN_MAP["SubManifest"]];
|
|
558
|
+
// If it's in the group
|
|
559
|
+
if ((tmpRowGroupHash === tmpGroupHash)
|
|
560
|
+
// And it is a tabular row
|
|
561
|
+
&& (tmpRowSubManifest == tmpGroup.RecordManifest)
|
|
562
|
+
// And an equation hasn't been set already
|
|
563
|
+
&& (!tmpRowEquation || (tmpRowEquation.length == 0)))
|
|
564
|
+
{
|
|
565
|
+
// This is an unused row for this group
|
|
566
|
+
if (typeof(tmpSolver) === 'string')
|
|
567
|
+
{
|
|
568
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver;
|
|
569
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = 1;
|
|
570
|
+
}
|
|
571
|
+
else if (typeof(tmpSolver) === 'object' && tmpSolver.Expression)
|
|
572
|
+
{
|
|
573
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver.Expression;
|
|
574
|
+
tmpRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = tmpSolver.Ordinal || 1;
|
|
575
|
+
}
|
|
576
|
+
tmpSolverAssigned = true;
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
// If the solver wasn't assigned, we have to create a hidden data only row for it and splice it in
|
|
582
|
+
if (!tmpSolverAssigned)
|
|
583
|
+
{
|
|
584
|
+
let tmpHiddenSolverRow = new Array(this.CSV_HEADER.length).fill('');
|
|
585
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Form"]] = tmpForm;
|
|
586
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Section Hash"]] = tmpSectionHash;
|
|
587
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Group Hash"]] = tmpGroupHash;
|
|
588
|
+
// Set the submanifest on the row
|
|
589
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["SubManifest"]] = tmpGroup.RecordManifest;
|
|
590
|
+
// Set DataOnly
|
|
591
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["DataOnly"]] = '1';
|
|
592
|
+
// Generate an input hash and name that show its for a solver
|
|
593
|
+
let tmpSolverInputHash = `Solver_for_${tmpGroupHash}_${m + 1}`;
|
|
594
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Input Hash"]] = tmpSolverInputHash;
|
|
595
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Input Name"]] = `Auto gen hidden solver entry for ${tmpGroup.Name || tmpGroupHash} #${m + 1}`;
|
|
596
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Input Address"]] = tmpSolverInputHash;
|
|
597
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["DataType"]] = 'String';
|
|
598
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["InputType"]] = 'Hidden';
|
|
599
|
+
if (typeof(tmpSolver) === 'string')
|
|
600
|
+
{
|
|
601
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver;
|
|
602
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = 1;
|
|
603
|
+
}
|
|
604
|
+
else if (typeof(tmpSolver) === 'object' && tmpSolver.Expression)
|
|
605
|
+
{
|
|
606
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation"]] = tmpSolver.Expression;
|
|
607
|
+
tmpHiddenSolverRow[this.CSV_COLUMN_MAP["Equation Ordinal"]] = tmpSolver.Ordinal || 1;
|
|
608
|
+
}
|
|
609
|
+
// Splice this row after the last row for this group
|
|
610
|
+
let tmpLastGroupRowIndex = -1;
|
|
611
|
+
for (let k = 0; k < tmpCSVRows.length; k++)
|
|
612
|
+
{
|
|
613
|
+
let tmpRow = tmpCSVRows[k];
|
|
614
|
+
if ((tmpRow) && (Array.isArray(tmpRow)) && (tmpRow.length >= this.CSV_HEADER.length))
|
|
615
|
+
{
|
|
616
|
+
let tmpRowGroupHash = tmpRow[this.CSV_COLUMN_MAP["Group Hash"]];
|
|
617
|
+
if (tmpRowGroupHash === tmpGroupHash)
|
|
618
|
+
{
|
|
619
|
+
tmpLastGroupRowIndex = k;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (tmpLastGroupRowIndex >= 0)
|
|
624
|
+
{
|
|
625
|
+
tmpCSVRows.splice(tmpLastGroupRowIndex + 1, 0, tmpHiddenSolverRow);
|
|
626
|
+
}
|
|
627
|
+
else
|
|
628
|
+
{
|
|
629
|
+
// Just push it on the end
|
|
630
|
+
tmpCSVRows.push(tmpHiddenSolverRow);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (tmpCSVRows.length > 1)
|
|
640
|
+
{
|
|
641
|
+
// Add the FormName from the root of the manifest to the first row Form Name column
|
|
642
|
+
let tmpFirstDataRow = tmpCSVRows[1];
|
|
643
|
+
if (tmpFirstDataRow && pManifest.FormName)
|
|
644
|
+
{
|
|
645
|
+
tmpFirstDataRow[this.CSV_COLUMN_MAP["Form Name"]] = pManifest.FormName || tmpFirstDataRow[this.CSV_COLUMN_MAP["Form Name"]];
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
return tmpCSVRows;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
module.exports = ManifestConversionToCSV;
|