@ninetailed/experience.js-utils 3.0.0 → 3.0.1-beta.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.
Files changed (2) hide show
  1. package/index.cjs +197 -0
  2. package/package.json +4 -4
package/index.cjs ADDED
@@ -0,0 +1,197 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var experience_jsShared = require('@ninetailed/experience.js-shared');
6
+ var zod = require('zod');
7
+
8
+ const Audience = zod.z.object({
9
+ id: zod.z.string()
10
+ });
11
+
12
+ const Config = zod.z.object({
13
+ distribution: zod.z.array(zod.z.number()).default([0.5, 0.5]),
14
+ traffic: zod.z.number().default(0),
15
+ components: zod.z.array(zod.z.object({
16
+ baseline: zod.z.object({
17
+ id: zod.z.string().default('')
18
+ }),
19
+ variants: zod.z.array(zod.z.object({
20
+ id: zod.z.string().default(''),
21
+ hidden: zod.z.boolean().default(false)
22
+ }))
23
+ })).default([{
24
+ baseline: {
25
+ id: ''
26
+ },
27
+ variants: [{
28
+ id: '',
29
+ hidden: false
30
+ }]
31
+ }])
32
+ });
33
+ // export interface Config {
34
+ // distribution: number[];
35
+ // traffic: number;
36
+ // components: BaselineWithVariantRefs[];
37
+ // }
38
+
39
+ const Variant = zod.z.object({
40
+ id: zod.z.string()
41
+ }).catchall(zod.z.unknown());
42
+
43
+ /**
44
+ * Zod helper for parsing arrays and ignore items not specified in the schema
45
+ *
46
+ * @param zodUnion - union of known types
47
+ *
48
+ * @example
49
+ * const binaryArraySchema = arrayIgnoreUnknown(z.union([z.literal('0'), z.literal('1')]))
50
+ * type BinaryArray = z.TypeOf<typeof binaryArraySchema>
51
+ *
52
+ * const binaryArray: BinaryArray = binaryArraySchema.parse(['0', '1', '2', '0'])
53
+ * console.log(binaryArray) // ['0', '1', '0']
54
+ */
55
+ function zodArrayIgnoreUnknown(zodType) {
56
+ const isKnownItem = item => zodType.safeParse(item).success;
57
+ return zod.z.preprocess(val => toSafeArray(val).filter(isKnownItem), zod.z.array(zodType));
58
+ }
59
+ function toSafeArray(item) {
60
+ if (isArray(item)) {
61
+ return item;
62
+ }
63
+ return [item];
64
+ }
65
+ function isArray(item) {
66
+ return Array.isArray(item);
67
+ }
68
+
69
+ const ExperienceSchema = zod.z.object({
70
+ id: zod.z.string(),
71
+ /**
72
+ * The name of the experience (Short Text)
73
+ */
74
+ name: zod.z.string(),
75
+ /**
76
+ * The type if the experience (nt_experiment | nt_personalization)
77
+ */
78
+ type: zod.z.union([zod.z.string().regex(/^nt_experiment$/g), zod.z.string().regex(/^nt_personalization$/g)]),
79
+ /**
80
+ * The config of the experience (JSON)
81
+ */
82
+ config: Config.default({}),
83
+ /**
84
+ * The audience of the experience (Audience)
85
+ */
86
+ audience: Audience.optional().nullable(),
87
+ /**
88
+ * All used variants of the experience (References to other Content Types)
89
+ */
90
+ variants: zodArrayIgnoreUnknown(Variant).default([])
91
+ });
92
+ const parse$1 = input => {
93
+ const output = ExperienceSchema.parse(input);
94
+ return Object.assign(Object.assign({}, output), {
95
+ variants: input.variants
96
+ });
97
+ };
98
+ const safeParse$1 = input => {
99
+ const output = ExperienceSchema.safeParse(input);
100
+ if (!output.success) {
101
+ return output;
102
+ }
103
+ return Object.assign(Object.assign({}, output), {
104
+ data: Object.assign(Object.assign({}, output.data), {
105
+ variants: input.variants
106
+ })
107
+ });
108
+ };
109
+ const Experience = Object.assign(Object.assign({}, ExperienceSchema), {
110
+ parse: parse$1,
111
+ safeParse: safeParse$1
112
+ });
113
+
114
+ const ExperimentSchema = ExperienceSchema.extend({
115
+ type: zod.z.string().regex(/^nt_experiment$/g)
116
+ });
117
+ const parse = input => {
118
+ const output = ExperimentSchema.parse(input);
119
+ return Object.assign(Object.assign({}, output), {
120
+ variants: input.variants
121
+ });
122
+ };
123
+ const safeParse = input => {
124
+ const output = ExperimentSchema.safeParse(input);
125
+ if (!output.success) {
126
+ return output;
127
+ }
128
+ return Object.assign(Object.assign({}, output), {
129
+ data: Object.assign(Object.assign({}, output.data), {
130
+ variants: input.variants
131
+ })
132
+ });
133
+ };
134
+ const Experiment = Object.assign(Object.assign({}, ExperimentSchema), {
135
+ parse,
136
+ safeParse
137
+ });
138
+
139
+ class ExperienceMapper {
140
+ static isExperienceEntry(experience) {
141
+ return Experience.safeParse(experience).success;
142
+ }
143
+ static mapExperience(experience) {
144
+ const parsedExperience = Experience.safeParse(experience);
145
+ if (!parsedExperience.success) {
146
+ experience_jsShared.logger.warn('[Ninetailed ExperienceMapper]', 'Error parsing experience', parsedExperience.error.format());
147
+ throw new Error(`[Ninetailed ExperienceMapper] The Experience Input is not valid. Please filter data first with "ExperienceMapper.isExperienceEntry".\n${JSON.stringify(parsedExperience.error.format(), null, 2)}`);
148
+ }
149
+ const {
150
+ id,
151
+ type,
152
+ audience,
153
+ config,
154
+ variants
155
+ } = parsedExperience.data;
156
+ const {
157
+ components,
158
+ traffic
159
+ } = config;
160
+ return Object.assign(Object.assign({
161
+ id,
162
+ type: type
163
+ }, audience ? {
164
+ audience
165
+ } : {}), {
166
+ trafficAllocation: traffic,
167
+ distribution: config.distribution.map((percentage, index) => ({
168
+ index,
169
+ start: config.distribution.slice(0, index).reduce((a, b) => a + b, 0),
170
+ end: config.distribution.slice(0, index + 1).reduce((a, b) => a + b, 0)
171
+ })),
172
+ components: components.map(component => ({
173
+ baseline: component.baseline,
174
+ variants: component.variants.map(variantRef => {
175
+ if (variantRef.hidden) {
176
+ return variantRef;
177
+ }
178
+ const matchingVariant = variants.find(variant => variant.id === variantRef.id);
179
+ return matchingVariant !== null && matchingVariant !== void 0 ? matchingVariant : null;
180
+ }).filter(variant => variant !== null)
181
+ }))
182
+ });
183
+ }
184
+ static isExperimentEntry(experiment) {
185
+ return Experiment.safeParse(experiment).success;
186
+ }
187
+ static mapExperiment(experiment) {
188
+ return ExperienceMapper.mapExperience(experiment);
189
+ }
190
+ }
191
+
192
+ exports.Audience = Audience;
193
+ exports.Config = Config;
194
+ exports.Experience = Experience;
195
+ exports.ExperienceMapper = ExperienceMapper;
196
+ exports.Experiment = Experiment;
197
+ exports.Variant = Variant;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@ninetailed/experience.js-utils",
3
- "version": "3.0.0",
3
+ "version": "3.0.1-beta.0",
4
4
  "module": "./index.js",
5
- "main": "./index.js",
5
+ "main": "./index.cjs",
6
6
  "type": "module",
7
7
  "types": "./index.d.ts",
8
8
  "dependencies": {
9
- "@ninetailed/experience.js": "3.0.0",
10
- "@ninetailed/experience.js-shared": "3.0.0",
9
+ "@ninetailed/experience.js": "3.0.1-beta.0",
10
+ "@ninetailed/experience.js-shared": "3.0.1-beta.0",
11
11
  "zod": "3.20.2"
12
12
  },
13
13
  "peerDependencies": {}