@case-framework/survey-core 0.1.0 → 0.3.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 +181 -0
- package/build/editor.d.mts +169 -5
- package/build/editor.d.mts.map +1 -1
- package/build/editor.mjs +429 -12
- package/build/editor.mjs.map +1 -1
- package/build/index.d.mts +197 -6
- package/build/index.d.mts.map +1 -1
- package/build/index.mjs +365 -42
- package/build/index.mjs.map +1 -1
- package/build/{package.json/package.json → package.json} +6 -6
- package/build/{survey-C3ZHI-5z.mjs → survey-DJbgFVPz.mjs} +298 -198
- package/build/survey-DJbgFVPz.mjs.map +1 -0
- package/build/{survey-TUPUXiXl.d.mts → survey-wnGyIY66.d.mts} +81 -6
- package/build/survey-wnGyIY66.d.mts.map +1 -0
- package/package.json +6 -6
- package/build/survey-C3ZHI-5z.mjs.map +0 -1
- package/build/survey-TUPUXiXl.d.mts.map +0 -1
package/build/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { A as FunctionExpressionNames, C as serializeTemplateValues, D as Expression, E as ContextVariableType, F as generateCodingKey, I as generateId, L as shuffleIndices, M as ReferenceUsageType, N as ValueReference, O as ExpressionType, P as ValueReferenceMethod, R as structuredCloneMethod, S as serializeTemplateValue, T as ContextVariableExpression, _ as NumberPrecision, a as createFullRegistry, b as deserializeTemplateValue, c as toItemTypeDefinitionRegistry, d as builtInItemCoreRegistry, f as isBuiltInItemType, g as DurationUnits, h as SurveyItemCore, i as validateLocale, j as ResponseVariableExpression, k as FunctionExpression, l as GroupItemCore, m as ReservedSurveyItemTypes, n as SurveyItemTranslations, o as createItemCore, p as SurveyItemKey, r as SurveyTranslations, s as createItemTypeDefinitionRegistry, t as Survey, u as PageBreakItemCore, v as ValueType, w as ConstExpression, x as deserializeTemplateValues, y as TemplateDefTypes } from "./survey-DJbgFVPz.mjs";
|
|
2
2
|
import { format } from "date-fns";
|
|
3
3
|
import { enUS } from "date-fns/locale";
|
|
4
|
-
|
|
5
4
|
//#region src/to_mirgrate/data_types/legacy-types.ts
|
|
6
5
|
const isLegacyItemGroupComponent = (item) => {
|
|
7
6
|
const items = item.items;
|
|
@@ -11,7 +10,6 @@ const isLegacySurveyGroupItem = (item) => {
|
|
|
11
10
|
const items = item.items;
|
|
12
11
|
return items !== void 0 && items.length > 0;
|
|
13
12
|
};
|
|
14
|
-
|
|
15
13
|
//#endregion
|
|
16
14
|
//#region src/survey/responses/item-response.ts
|
|
17
15
|
/**
|
|
@@ -66,7 +64,6 @@ var ResponseItem = class ResponseItem {
|
|
|
66
64
|
return new ResponseItem(json.slotValues);
|
|
67
65
|
}
|
|
68
66
|
};
|
|
69
|
-
|
|
70
67
|
//#endregion
|
|
71
68
|
//#region src/survey/responses/response-meta.ts
|
|
72
69
|
const SurveyEventTypes = {
|
|
@@ -75,7 +72,6 @@ const SurveyEventTypes = {
|
|
|
75
72
|
responeChanged: "responeChanged",
|
|
76
73
|
languageChanged: "languageChanged"
|
|
77
74
|
};
|
|
78
|
-
|
|
79
75
|
//#endregion
|
|
80
76
|
//#region src/survey/responses/survey-response.ts
|
|
81
77
|
/**
|
|
@@ -113,40 +109,13 @@ var SurveyResponse = class SurveyResponse {
|
|
|
113
109
|
response.participantId = json.participantId;
|
|
114
110
|
response.submittedAt = json.submittedAt;
|
|
115
111
|
response.responses = new Map(json.responses.map((r) => [r.itemId, SurveyItemResponse.deserialize(r)]));
|
|
112
|
+
response.events = json.events ?? [];
|
|
113
|
+
response.versionId = json.versionId;
|
|
114
|
+
response.key = json.key;
|
|
116
115
|
response.context = json.context;
|
|
117
116
|
return response;
|
|
118
117
|
}
|
|
119
118
|
};
|
|
120
|
-
|
|
121
|
-
//#endregion
|
|
122
|
-
//#region src/survey/responses/value-types.ts
|
|
123
|
-
const ValueType = {
|
|
124
|
-
string: "string",
|
|
125
|
-
duration: "duration",
|
|
126
|
-
reference: "reference",
|
|
127
|
-
number: "number",
|
|
128
|
-
boolean: "boolean",
|
|
129
|
-
date: "date",
|
|
130
|
-
stringArray: "string[]",
|
|
131
|
-
durationArray: "duration[]",
|
|
132
|
-
referenceArray: "reference[]",
|
|
133
|
-
numberArray: "number[]",
|
|
134
|
-
dateArray: "date[]"
|
|
135
|
-
};
|
|
136
|
-
const DurationUnits = {
|
|
137
|
-
seconds: "seconds",
|
|
138
|
-
minutes: "minutes",
|
|
139
|
-
hours: "hours",
|
|
140
|
-
days: "days",
|
|
141
|
-
weeks: "weeks",
|
|
142
|
-
months: "months",
|
|
143
|
-
years: "years"
|
|
144
|
-
};
|
|
145
|
-
const NumberPrecision = {
|
|
146
|
-
int: "int",
|
|
147
|
-
float: "float"
|
|
148
|
-
};
|
|
149
|
-
|
|
150
119
|
//#endregion
|
|
151
120
|
//#region src/survey/responses/utils.ts
|
|
152
121
|
const initValueForType = (returnType) => {
|
|
@@ -200,7 +169,6 @@ const initValueForType = (returnType) => {
|
|
|
200
169
|
default: throw new Error("Invalid return type: " + returnType);
|
|
201
170
|
}
|
|
202
171
|
};
|
|
203
|
-
|
|
204
172
|
//#endregion
|
|
205
173
|
//#region src/expressions/expression-evaluator.ts
|
|
206
174
|
var ExpressionEvaluator = class {
|
|
@@ -530,7 +498,6 @@ var ExpressionEvaluator = class {
|
|
|
530
498
|
});
|
|
531
499
|
}
|
|
532
500
|
};
|
|
533
|
-
|
|
534
501
|
//#endregion
|
|
535
502
|
//#region src/expressions/editors/expression-editor.ts
|
|
536
503
|
var ExpressionEditor = class {
|
|
@@ -1053,7 +1020,6 @@ var MaxExpressionEditor = class extends GroupExpressionEditor {
|
|
|
1053
1020
|
return new FunctionExpression(FunctionExpressionNames.max, this.args.map((arg) => arg.getExpression()), this._editorConfig);
|
|
1054
1021
|
}
|
|
1055
1022
|
};
|
|
1056
|
-
|
|
1057
1023
|
//#endregion
|
|
1058
1024
|
//#region src/expressions/editors/expression-editor-generators.ts
|
|
1059
1025
|
const const_string_array = (...values) => {
|
|
@@ -1158,7 +1124,6 @@ const min = (...args) => {
|
|
|
1158
1124
|
const max = (...args) => {
|
|
1159
1125
|
return new MaxExpressionEditor(args);
|
|
1160
1126
|
};
|
|
1161
|
-
|
|
1162
1127
|
//#endregion
|
|
1163
1128
|
//#region src/survey/utils/content.ts
|
|
1164
1129
|
let ContentType = /* @__PURE__ */ function(ContentType) {
|
|
@@ -1171,7 +1136,6 @@ let AttributionType = /* @__PURE__ */ function(AttributionType) {
|
|
|
1171
1136
|
AttributionType["template"] = "template";
|
|
1172
1137
|
return AttributionType;
|
|
1173
1138
|
}({});
|
|
1174
|
-
|
|
1175
1139
|
//#endregion
|
|
1176
1140
|
//#region src/engine/engine.ts
|
|
1177
1141
|
var SurveyEngineCore = class {
|
|
@@ -1580,7 +1544,366 @@ const flattenTree = (itemTree) => {
|
|
|
1580
1544
|
});
|
|
1581
1545
|
return flatTree;
|
|
1582
1546
|
};
|
|
1583
|
-
|
|
1584
1547
|
//#endregion
|
|
1585
|
-
|
|
1548
|
+
//#region src/response-exporter/types.ts
|
|
1549
|
+
/** Meta column keys in fixed order (common attributes first). */
|
|
1550
|
+
const META_COLUMN_ORDER = [
|
|
1551
|
+
"submittedAt",
|
|
1552
|
+
"participantId",
|
|
1553
|
+
"responseId",
|
|
1554
|
+
"versionId"
|
|
1555
|
+
];
|
|
1556
|
+
/** Built-in transform modes for slot export. */
|
|
1557
|
+
const SlotTransformMode = {
|
|
1558
|
+
default: "default",
|
|
1559
|
+
mask: "mask",
|
|
1560
|
+
dateFormat: "dateFormat"
|
|
1561
|
+
};
|
|
1562
|
+
/** Separator between item key path and slot coding path in default export headers. */
|
|
1563
|
+
const EXPORT_COLUMN_SLOT_SEPARATOR = "__";
|
|
1564
|
+
/** Source of an export column. */
|
|
1565
|
+
const ExportColumnSource = {
|
|
1566
|
+
meta: "meta",
|
|
1567
|
+
context: "context",
|
|
1568
|
+
response: "response"
|
|
1569
|
+
};
|
|
1570
|
+
//#endregion
|
|
1571
|
+
//#region src/response-exporter/slot-formatter.ts
|
|
1572
|
+
/** Default transform config when no profile override. */
|
|
1573
|
+
const DEFAULT_TRANSFORM = { mode: SlotTransformMode.default };
|
|
1574
|
+
/**
|
|
1575
|
+
* Export a single response slot to a string. Pure function for unit testing.
|
|
1576
|
+
* Uses default formatting by ValueType unless overridden by transformConfig.
|
|
1577
|
+
*/
|
|
1578
|
+
function exportSingleResponseSlot(params) {
|
|
1579
|
+
const { value, valueType, transformConfig } = params;
|
|
1580
|
+
if (value === void 0 || value === null) return "";
|
|
1581
|
+
const mode = transformConfig.mode;
|
|
1582
|
+
if (mode === SlotTransformMode.mask) return maskValue(value, transformConfig.maskChar ?? "***");
|
|
1583
|
+
if (mode === SlotTransformMode.dateFormat && (valueType === ValueType.date || valueType === ValueType.dateArray)) return formatDateValue(value, transformConfig.dateFormat?.pattern ?? "yyyy-MM-dd");
|
|
1584
|
+
return formatDefault(value);
|
|
1585
|
+
}
|
|
1586
|
+
const BooleanExportValues = {
|
|
1587
|
+
TRUE: "TRUE",
|
|
1588
|
+
FALSE: "FALSE"
|
|
1589
|
+
};
|
|
1590
|
+
function formatDefault(value) {
|
|
1591
|
+
switch (value.type) {
|
|
1592
|
+
case ValueType.string: return String(value.value);
|
|
1593
|
+
case ValueType.reference: return String(value.value);
|
|
1594
|
+
case ValueType.boolean: return value.value ? BooleanExportValues.TRUE : BooleanExportValues.FALSE;
|
|
1595
|
+
case ValueType.number: return value.precision === NumberPrecision.int ? String(Math.floor(value.value)) : String(value.value);
|
|
1596
|
+
case ValueType.date: return (/* @__PURE__ */ new Date(value.value * 1e3)).toISOString();
|
|
1597
|
+
case ValueType.duration: {
|
|
1598
|
+
const d = value;
|
|
1599
|
+
return `${d.precision === NumberPrecision.int ? Math.floor(d.value) : d.value} ${d.unit}`;
|
|
1600
|
+
}
|
|
1601
|
+
case ValueType.stringArray: return value.value.join("; ");
|
|
1602
|
+
case ValueType.referenceArray: return value.value.join("; ");
|
|
1603
|
+
case ValueType.numberArray: {
|
|
1604
|
+
const arr = value.value;
|
|
1605
|
+
const prec = value.precision;
|
|
1606
|
+
const fmt = (n) => prec === NumberPrecision.int ? Math.floor(n) : n;
|
|
1607
|
+
return arr.map(fmt).join("; ");
|
|
1608
|
+
}
|
|
1609
|
+
case ValueType.dateArray: return value.value.map((ts) => (/* @__PURE__ */ new Date(ts * 1e3)).toISOString()).join("; ");
|
|
1610
|
+
case ValueType.durationArray: {
|
|
1611
|
+
const d = value;
|
|
1612
|
+
const prec = d.precision === NumberPrecision.int;
|
|
1613
|
+
const fmt = (n) => prec ? Math.floor(n) : n;
|
|
1614
|
+
return d.value.map((v) => `${fmt(v)} ${d.unit}`).join("; ");
|
|
1615
|
+
}
|
|
1616
|
+
default: return String(value.value ?? "");
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
function formatDateValue(value, pattern) {
|
|
1620
|
+
if (value.type === ValueType.date) return format(/* @__PURE__ */ new Date(value.value * 1e3), pattern);
|
|
1621
|
+
if (value.type === ValueType.dateArray) return value.value.map((ts) => format(/* @__PURE__ */ new Date(ts * 1e3), pattern)).join("; ");
|
|
1622
|
+
return formatDefault(value);
|
|
1623
|
+
}
|
|
1624
|
+
function maskValue(value, maskChar) {
|
|
1625
|
+
return valueToString(value) ? maskChar : "";
|
|
1626
|
+
}
|
|
1627
|
+
function valueToString(value) {
|
|
1628
|
+
switch (value.type) {
|
|
1629
|
+
case ValueType.string:
|
|
1630
|
+
case ValueType.reference: return String(value.value);
|
|
1631
|
+
case ValueType.stringArray:
|
|
1632
|
+
case ValueType.referenceArray: return value.value.join(" ");
|
|
1633
|
+
default: return String(value.value ?? "");
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
//#endregion
|
|
1637
|
+
//#region src/response-exporter/csv-serializer.ts
|
|
1638
|
+
const DEFAULT_OPTIONS = {
|
|
1639
|
+
separator: ",",
|
|
1640
|
+
lineEnding: "\n",
|
|
1641
|
+
includeHeader: true
|
|
1642
|
+
};
|
|
1643
|
+
/**
|
|
1644
|
+
* Escape a cell value for CSV. Quotes the cell when it contains separator, quote, CR, or LF.
|
|
1645
|
+
* Doubles embedded quotes. Preserves multiline content inside quoted cells.
|
|
1646
|
+
*/
|
|
1647
|
+
function escapeCsvCell(value, separator = ",") {
|
|
1648
|
+
if (value === "") return value;
|
|
1649
|
+
if (!(value.includes(separator) || value.includes("\"") || value.includes("\r") || value.includes("\n"))) return value;
|
|
1650
|
+
return `"${value.replace(/"/g, "\"\"")}"`;
|
|
1651
|
+
}
|
|
1652
|
+
/**
|
|
1653
|
+
* Serialize export rows to CSV string.
|
|
1654
|
+
*/
|
|
1655
|
+
function serializeToCsv(columns, rows, options) {
|
|
1656
|
+
const opts = {
|
|
1657
|
+
...DEFAULT_OPTIONS,
|
|
1658
|
+
...options
|
|
1659
|
+
};
|
|
1660
|
+
const sep = opts.separator;
|
|
1661
|
+
const lines = [];
|
|
1662
|
+
const headers = columns.map((c) => c.header);
|
|
1663
|
+
if (opts.includeHeader) lines.push(headers.map((header) => escapeCsvCell(header, sep)).join(sep));
|
|
1664
|
+
for (const row of rows) {
|
|
1665
|
+
const cells = headers.map((header) => escapeCsvCell(row[header] ?? "", sep));
|
|
1666
|
+
lines.push(cells.join(sep));
|
|
1667
|
+
}
|
|
1668
|
+
return lines.join(opts.lineEnding);
|
|
1669
|
+
}
|
|
1670
|
+
//#endregion
|
|
1671
|
+
//#region src/response-exporter/exporter.ts
|
|
1672
|
+
function slotOverrideKey(itemId, slotId) {
|
|
1673
|
+
return `${itemId}::${slotId}`;
|
|
1674
|
+
}
|
|
1675
|
+
function responseColumnId(itemId, slotId) {
|
|
1676
|
+
return `${itemId}::${slotId}`;
|
|
1677
|
+
}
|
|
1678
|
+
function metaColumnId(metaField) {
|
|
1679
|
+
return `meta:${metaField}`;
|
|
1680
|
+
}
|
|
1681
|
+
function contextColumnId(contextKey) {
|
|
1682
|
+
return `context:${contextKey}`;
|
|
1683
|
+
}
|
|
1684
|
+
function formatMetaValue(response, metaField) {
|
|
1685
|
+
switch (metaField) {
|
|
1686
|
+
case "submittedAt":
|
|
1687
|
+
if (response.submittedAt == null || response.submittedAt === 0) return "";
|
|
1688
|
+
return format(/* @__PURE__ */ new Date(response.submittedAt * 1e3), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx");
|
|
1689
|
+
case "participantId": return response.participantId ?? "";
|
|
1690
|
+
case "responseId": return response.key;
|
|
1691
|
+
case "versionId": return response.versionId;
|
|
1692
|
+
default: return "";
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
var SurveyResponseExporter = class {
|
|
1696
|
+
versions = /* @__PURE__ */ new Map();
|
|
1697
|
+
constructor(versionBindings, profiles = []) {
|
|
1698
|
+
this.profiles = profiles;
|
|
1699
|
+
for (const vb of versionBindings) this.versions.set(vb.versionId, vb);
|
|
1700
|
+
}
|
|
1701
|
+
getSurveyForVersion(versionId) {
|
|
1702
|
+
return this.versions.get(versionId);
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Compute response-only columns from survey definition.
|
|
1706
|
+
*/
|
|
1707
|
+
computeResponseColumns(versionId) {
|
|
1708
|
+
const binding = this.versions.get(versionId);
|
|
1709
|
+
if (!binding) return [];
|
|
1710
|
+
const survey = binding.survey;
|
|
1711
|
+
const keyIndex = survey.keyIndex;
|
|
1712
|
+
const keyByItemId = new Map(keyIndex.map((r) => [r.itemId, r]));
|
|
1713
|
+
const profile = this.resolveProfileForVersion(versionId);
|
|
1714
|
+
const columns = [];
|
|
1715
|
+
for (const { itemId, slots } of survey.getResponseSlotDefinitions()) {
|
|
1716
|
+
const keyInfo = keyByItemId.get(itemId);
|
|
1717
|
+
const itemBaseKey = keyInfo ? [...keyInfo.keyPath, keyInfo.key].join(".") : itemId;
|
|
1718
|
+
for (const slot of slots) {
|
|
1719
|
+
const columnId = responseColumnId(itemId, slot.slotId);
|
|
1720
|
+
const codingPath = [...slot.keyPath, slot.key].filter((part) => part.trim().length > 0);
|
|
1721
|
+
const defaultHeader = codingPath.length > 0 ? `${itemBaseKey}__${codingPath.join(".")}` : `${itemBaseKey}__${slot.slotId}`;
|
|
1722
|
+
const header = this.resolveColumnHeader(profile, columnId, defaultHeader);
|
|
1723
|
+
columns.push({
|
|
1724
|
+
id: columnId,
|
|
1725
|
+
header,
|
|
1726
|
+
source: ExportColumnSource.response,
|
|
1727
|
+
itemId,
|
|
1728
|
+
slotId: slot.slotId,
|
|
1729
|
+
valueType: slot.valueType
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
return columns;
|
|
1734
|
+
}
|
|
1735
|
+
/**
|
|
1736
|
+
* Compute full export columns: meta first, then context (from responses), then response columns.
|
|
1737
|
+
* Column order: meta (fixed) -> context (profile order or alphabetical) -> response (profile order + alphabetical).
|
|
1738
|
+
*/
|
|
1739
|
+
computeColumns(versionId, responses, versionIds) {
|
|
1740
|
+
const vids = versionIds ?? [versionId];
|
|
1741
|
+
const responseCols = [];
|
|
1742
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1743
|
+
for (const vid of vids) for (const c of this.computeResponseColumns(vid)) if (!seen.has(c.id)) {
|
|
1744
|
+
seen.add(c.id);
|
|
1745
|
+
responseCols.push(c);
|
|
1746
|
+
}
|
|
1747
|
+
const profile = this.resolveProfileForVersion(versionId);
|
|
1748
|
+
const metaColumns = META_COLUMN_ORDER.map((metaField) => ({
|
|
1749
|
+
id: metaColumnId(metaField),
|
|
1750
|
+
header: this.resolveColumnHeader(profile, metaColumnId(metaField), metaField),
|
|
1751
|
+
source: ExportColumnSource.meta,
|
|
1752
|
+
metaField
|
|
1753
|
+
}));
|
|
1754
|
+
const contextKeys = /* @__PURE__ */ new Set();
|
|
1755
|
+
for (const r of responses ?? []) if (r.context) for (const k of Object.keys(r.context)) contextKeys.add(k);
|
|
1756
|
+
const contextOrder = profile?.contextColumnOrder;
|
|
1757
|
+
const contextCols = Array.from(contextKeys).sort(contextOrder ? (a, b) => {
|
|
1758
|
+
const ia = contextOrder.indexOf(a);
|
|
1759
|
+
const ib = contextOrder.indexOf(b);
|
|
1760
|
+
if (ia >= 0 && ib >= 0) return ia - ib;
|
|
1761
|
+
if (ia >= 0) return -1;
|
|
1762
|
+
if (ib >= 0) return 1;
|
|
1763
|
+
return a.localeCompare(b);
|
|
1764
|
+
} : void 0).map((contextKey) => ({
|
|
1765
|
+
id: contextColumnId(contextKey),
|
|
1766
|
+
header: this.resolveColumnHeader(profile, contextColumnId(contextKey), `context.${contextKey}`),
|
|
1767
|
+
source: ExportColumnSource.context,
|
|
1768
|
+
contextKey
|
|
1769
|
+
}));
|
|
1770
|
+
const respOrder = profile?.responseColumnOrder ?? [];
|
|
1771
|
+
const byOrder = respOrder.filter((id) => responseCols.some((c) => c.id === id)).map((id) => responseCols.find((c) => c.id === id));
|
|
1772
|
+
const remaining = responseCols.filter((c) => !respOrder.includes(c.id)).sort((a, b) => a.header.localeCompare(b.header));
|
|
1773
|
+
const respCols = [...byOrder, ...remaining];
|
|
1774
|
+
const columns = [
|
|
1775
|
+
...metaColumns,
|
|
1776
|
+
...contextCols,
|
|
1777
|
+
...respCols
|
|
1778
|
+
];
|
|
1779
|
+
this.assertUniqueHeaders(columns);
|
|
1780
|
+
return columns;
|
|
1781
|
+
}
|
|
1782
|
+
resolveProfileForVersion(versionId) {
|
|
1783
|
+
return this.profiles.find((p) => !p.versionId || p.versionId === versionId);
|
|
1784
|
+
}
|
|
1785
|
+
resolveColumnHeader(profile, columnId, defaultHeader) {
|
|
1786
|
+
const override = profile?.columnHeaders?.[columnId]?.trim();
|
|
1787
|
+
return override && override.length > 0 ? override : defaultHeader;
|
|
1788
|
+
}
|
|
1789
|
+
assertUniqueHeaders(columns) {
|
|
1790
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1791
|
+
for (const column of columns) {
|
|
1792
|
+
const existingId = seen.get(column.header);
|
|
1793
|
+
if (existingId && existingId !== column.id) throw new Error(`Duplicate export column header '${column.header}' for columns '${existingId}' and '${column.id}'`);
|
|
1794
|
+
seen.set(column.header, column.id);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
getTransformConfig(versionId, itemId, slotId) {
|
|
1798
|
+
return this.resolveProfileForVersion(versionId)?.slotOverrides?.[slotOverrideKey(itemId, slotId)] ?? DEFAULT_TRANSFORM;
|
|
1799
|
+
}
|
|
1800
|
+
getContextTransformConfig(versionId, contextKey) {
|
|
1801
|
+
return this.resolveProfileForVersion(versionId)?.contextOverrides?.[contextKey] ?? DEFAULT_TRANSFORM;
|
|
1802
|
+
}
|
|
1803
|
+
exportResponse(response) {
|
|
1804
|
+
if (!this.versions.get(response.versionId)) return null;
|
|
1805
|
+
const columns = this.computeColumns(response.versionId, [response]);
|
|
1806
|
+
const row = {};
|
|
1807
|
+
for (const col of columns) {
|
|
1808
|
+
if (col.source === ExportColumnSource.meta && col.metaField) {
|
|
1809
|
+
row[col.header] = formatMetaValue(response, col.metaField);
|
|
1810
|
+
continue;
|
|
1811
|
+
}
|
|
1812
|
+
if (col.source === ExportColumnSource.context && col.contextKey) {
|
|
1813
|
+
const value = response.context?.[col.contextKey];
|
|
1814
|
+
const transformConfig = this.getContextTransformConfig(response.versionId, col.contextKey);
|
|
1815
|
+
const valueType = value?.type ?? ValueType.string;
|
|
1816
|
+
row[col.header] = exportSingleResponseSlot({
|
|
1817
|
+
value,
|
|
1818
|
+
valueType,
|
|
1819
|
+
transformConfig
|
|
1820
|
+
});
|
|
1821
|
+
continue;
|
|
1822
|
+
}
|
|
1823
|
+
if (col.source === ExportColumnSource.response && col.itemId != null && col.slotId != null && col.valueType != null) {
|
|
1824
|
+
const value = response.responses.get(col.itemId)?.response?.get(col.slotId);
|
|
1825
|
+
const transformConfig = this.getTransformConfig(response.versionId, col.itemId, col.slotId);
|
|
1826
|
+
row[col.header] = exportSingleResponseSlot({
|
|
1827
|
+
value,
|
|
1828
|
+
valueType: col.valueType,
|
|
1829
|
+
transformConfig
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
return row;
|
|
1834
|
+
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Compute columns for a batch of responses (union of response columns across versions).
|
|
1837
|
+
*/
|
|
1838
|
+
computeColumnsForBatch(responses) {
|
|
1839
|
+
if (responses.length === 0) return [];
|
|
1840
|
+
const versionIds = [...new Set(responses.map((r) => r.versionId))];
|
|
1841
|
+
const primaryVersionId = versionIds[0];
|
|
1842
|
+
return this.computeColumns(primaryVersionId, responses, versionIds);
|
|
1843
|
+
}
|
|
1844
|
+
exportResponsesToCsv(responses, options) {
|
|
1845
|
+
if (responses.length === 0) return "";
|
|
1846
|
+
return serializeToCsv(this.computeColumnsForBatch(responses), responses.map((r) => this.exportResponse(r)).filter((r) => r !== null), options);
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
//#endregion
|
|
1850
|
+
//#region src/response-exporter/codebook.ts
|
|
1851
|
+
/**
|
|
1852
|
+
* Extract plain text from Content for codebook display.
|
|
1853
|
+
*/
|
|
1854
|
+
function contentToPlainText(c) {
|
|
1855
|
+
if (!c) return "";
|
|
1856
|
+
return c.content ?? "";
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* Generate a structured codebook from a survey definition.
|
|
1860
|
+
*/
|
|
1861
|
+
function generateCodebook(survey, options) {
|
|
1862
|
+
const locales = options?.locales ?? survey.locales;
|
|
1863
|
+
const keyIndex = survey.keyIndex;
|
|
1864
|
+
const keyByItemId = new Map(keyIndex.map((r) => [r.itemId, r]));
|
|
1865
|
+
const slotDefsByItemId = new Map(survey.getResponseSlotDefinitions().map(({ itemId, slots }) => [itemId, slots.map((slot) => ({
|
|
1866
|
+
slotId: slot.slotId,
|
|
1867
|
+
key: slot.key,
|
|
1868
|
+
keyPath: [...slot.keyPath],
|
|
1869
|
+
valueType: slot.valueType
|
|
1870
|
+
}))]));
|
|
1871
|
+
const items = [];
|
|
1872
|
+
for (const item of survey.surveyItems.values()) {
|
|
1873
|
+
const keyInfo = keyByItemId.get(item.id);
|
|
1874
|
+
const key = keyInfo?.key ?? item.id;
|
|
1875
|
+
const keyPath = keyInfo?.keyPath ?? [];
|
|
1876
|
+
const slotList = slotDefsByItemId.get(item.id) ?? [];
|
|
1877
|
+
slotList.sort((a, b) => a.slotId.localeCompare(b.slotId));
|
|
1878
|
+
let contentByLocale;
|
|
1879
|
+
if (locales.length > 0) {
|
|
1880
|
+
contentByLocale = {};
|
|
1881
|
+
const itemTranslations = survey.getItemTranslations(item.id);
|
|
1882
|
+
if (itemTranslations) for (const locale of locales) {
|
|
1883
|
+
const all = itemTranslations.getAllForLocale(locale);
|
|
1884
|
+
if (all) {
|
|
1885
|
+
const flat = {};
|
|
1886
|
+
for (const [contentKey, content] of Object.entries(all)) flat[contentKey] = contentToPlainText(content);
|
|
1887
|
+
contentByLocale[locale] = flat;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
items.push({
|
|
1892
|
+
id: item.id,
|
|
1893
|
+
key,
|
|
1894
|
+
keyPath,
|
|
1895
|
+
type: item.type,
|
|
1896
|
+
interactive: item.isInteractive(),
|
|
1897
|
+
slots: slotList,
|
|
1898
|
+
contentByLocale
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
return {
|
|
1902
|
+
surveyKey: survey.surveyKey,
|
|
1903
|
+
items: items.sort((a, b) => a.key.localeCompare(b.key))
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
//#endregion
|
|
1907
|
+
export { AndExpressionEditor, AttributionType, ConstBooleanEditor, ConstDateArrayEditor, ConstDateEditor, ConstExpression, ConstNumberArrayEditor, ConstNumberEditor, ConstStringArrayEditor, ConstStringEditor, ContentType, ContextVariableExpression, ContextVariableType, CtxCustomExpressionEditor, CtxCustomValueEditor, CtxLocaleEditor, CtxPFlagDateEditor, CtxPFlagIsDefinedEditor, CtxPFlagNumEditor, CtxPFlagStringEditor, DEFAULT_TRANSFORM, DurationUnits, EXPORT_COLUMN_SLOT_SEPARATOR, EqExpressionEditor, Expression, ExpressionEditor, ExpressionEvaluator, ExpressionType, FunctionExpression, FunctionExpressionNames, GroupItemCore, GtExpressionEditor, GteExpressionEditor, InRangeExpressionEditor, LtExpressionEditor, LteExpressionEditor, META_COLUMN_ORDER, MaxExpressionEditor, MinExpressionEditor, NumberPrecision, OrExpressionEditor, PageBreakItemCore, ReferenceUsageType, ReservedSurveyItemTypes, ResponseItem, ResponseVariableEditor, ResponseVariableExpression, SlotTransformMode, StrEqExpressionEditor, StrListContainsExpressionEditor, SumExpressionEditor, Survey, SurveyEngineCore, SurveyEventTypes, SurveyItemCore, SurveyItemKey, SurveyItemResponse, SurveyItemTranslations, SurveyResponse, SurveyResponseExporter, SurveyTranslations, TemplateDefTypes, ValueReference, ValueReferenceMethod, ValueType, and, builtInItemCoreRegistry, const_boolean, const_date, const_date_array, const_number, const_number_array, const_string, const_string_array, createFullRegistry, createItemCore, createItemTypeDefinitionRegistry, ctx_custom_expression, ctx_custom_value, ctx_locale, ctx_pflag_date, ctx_pflag_is_defined, ctx_pflag_num, ctx_pflag_string, deserializeTemplateValue, deserializeTemplateValues, eq, escapeCsvCell, exportSingleResponseSlot, flattenTree, generateCodebook, generateCodingKey, generateId, gt, gte, in_range, initValueForType, isBuiltInItemType, isLegacyItemGroupComponent, isLegacySurveyGroupItem, lt, lte, max, min, or, response_boolean, response_date, response_date_array, response_number, response_number_array, response_string, response_string_array, serializeTemplateValue, serializeTemplateValues, serializeToCsv, shuffleIndices, str_eq, str_list_contains, structuredCloneMethod, sum, toItemTypeDefinitionRegistry, validateLocale };
|
|
1908
|
+
|
|
1586
1909
|
//# sourceMappingURL=index.mjs.map
|