@frt-platform/report-core 1.0.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/dist/index.mjs ADDED
@@ -0,0 +1,197 @@
1
+ // src/schema.ts
2
+ import { z } from "zod";
3
+ var REPORT_TEMPLATE_VERSION = 1;
4
+ var REPORT_TEMPLATE_FIELD_TYPES = [
5
+ "shortText",
6
+ "longText",
7
+ "number",
8
+ "date",
9
+ "checkbox",
10
+ "singleSelect",
11
+ "multiSelect",
12
+ "starRating"
13
+ ];
14
+ var ReportTemplateFieldSchema = z.object({
15
+ id: z.string().min(1).max(60).regex(/^[a-z0-9_-]+$/),
16
+ type: z.string(),
17
+ label: z.string().min(1).max(200),
18
+ required: z.boolean().optional(),
19
+ description: z.string().max(400).optional(),
20
+ placeholder: z.string().max(200).optional(),
21
+ options: z.array(z.string().min(1).max(120)).optional(),
22
+ allowOther: z.boolean().optional(),
23
+ defaultValue: z.union([
24
+ z.string(),
25
+ z.number(),
26
+ z.boolean(),
27
+ z.array(z.string()),
28
+ z.null()
29
+ ]).optional(),
30
+ minLength: z.number().int().min(0).optional(),
31
+ maxLength: z.number().int().min(0).optional(),
32
+ minValue: z.number().optional(),
33
+ maxValue: z.number().optional(),
34
+ step: z.number().nonnegative().optional(),
35
+ minSelections: z.number().int().min(0).optional(),
36
+ maxSelections: z.number().int().min(0).optional(),
37
+ dataClassification: z.enum(["none", "personal", "special"]).optional()
38
+ });
39
+ var ReportTemplateSectionSchema = z.object({
40
+ id: z.string().min(1).max(60).regex(/^[a-z0-9_-]+$/),
41
+ title: z.string().max(200).optional(),
42
+ description: z.string().max(500).optional(),
43
+ fields: z.array(ReportTemplateFieldSchema).default([])
44
+ });
45
+ var ReportTemplateSchemaValidator = z.object({
46
+ version: z.number().int().min(1).default(REPORT_TEMPLATE_VERSION),
47
+ title: z.string().max(200).optional(),
48
+ description: z.string().max(500).optional(),
49
+ sections: z.array(ReportTemplateSectionSchema).max(25).default([])
50
+ });
51
+
52
+ // src/fields.ts
53
+ var DEFAULT_FIELD_LABEL = "Untitled question";
54
+ var CORE_FIELD_DEFAULTS = {
55
+ shortText: { label: DEFAULT_FIELD_LABEL, placeholder: "Short answer text" },
56
+ longText: { label: DEFAULT_FIELD_LABEL, placeholder: "Long answer text" },
57
+ number: { label: DEFAULT_FIELD_LABEL, placeholder: "123" },
58
+ date: { label: DEFAULT_FIELD_LABEL },
59
+ checkbox: { label: DEFAULT_FIELD_LABEL, placeholder: "Check to confirm" },
60
+ singleSelect: {
61
+ label: DEFAULT_FIELD_LABEL,
62
+ options: ["Option 1", "Option 2", "Option 3"]
63
+ },
64
+ multiSelect: {
65
+ label: DEFAULT_FIELD_LABEL,
66
+ options: ["Option 1", "Option 2", "Option 3"],
67
+ allowOther: false
68
+ },
69
+ starRating: {
70
+ label: DEFAULT_FIELD_LABEL,
71
+ minValue: 1,
72
+ maxValue: 5
73
+ }
74
+ };
75
+
76
+ // src/ids.ts
77
+ function createUniqueId(prefix, existing) {
78
+ const used = new Set(existing);
79
+ let attempt = used.size + 1;
80
+ let candidate = `${prefix}-${attempt}`;
81
+ while (used.has(candidate)) {
82
+ attempt++;
83
+ candidate = `${prefix}-${attempt}`;
84
+ }
85
+ return candidate;
86
+ }
87
+
88
+ // src/migrate.ts
89
+ var LEGACY_FIELD_TYPE_MAP = {
90
+ shorttext: "shortText",
91
+ text: "shortText",
92
+ longtext: "longText",
93
+ textarea: "longText",
94
+ number: "number",
95
+ numeric: "number",
96
+ date: "date",
97
+ checkbox: "checkbox",
98
+ boolean: "checkbox",
99
+ select: "singleSelect",
100
+ dropdown: "singleSelect",
101
+ radio: "singleSelect",
102
+ multiselect: "multiSelect",
103
+ checkboxes: "multiSelect"
104
+ };
105
+ function migrateLegacySchema(raw) {
106
+ if (!raw || typeof raw !== "object") return raw;
107
+ const obj = structuredClone(raw);
108
+ if (obj.fields) {
109
+ obj.sections = [
110
+ {
111
+ id: "section-1",
112
+ title: obj.title,
113
+ description: obj.description,
114
+ fields: obj.fields.map((f, i) => ({
115
+ ...f,
116
+ id: f.id || `field-${i + 1}`,
117
+ type: LEGACY_FIELD_TYPE_MAP[f.type?.toLowerCase()] ?? f.type
118
+ }))
119
+ }
120
+ ];
121
+ delete obj.fields;
122
+ return obj;
123
+ }
124
+ if (Array.isArray(obj.sections)) {
125
+ obj.sections = obj.sections.map((sec, i) => ({
126
+ ...sec,
127
+ id: sec.id || `section-${i + 1}`,
128
+ fields: (sec.fields || []).map((f, idx) => ({
129
+ ...f,
130
+ id: f.id || `field-${idx + 1}`,
131
+ type: LEGACY_FIELD_TYPE_MAP[f.type?.toLowerCase()] ?? f.type
132
+ }))
133
+ }));
134
+ }
135
+ return obj;
136
+ }
137
+
138
+ // src/normalize.ts
139
+ function parseReportTemplateSchema(raw) {
140
+ const migrated = migrateLegacySchema(raw);
141
+ const parsed = ReportTemplateSchemaValidator.parse(migrated);
142
+ return normalizeReportTemplateSchema(parsed);
143
+ }
144
+ function normalizeReportTemplateSchema(schema) {
145
+ const sections = schema.sections.length > 0 ? schema.sections : [
146
+ {
147
+ id: "section-1",
148
+ title: "",
149
+ description: "",
150
+ fields: []
151
+ }
152
+ ];
153
+ const normalizedSections = sections.map((sec, i) => {
154
+ const seen = /* @__PURE__ */ new Set();
155
+ const safeSectionId = sec.id.trim() || `section-${i + 1}`;
156
+ const fields = sec.fields.map((field, idx) => {
157
+ const trimmed = field.id.trim() || `field-${idx + 1}`;
158
+ const safeId = seen.has(trimmed) ? `field-${idx + 1}` : trimmed;
159
+ seen.add(safeId);
160
+ return {
161
+ ...field,
162
+ id: safeId
163
+ };
164
+ });
165
+ return {
166
+ ...sec,
167
+ id: safeSectionId,
168
+ fields
169
+ };
170
+ });
171
+ return {
172
+ ...schema,
173
+ sections: normalizedSections
174
+ };
175
+ }
176
+ function parseReportTemplateSchemaFromString(raw) {
177
+ const obj = JSON.parse(raw);
178
+ return parseReportTemplateSchema(obj);
179
+ }
180
+ function serializeReportTemplateSchema(schema) {
181
+ return JSON.stringify(schema, null, 2);
182
+ }
183
+ export {
184
+ CORE_FIELD_DEFAULTS,
185
+ DEFAULT_FIELD_LABEL,
186
+ REPORT_TEMPLATE_FIELD_TYPES,
187
+ REPORT_TEMPLATE_VERSION,
188
+ ReportTemplateFieldSchema,
189
+ ReportTemplateSchemaValidator,
190
+ ReportTemplateSectionSchema,
191
+ createUniqueId,
192
+ migrateLegacySchema,
193
+ normalizeReportTemplateSchema,
194
+ parseReportTemplateSchema,
195
+ parseReportTemplateSchemaFromString,
196
+ serializeReportTemplateSchema
197
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@frt-platform/report-core",
3
+ "version": "1.0.0",
4
+ "description": "Core report template engine: schema, validation, normalization, and migration.",
5
+ "author": "Sebastian Mostert",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.mjs",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "sideEffects": false,
22
+ "scripts": {
23
+ "build": "tsup src/index.ts --format esm,cjs --dts",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "dependencies": {
30
+ "zod": "^3.23.8"
31
+ },
32
+ "devDependencies": {
33
+ "tsup": "^8.5.1",
34
+ "typescript": "^5.6.3"
35
+ }
36
+ }