@pie-element/ebsr 6.6.3-next.133 → 6.6.3-next.1353

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.
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { settings, layout } from '@pie-lib/config-ui';
4
4
  import { withStyles } from '@material-ui/core/styles';
5
- import cloneDeep from 'lodash/cloneDeep';
6
5
 
7
6
  const { Panel, toggle, radio, dropdown } = settings;
8
7
 
@@ -68,7 +67,7 @@ export class Main extends React.Component {
68
67
  configuration,
69
68
  onConfigurationChanged
70
69
  } = this.props;
71
- const { partLabelType } = model;
70
+ const { partLabelType, partA: modelPartA, partB: modelPartB } = model;
72
71
  const { partA, partB, partialScoring, scoringType, ...generalConfiguration } = configuration;
73
72
  const {
74
73
  feedback: feedbackA = {},
@@ -78,8 +77,10 @@ export class Main extends React.Component {
78
77
  prompt: promptA = {},
79
78
  teacherInstructions: teacherInstructionsA = {},
80
79
  studentInstructions: studentInstructionsA = {},
81
- verticalMode: verticalModeA = {},
82
- rationale: rationaleA = {}
80
+ choicesLayout: choicesLayoutA = {},
81
+ gridColumns: gridColumnsA = {},
82
+ rationale: rationaleA = {},
83
+ spellCheck: spellCheckA = {}
83
84
  } = partA || {};
84
85
  const {
85
86
  feedback: feedbackB = {},
@@ -89,13 +90,21 @@ export class Main extends React.Component {
89
90
  prompt: promptB = {},
90
91
  teacherInstructions: teacherInstructionsB = {},
91
92
  studentInstructions: studentInstructionsB = {},
92
- verticalMode: verticalModeB = {},
93
- rationale: rationaleB = {}
93
+ choicesLayout: choicesLayoutB = {},
94
+ gridColumns: gridColumnsB = {},
95
+ rationale: rationaleB = {},
96
+ spellCheck: spellCheckB = {}
94
97
  } = partB || {};
95
98
  const type = partLabelType || 'Numbers';
96
99
  const typeIsNumber = type === 'Numbers';
97
100
  const firstPart = `Part ${typeIsNumber ? '1' : 'A'}`;
98
101
  const secondPart = `Part ${typeIsNumber ? '2' : 'B'}`;
102
+ const nrOfColumnsAvailable = {
103
+ partA: modelPartA.choices && modelPartA.choices.length ?
104
+ Array.from({length: modelPartA.choices.length}, (_, i) => (`${i + 1}`)) : [],
105
+ partB: modelPartB.choices && modelPartB.choices.length ?
106
+ Array.from({length: modelPartB.choices.length}, (_, i) => (`${i + 1}`)) : [],
107
+ };
99
108
 
100
109
  return (
101
110
  <div className={classes.design}>
@@ -127,8 +136,13 @@ export class Main extends React.Component {
127
136
  radio(choicePrefixA.label, ['numbers', 'letters']),
128
137
  'partA.lockChoiceOrder':
129
138
  lockChoiceOrderA.settings && toggle(lockChoiceOrderA.label),
130
- 'partA.verticalMode':
131
- verticalModeA.settings && toggle(verticalModeA.label)
139
+ 'partA.choicesLayout':
140
+ choicesLayoutA.settings &&
141
+ dropdown(choicesLayoutA.label, ['vertical', 'grid', 'horizontal']),
142
+ 'partA.gridColumns':
143
+ choicesLayoutA.settings && modelPartA.choicesLayout === 'grid' &&
144
+ nrOfColumnsAvailable.partA.length > 0 &&
145
+ dropdown(gridColumnsA.label, nrOfColumnsAvailable.partA)
132
146
  },
133
147
  [`Properties ${firstPart}`]: {
134
148
  'partA.feedbackEnabled': feedbackA.settings &&
@@ -142,7 +156,9 @@ export class Main extends React.Component {
142
156
  studentInstructionsA.settings &&
143
157
  toggle(studentInstructionsA.label),
144
158
  'partA.rationaleEnabled':
145
- rationaleA.settings && toggle(rationaleA.label)
159
+ rationaleA.settings && toggle(rationaleA.label),
160
+ 'partA.spellCheckEnabled':
161
+ spellCheckA.settings && toggle(spellCheckA.label),
146
162
  },
147
163
  [`Settings ${secondPart}`]: {
148
164
  'partB.choiceMode':
@@ -153,8 +169,13 @@ export class Main extends React.Component {
153
169
  radio(choicePrefixB.label, ['numbers', 'letters']),
154
170
  'partB.lockChoiceOrder':
155
171
  lockChoiceOrderB.settings && toggle(lockChoiceOrderB.label),
156
- 'partB.verticalMode':
157
- verticalModeB.settings && toggle(verticalModeB.label)
172
+ 'partB.choicesLayout':
173
+ choicesLayoutB.settings &&
174
+ dropdown(choicesLayoutB.label, ['vertical', 'grid', 'horizontal']),
175
+ 'partB.gridColumns':
176
+ choicesLayoutB.settings && modelPartB.choicesLayout === 'grid' &&
177
+ nrOfColumnsAvailable.partB.length > 0 &&
178
+ dropdown(gridColumnsB.label, nrOfColumnsAvailable.partB)
158
179
  },
159
180
  [`Properties ${secondPart}`]: {
160
181
  'partB.feedbackEnabled':
@@ -168,7 +189,9 @@ export class Main extends React.Component {
168
189
  studentInstructionsB.settings &&
169
190
  toggle(studentInstructionsB.label),
170
191
  'partB.rationaleEnabled':
171
- rationaleB.settings && toggle(rationaleB.label)
192
+ rationaleB.settings && toggle(rationaleB.label),
193
+ 'partB.spellCheckEnabled':
194
+ spellCheckB.settings && toggle(spellCheckB.label),
172
195
  }
173
196
  }}
174
197
  />
@@ -184,7 +207,10 @@ export class Main extends React.Component {
184
207
  if (ref) {
185
208
  // do not use destructuring to get model from props
186
209
  this.partA = ref;
187
- this.partA._model = cloneDeep(this.props.model.partA);
210
+ this.partA._model = {
211
+ ...this.props.model.partA,
212
+ errors: this.props.model.errors && this.props.model.errors.partA || {}
213
+ };
188
214
  this.partA.configuration = {
189
215
  ...partA,
190
216
  ...generalConfiguration
@@ -203,7 +229,10 @@ export class Main extends React.Component {
203
229
  if (ref) {
204
230
  // do not use destructuring to get model from props
205
231
  this.partB = ref;
206
- this.partB._model = cloneDeep(this.props.model.partB);
232
+ this.partB._model ={
233
+ ...this.props.model.partB,
234
+ errors: this.props.model.errors && this.props.model.errors.partB || {}
235
+ };
207
236
  this.partB.configuration = {
208
237
  ...partB,
209
238
  ...generalConfiguration
@@ -3,6 +3,39 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [6.0.5](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@6.0.4...@pie-element/ebsr-controller@6.0.5) (2022-05-30)
7
+
8
+ **Note:** Version bump only for package @pie-element/ebsr-controller
9
+
10
+
11
+
12
+
13
+
14
+ ## [6.0.1](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@6.0.0...@pie-element/ebsr-controller@6.0.1) (2021-09-01)
15
+
16
+ **Note:** Version bump only for package @pie-element/ebsr-controller
17
+
18
+
19
+
20
+
21
+
22
+ # [6.0.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@5.2.2...@pie-element/ebsr-controller@6.0.0) (2021-08-09)
23
+
24
+
25
+ ### Features
26
+
27
+ * **ebsr:** Added choicesLayout support ([33fb7e7](https://github.com/pie-framework/pie-elements/commit/33fb7e765146a7343a58663f3667f4a5de472960))
28
+ * **ebsr:** Added choicesLayout support \n BREAKING CHANGE: removed vertical mode ([348fc00](https://github.com/pie-framework/pie-elements/commit/348fc0031536d458071a1105e742c3d19399a15e))
29
+
30
+
31
+ ### BREAKING CHANGES
32
+
33
+ * **ebsr:** removed vertical mode.
34
+
35
+
36
+
37
+
38
+
6
39
  ## [5.2.2](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@5.2.0...@pie-element/ebsr-controller@5.2.2) (2021-08-05)
7
40
 
8
41
 
@@ -5,14 +5,20 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
+ exports.createDefaultModel = exports.createCorrectResponseSession = void 0;
8
9
  exports.model = model;
10
+ exports.normalize = void 0;
9
11
  exports.outcome = outcome;
10
- exports.createCorrectResponseSession = exports.createDefaultModel = exports.normalize = void 0;
12
+ exports.validate = void 0;
11
13
 
12
14
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
13
15
 
16
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
17
+
14
18
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
15
19
 
20
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
21
+
16
22
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
17
23
 
18
24
  var _defaults = _interopRequireDefault(require("./defaults"));
@@ -25,9 +31,11 @@ var _get = _interopRequireDefault(require("lodash/get"));
25
31
 
26
32
  var _isEmpty = _interopRequireDefault(require("lodash/isEmpty"));
27
33
 
28
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
34
+ var _excluded = ["partA", "partB"];
29
35
 
30
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
36
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
37
+
38
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
31
39
 
32
40
  var prepareChoice = function prepareChoice(model, env, defaultFeedback) {
33
41
  return function (choice) {
@@ -78,27 +86,36 @@ var parsePart = function parsePart(part, key, session, env) {
78
86
  });
79
87
  };
80
88
 
81
- var normalize = function normalize(question) {
89
+ var normalize = function normalize(_ref) {
90
+ var _ref$partA = _ref.partA,
91
+ partA = _ref$partA === void 0 ? {} : _ref$partA,
92
+ _ref$partB = _ref.partB,
93
+ partB = _ref$partB === void 0 ? {} : _ref$partB,
94
+ question = (0, _objectWithoutProperties2["default"])(_ref, _excluded);
82
95
  return _objectSpread(_objectSpread({
83
96
  partLabels: true,
84
97
  partLabelType: 'Letters'
85
98
  }, question), {}, {
86
- partA: _objectSpread(_objectSpread({}, _defaults["default"].partA), {}, {
99
+ partA: _objectSpread(_objectSpread(_objectSpread({}, _defaults["default"].partA), {}, {
87
100
  rationaleEnabled: true,
88
101
  feedbackEnabled: true,
89
102
  promptEnabled: true,
90
103
  teacherInstructionsEnabled: true,
91
104
  studentInstructionsEnabled: true,
92
- verticalMode: true
93
- }, question.partA),
94
- partB: _objectSpread(_objectSpread({}, _defaults["default"].partB), {}, {
105
+ gridColumns: '2'
106
+ }, partA), {}, {
107
+ choicesLayout: partA.choicesLayout || partA.verticalMode === false && 'horizontal' || 'vertical'
108
+ }),
109
+ partB: _objectSpread(_objectSpread(_objectSpread({}, _defaults["default"].partB), {}, {
95
110
  rationaleEnabled: true,
96
111
  promptEnabled: true,
97
112
  feedbackEnabled: true,
98
113
  teacherInstructionsEnabled: true,
99
114
  studentInstructionsEnabled: true,
100
- verticalMode: true
101
- }, question.partB)
115
+ gridColumns: '2'
116
+ }, partB), {}, {
117
+ choicesLayout: partB.choicesLayout || partB.verticalMode === false && 'horizontal' || 'vertical'
118
+ })
102
119
  });
103
120
  };
104
121
  /**
@@ -118,7 +135,7 @@ function model(_x, _x2, _x3, _x4) {
118
135
 
119
136
  function _model() {
120
137
  _model = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(question, session, env, updateSession) {
121
- var normalizedQuestion, partA, partB, shuffledValues, us, partASession, partALockChoiceOrder, _ref5, partAChoices, _ref6, partBChoices, partBSession, partBLockChoiceOrder;
138
+ var normalizedQuestion, partA, partB, shuffledValues, us, partASession, partALockChoiceOrder, _ref8, partAChoices, _ref9, partBChoices, partBSession, partBLockChoiceOrder;
122
139
 
123
140
  return _regenerator["default"].wrap(function _callee$(_context) {
124
141
  while (1) {
@@ -140,8 +157,8 @@ function _model() {
140
157
 
141
158
  partASession = (0, _get["default"])(session, 'value.partA');
142
159
  partALockChoiceOrder = (0, _controllerUtils.lockChoices)(normalizedQuestion.partA, partASession, env);
143
- _ref5 = partA || {}, partAChoices = _ref5.choices;
144
- _ref6 = partB || {}, partBChoices = _ref6.choices;
160
+ _ref8 = partA || {}, partAChoices = _ref8.choices;
161
+ _ref9 = partB || {}, partBChoices = _ref9.choices;
145
162
 
146
163
  if (!(!partALockChoiceOrder && partAChoices && partAChoices.length)) {
147
164
  _context.next = 13;
@@ -235,14 +252,14 @@ var isCorrect = function isCorrect(c) {
235
252
  };
236
253
 
237
254
  var getScore = function getScore(config, sessionPart, key) {
238
- var _ref = config && config[key] || {},
239
- _ref$choices = _ref.choices,
240
- choices = _ref$choices === void 0 ? [] : _ref$choices;
255
+ var _ref2 = config && config[key] || {},
256
+ _ref2$choices = _ref2.choices,
257
+ choices = _ref2$choices === void 0 ? [] : _ref2$choices;
241
258
 
242
259
  var maxScore = choices.length;
243
260
 
244
- var _ref2 = sessionPart || {},
245
- sessionPartValue = _ref2.value;
261
+ var _ref3 = sessionPart || {},
262
+ sessionPartValue = _ref3.value;
246
263
 
247
264
  var chosen = function chosen(c) {
248
265
  return !!(sessionPartValue || []).find(function (v) {
@@ -275,8 +292,8 @@ var getScore = function getScore(config, sessionPart, key) {
275
292
 
276
293
  function outcome(config, session) {
277
294
  return new Promise(function (resolve) {
278
- var _ref3 = session || {},
279
- value = _ref3.value;
295
+ var _ref4 = session || {},
296
+ value = _ref4.value;
280
297
 
281
298
  if (!session || !value) {
282
299
  resolve({
@@ -288,9 +305,9 @@ function outcome(config, session) {
288
305
  }
289
306
 
290
307
  if (value) {
291
- var _ref4 = value || {},
292
- partA = _ref4.partA,
293
- partB = _ref4.partB;
308
+ var _ref5 = value || {},
309
+ partA = _ref5.partA,
310
+ partB = _ref5.partB;
294
311
 
295
312
  var scoreA = getScore(config, partA, 'partA');
296
313
  var scoreB = getScore(config, partB, 'partB');
@@ -378,4 +395,77 @@ var createCorrectResponseSession = function createCorrectResponseSession(questio
378
395
  };
379
396
 
380
397
  exports.createCorrectResponseSession = createCorrectResponseSession;
398
+
399
+ var validatePart = function validatePart() {
400
+ var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
401
+ var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
402
+ var choices = model.choices;
403
+ var _config$minAnswerChoi = config.minAnswerChoices,
404
+ minAnswerChoices = _config$minAnswerChoi === void 0 ? 2 : _config$minAnswerChoi,
405
+ maxAnswerChoices = config.maxAnswerChoices;
406
+ var reversedChoices = (0, _toConsumableArray2["default"])(choices || []).reverse();
407
+ var choicesErrors = {};
408
+ var hasCorrectResponse = false;
409
+ reversedChoices.forEach(function (choice, index) {
410
+ var correct = choice.correct,
411
+ value = choice.value,
412
+ label = choice.label;
413
+
414
+ if (correct) {
415
+ hasCorrectResponse = true;
416
+ }
417
+
418
+ if (label === '' || label === '<div></div>') {
419
+ choicesErrors[value] = 'Content should not be empty.';
420
+ } else {
421
+ var identicalAnswer = reversedChoices.slice(index + 1).some(function (c) {
422
+ return c.label === label;
423
+ });
424
+
425
+ if (identicalAnswer) {
426
+ choicesErrors[value] = 'Content should be unique.';
427
+ }
428
+ }
429
+ });
430
+ var errors = {};
431
+ var nbOfChoices = (choices || []).length;
432
+
433
+ if (nbOfChoices < minAnswerChoices) {
434
+ errors.answerChoicesError = "There should be at least ".concat(minAnswerChoices, " choices defined.");
435
+ } else if (nbOfChoices > maxAnswerChoices) {
436
+ errors.answerChoicesError = "No more than ".concat(maxAnswerChoices, " choices should be defined.");
437
+ }
438
+
439
+ if (!hasCorrectResponse) {
440
+ errors.correctResponseError = 'No correct response defined.';
441
+ }
442
+
443
+ if (!(0, _isEmpty["default"])(choicesErrors)) {
444
+ errors.choicesErrors = choicesErrors;
445
+ }
446
+
447
+ return errors;
448
+ };
449
+
450
+ var validate = function validate() {
451
+ var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
452
+ var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
453
+
454
+ var _ref6 = model || {},
455
+ partA = _ref6.partA,
456
+ partB = _ref6.partB;
457
+
458
+ var _ref7 = config || {},
459
+ partAConfig = _ref7.partA,
460
+ partBConfig = _ref7.partB;
461
+
462
+ var partAErrors = validatePart(partA, partAConfig);
463
+ var partBErrors = validatePart(partB, partBConfig);
464
+ return {
465
+ partA: partAErrors,
466
+ partB: partBErrors
467
+ };
468
+ };
469
+
470
+ exports.validate = validate;
381
471
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"names":["prepareChoice","model","env","defaultFeedback","choice","out","label","value","role","mode","rationale","rationaleEnabled","correct","feedbackEnabled","feedbackType","feedback","type","parsePart","part","key","session","Object","assign","incorrect","choices","map","disabled","complete","min","filter","c","length","responseCorrect","undefined","normalize","question","partLabels","partLabelType","partA","defaults","promptEnabled","teacherInstructionsEnabled","studentInstructionsEnabled","verticalMode","partB","updateSession","normalizedQuestion","shuffledValues","us","id","element","update","Promise","resolve","partASession","partALockChoiceOrder","partAChoices","partBChoices","partBSession","partBLockChoiceOrder","e","console","error","partLabel","teacherInstructions","prompt","createDefaultModel","isCorrect","getScore","config","sessionPart","maxScore","sessionPartValue","chosen","find","v","correctAndNotChosen","incorrectAndChosen","correctChoices","reduce","total","partialScoring","parseFloat","toFixed","outcome","score","scoreA","scoreB","empty","max","returnPartCorrect","answers","forEach","i","push","createCorrectResponseSession","partACorrect","partBCorrect"],"mappings":"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","sourcesContent":["import defaults from './defaults';\nimport { lockChoices, getShuffledChoices } from '@pie-lib/controller-utils';\nimport { isResponseCorrect } from './utils';\nimport get from 'lodash/get';\nimport isEmpty from 'lodash/isEmpty';\n\nconst prepareChoice = (model, env, defaultFeedback) => choice => {\n const out = {\n label: choice.label,\n value: choice.value\n };\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n out.rationale = model.rationaleEnabled ? choice.rationale : null;\n } else {\n out.rationale = null;\n }\n\n if (env.mode === 'evaluate') {\n out.correct = !!choice.correct;\n\n if (model.feedbackEnabled) {\n const feedbackType = (choice.feedback && choice.feedback.type) || 'none';\n\n if (feedbackType === 'default') {\n out.feedback = defaultFeedback[choice.correct ? 'correct' : 'incorrect'];\n } else if (feedbackType === 'custom') {\n out.feedback = choice.feedback.value;\n }\n }\n }\n\n return out;\n};\n\nconst parsePart = (part, key, session, env) => {\n const defaultFeedback = Object.assign(\n { correct: 'Correct', incorrect: 'Incorrect' },\n part.defaultFeedback\n );\n\n let choices = part.choices\n ? part.choices.map(prepareChoice(part, env, defaultFeedback))\n : [];\n\n return {\n ...part,\n choices,\n disabled: env.mode !== 'gather',\n complete: {\n min: part.choices.filter(c => c.correct).length\n },\n responseCorrect:\n env.mode === 'evaluate'\n ? isResponseCorrect(part, key, session)\n : undefined\n };\n};\n\nexport const normalize = question => ({\n partLabels: true,\n partLabelType: 'Letters',\n ...question,\n partA: {\n ...defaults.partA,\n rationaleEnabled: true,\n feedbackEnabled: true,\n promptEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n verticalMode: true,\n ...question.partA\n },\n partB: {\n ...defaults.partB,\n rationaleEnabled: true,\n promptEnabled: true,\n feedbackEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n verticalMode: true,\n ...question.partB\n }\n});\n\n/**\n *\n * @param {*} question\n * @param {*} session\n * @param {*} env\n * @param {*} updateSession - optional - a function that will set the properties passed into it on the session.\n */\nexport async function model(question, session, env, updateSession) {\n const normalizedQuestion = normalize(question);\n const partA = parsePart(normalizedQuestion.partA, 'partA', session, env);\n const partB = parsePart(normalizedQuestion.partB, 'partB', session, env);\n\n const shuffledValues = {};\n\n const us = part => (id, element, update) =>\n new Promise(resolve => {\n shuffledValues[part] = update.shuffledValues;\n resolve();\n });\n\n const partASession = get(session, 'value.partA');\n const partALockChoiceOrder = lockChoices(normalizedQuestion.partA, partASession, env);\n\n const { choices: partAChoices } = partA || {};\n const { choices: partBChoices } = partB || {};\n\n if (!partALockChoiceOrder && partAChoices && partAChoices.length) {\n partA.choices = await getShuffledChoices(\n partAChoices,\n { shuffledValues: (session.shuffledValues || {}).partA },\n us('partA'),\n 'value'\n );\n }\n\n const partBSession = get(session, 'value.partB');\n const partBLockChoiceOrder = lockChoices(normalizedQuestion.partB, partBSession, env);\n\n if (!partBLockChoiceOrder && partBChoices && partBChoices.length) {\n partB.choices = await getShuffledChoices(\n partBChoices,\n { shuffledValues: (session.shuffledValues || {}).partB },\n us('partB'),\n 'value'\n );\n }\n\n if (!isEmpty(shuffledValues)) {\n if (updateSession && typeof updateSession === 'function') {\n updateSession(session.id, session.element, {\n shuffledValues\n }).catch(e => {\n console.error('update session failed', e);\n });\n }\n }\n\n if (normalizedQuestion.partLabels) {\n partA.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part A' : 'Part 1';\n partB.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part B' : 'Part 2';\n } else {\n partA.partLabel = undefined;\n partB.partLabel = undefined;\n }\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n partA.teacherInstructions = normalizedQuestion.partA\n .teacherInstructionsEnabled\n ? normalizedQuestion.partA.teacherInstructions\n : null;\n partB.teacherInstructions = normalizedQuestion.partB\n .teacherInstructionsEnabled\n ? normalizedQuestion.partB.teacherInstructions\n : null;\n } else {\n partA.teacherInstructions = null;\n partB.teacherInstructions = null;\n }\n\n partA.prompt = normalizedQuestion.partA.promptEnabled\n ? normalizedQuestion.partA.prompt\n : null;\n partB.prompt = normalizedQuestion.partB.promptEnabled\n ? normalizedQuestion.partB.prompt\n : null;\n\n return new Promise(resolve => {\n resolve({\n disabled: env.mode !== 'gather',\n mode: env.mode,\n partA,\n partB\n });\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise(resolve => {\n resolve({\n ...defaults,\n ...model\n });\n });\n\nconst isCorrect = c => c.correct === true;\n\nconst getScore = (config, sessionPart, key) => {\n const { choices = [] } = (config && config[key]) || {};\n const maxScore = choices.length;\n const { value: sessionPartValue } = sessionPart || {};\n\n const chosen = c => !!(sessionPartValue || []).find(v => v === c.value);\n const correctAndNotChosen = c => isCorrect(c) && !chosen(c);\n const incorrectAndChosen = c => !isCorrect(c) && chosen(c);\n const correctChoices = choices.reduce((total, choice) => {\n if (correctAndNotChosen(choice) || incorrectAndChosen(choice)) {\n return total - 1;\n } else {\n return total;\n }\n }, choices.length);\n\n // determine score for a part\n if (!config.partialScoring && correctChoices < maxScore) {\n return 0;\n }\n\n return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);\n};\n\nexport function outcome(config, session) {\n return new Promise(resolve => {\n const { value } = session || {};\n\n if (!session || !value) {\n resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true });\n }\n\n if (value) {\n const { partA, partB } = value || {};\n\n const scoreA = getScore(config, partA, 'partA');\n const scoreB = getScore(config, partB, 'partB');\n\n if (!config.partialScoring) {\n // The EBSR item is worth 1 point\n // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded\n resolve({ score: (scoreA === 1 && scoreB === 1) ? 1 : 0, scoreA, scoreB, max: 1 });\n } else {\n // The EBSR item is worth 2 points\n if (scoreA === 1) {\n if (scoreB === 1) {\n // If Part A and Part B are both correct, 2 points are awarded\n resolve({ score: 2, scoreA, scoreB, max: 2 });\n } else {\n // If Part A is correct and part B is incorrect, 1 point is awarded\n resolve({ score: 1, scoreA, scoreB, max: 2 });\n }\n } else {\n // For all other combinations, no points are awarded\n resolve({ score: 0, scoreA, scoreB, max: 2 });\n }\n }\n }\n });\n}\n\nconst returnPartCorrect = choices => {\n let answers = [];\n\n choices.forEach(i => {\n const { correct, value } = i;\n if (correct) {\n answers.push(value);\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise(resolve => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { partA, partB } = question;\n\n const partACorrect = returnPartCorrect(partA.choices);\n const partBCorrect = returnPartCorrect(partB.choices);\n\n resolve({\n value: {\n partA: {\n id: 'partA',\n value: partACorrect\n },\n partB: {\n id: 'partB',\n value: partBCorrect\n }\n },\n id: '1'\n });\n } else {\n resolve(null);\n }\n });\n};\n"],"file":"index.js"}
1
+ {"version":3,"sources":["../src/index.js"],"names":["prepareChoice","model","env","defaultFeedback","choice","out","label","value","role","mode","rationale","rationaleEnabled","correct","feedbackEnabled","feedbackType","feedback","type","parsePart","part","key","session","Object","assign","incorrect","choices","map","disabled","complete","min","filter","c","length","responseCorrect","undefined","normalize","partA","partB","question","partLabels","partLabelType","defaults","promptEnabled","teacherInstructionsEnabled","studentInstructionsEnabled","gridColumns","choicesLayout","verticalMode","updateSession","normalizedQuestion","shuffledValues","us","id","element","update","Promise","resolve","partASession","partALockChoiceOrder","partAChoices","partBChoices","partBSession","partBLockChoiceOrder","e","console","error","partLabel","teacherInstructions","prompt","createDefaultModel","isCorrect","getScore","config","sessionPart","maxScore","sessionPartValue","chosen","find","v","correctAndNotChosen","incorrectAndChosen","correctChoices","reduce","total","partialScoring","parseFloat","toFixed","outcome","score","scoreA","scoreB","empty","max","returnPartCorrect","answers","forEach","i","push","createCorrectResponseSession","partACorrect","partBCorrect","validatePart","minAnswerChoices","maxAnswerChoices","reversedChoices","reverse","choicesErrors","hasCorrectResponse","index","identicalAnswer","slice","some","errors","nbOfChoices","answerChoicesError","correctResponseError","validate","partAConfig","partBConfig","partAErrors","partBErrors"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;;;;;;;AAEA,IAAMA,aAAa,GAAG,SAAhBA,aAAgB,CAACC,KAAD,EAAQC,GAAR,EAAaC,eAAb;AAAA,SAAiC,UAAAC,MAAM,EAAI;AAC/D,QAAMC,GAAG,GAAG;AACVC,MAAAA,KAAK,EAAEF,MAAM,CAACE,KADJ;AAEVC,MAAAA,KAAK,EAAEH,MAAM,CAACG;AAFJ,KAAZ;;AAKA,QACEL,GAAG,CAACM,IAAJ,KAAa,YAAb,KACCN,GAAG,CAACO,IAAJ,KAAa,MAAb,IAAuBP,GAAG,CAACO,IAAJ,KAAa,UADrC,CADF,EAGE;AACAJ,MAAAA,GAAG,CAACK,SAAJ,GAAgBT,KAAK,CAACU,gBAAN,GAAyBP,MAAM,CAACM,SAAhC,GAA4C,IAA5D;AACD,KALD,MAKO;AACLL,MAAAA,GAAG,CAACK,SAAJ,GAAgB,IAAhB;AACD;;AAED,QAAIR,GAAG,CAACO,IAAJ,KAAa,UAAjB,EAA6B;AAC3BJ,MAAAA,GAAG,CAACO,OAAJ,GAAc,CAAC,CAACR,MAAM,CAACQ,OAAvB;;AAEA,UAAIX,KAAK,CAACY,eAAV,EAA2B;AACzB,YAAMC,YAAY,GAAIV,MAAM,CAACW,QAAP,IAAmBX,MAAM,CAACW,QAAP,CAAgBC,IAApC,IAA6C,MAAlE;;AAEA,YAAIF,YAAY,KAAK,SAArB,EAAgC;AAC9BT,UAAAA,GAAG,CAACU,QAAJ,GAAeZ,eAAe,CAACC,MAAM,CAACQ,OAAP,GAAiB,SAAjB,GAA6B,WAA9B,CAA9B;AACD,SAFD,MAEO,IAAIE,YAAY,KAAK,QAArB,EAA+B;AACpCT,UAAAA,GAAG,CAACU,QAAJ,GAAeX,MAAM,CAACW,QAAP,CAAgBR,KAA/B;AACD;AACF;AACF;;AAED,WAAOF,GAAP;AACD,GA9BqB;AAAA,CAAtB;;AAgCA,IAAMY,SAAS,GAAG,SAAZA,SAAY,CAACC,IAAD,EAAOC,GAAP,EAAYC,OAAZ,EAAqBlB,GAArB,EAA6B;AAC7C,MAAMC,eAAe,GAAGkB,MAAM,CAACC,MAAP,CACtB;AAAEV,IAAAA,OAAO,EAAE,SAAX;AAAsBW,IAAAA,SAAS,EAAE;AAAjC,GADsB,EAEtBL,IAAI,CAACf,eAFiB,CAAxB;AAKA,MAAIqB,OAAO,GAAGN,IAAI,CAACM,OAAL,GACVN,IAAI,CAACM,OAAL,CAAaC,GAAb,CAAiBzB,aAAa,CAACkB,IAAD,EAAOhB,GAAP,EAAYC,eAAZ,CAA9B,CADU,GAEV,EAFJ;AAIA,yCACKe,IADL;AAEEM,IAAAA,OAAO,EAAPA,OAFF;AAGEE,IAAAA,QAAQ,EAAExB,GAAG,CAACO,IAAJ,KAAa,QAHzB;AAIEkB,IAAAA,QAAQ,EAAE;AACRC,MAAAA,GAAG,EAAEV,IAAI,CAACM,OAAL,CAAaK,MAAb,CAAoB,UAAAC,CAAC;AAAA,eAAIA,CAAC,CAAClB,OAAN;AAAA,OAArB,EAAoCmB;AADjC,KAJZ;AAOEC,IAAAA,eAAe,EACb9B,GAAG,CAACO,IAAJ,KAAa,UAAb,GACI,8BAAkBS,IAAlB,EAAwBC,GAAxB,EAA6BC,OAA7B,CADJ,GAEIa;AAVR;AAYD,CAtBD;;AAwBO,IAAMC,SAAS,GAAG,SAAZA,SAAY;AAAA,wBAAGC,KAAH;AAAA,MAAGA,KAAH,2BAAW,EAAX;AAAA,wBAAeC,KAAf;AAAA,MAAeA,KAAf,2BAAuB,EAAvB;AAAA,MAA8BC,QAA9B;AAAA;AACvBC,IAAAA,UAAU,EAAE,IADW;AAEvBC,IAAAA,aAAa,EAAE;AAFQ,KAGpBF,QAHoB;AAIvBF,IAAAA,KAAK,gDACAK,qBAASL,KADT;AAEHxB,MAAAA,gBAAgB,EAAE,IAFf;AAGHE,MAAAA,eAAe,EAAE,IAHd;AAIH4B,MAAAA,aAAa,EAAE,IAJZ;AAKHC,MAAAA,0BAA0B,EAAE,IALzB;AAMHC,MAAAA,0BAA0B,EAAE,IANzB;AAOHC,MAAAA,WAAW,EAAE;AAPV,OAQAT,KARA;AASHU,MAAAA,aAAa,EAAEV,KAAK,CAACU,aAAN,IAAwBV,KAAK,CAACW,YAAN,KAAuB,KAAvB,IAAgC,YAAxD,IAAyE;AATrF,MAJkB;AAevBV,IAAAA,KAAK,gDACAI,qBAASJ,KADT;AAEHzB,MAAAA,gBAAgB,EAAE,IAFf;AAGH8B,MAAAA,aAAa,EAAE,IAHZ;AAIH5B,MAAAA,eAAe,EAAE,IAJd;AAKH6B,MAAAA,0BAA0B,EAAE,IALzB;AAMHC,MAAAA,0BAA0B,EAAE,IANzB;AAOHC,MAAAA,WAAW,EAAE;AAPV,OAQAR,KARA;AASHS,MAAAA,aAAa,EAAET,KAAK,CAACS,aAAN,IAAwBT,KAAK,CAACU,YAAN,KAAuB,KAAvB,IAAgC,YAAxD,IAAyE;AATrF;AAfkB;AAAA,CAAlB;AA4BP;AACA;AACA;AACA;AACA;AACA;AACA;;;;;SACsB7C,K;;;;;yFAAf,iBAAqBoC,QAArB,EAA+BjB,OAA/B,EAAwClB,GAAxC,EAA6C6C,aAA7C;AAAA;;AAAA;AAAA;AAAA;AAAA;AACCC,YAAAA,kBADD,GACsBd,SAAS,CAACG,QAAD,CAD/B;AAECF,YAAAA,KAFD,GAESlB,SAAS,CAAC+B,kBAAkB,CAACb,KAApB,EAA2B,OAA3B,EAAoCf,OAApC,EAA6ClB,GAA7C,CAFlB;AAGCkC,YAAAA,KAHD,GAGSnB,SAAS,CAAC+B,kBAAkB,CAACZ,KAApB,EAA2B,OAA3B,EAAoChB,OAApC,EAA6ClB,GAA7C,CAHlB;AAKC+C,YAAAA,cALD,GAKkB,EALlB;;AAOCC,YAAAA,EAPD,GAOM,SAALA,EAAK,CAAAhC,IAAI;AAAA,qBAAI,UAACiC,EAAD,EAAKC,OAAL,EAAcC,MAAd;AAAA,uBACjB,IAAIC,OAAJ,CAAY,UAAAC,OAAO,EAAI;AACrBN,kBAAAA,cAAc,CAAC/B,IAAD,CAAd,GAAuBmC,MAAM,CAACJ,cAA9B;AACAM,kBAAAA,OAAO;AACR,iBAHD,CADiB;AAAA,eAAJ;AAAA,aAPV;;AAaCC,YAAAA,YAbD,GAagB,qBAAIpC,OAAJ,EAAa,aAAb,CAbhB;AAcCqC,YAAAA,oBAdD,GAcwB,kCAAYT,kBAAkB,CAACb,KAA/B,EAAsCqB,YAAtC,EAAoDtD,GAApD,CAdxB;AAAA,oBAgB6BiC,KAAK,IAAI,EAhBtC,EAgBYuB,YAhBZ,SAgBGlC,OAhBH;AAAA,oBAiB6BY,KAAK,IAAI,EAjBtC,EAiBYuB,YAjBZ,SAiBGnC,OAjBH;;AAAA,kBAmBD,CAACiC,oBAAD,IAAyBC,YAAzB,IAAyCA,YAAY,CAAC3B,MAnBrD;AAAA;AAAA;AAAA;;AAAA;AAAA,mBAoBmB,yCACpB2B,YADoB,EAEpB;AAAET,cAAAA,cAAc,EAAE,CAAC7B,OAAO,CAAC6B,cAAR,IAA0B,EAA3B,EAA+Bd;AAAjD,aAFoB,EAGpBe,EAAE,CAAC,OAAD,CAHkB,EAIpB,OAJoB,CApBnB;;AAAA;AAoBHf,YAAAA,KAAK,CAACX,OApBH;;AAAA;AA4BCoC,YAAAA,YA5BD,GA4BgB,qBAAIxC,OAAJ,EAAa,aAAb,CA5BhB;AA6BCyC,YAAAA,oBA7BD,GA6BwB,kCAAYb,kBAAkB,CAACZ,KAA/B,EAAsCwB,YAAtC,EAAoD1D,GAApD,CA7BxB;;AAAA,kBA+BD,CAAC2D,oBAAD,IAAyBF,YAAzB,IAAyCA,YAAY,CAAC5B,MA/BrD;AAAA;AAAA;AAAA;;AAAA;AAAA,mBAgCmB,yCACpB4B,YADoB,EAEpB;AAAEV,cAAAA,cAAc,EAAE,CAAC7B,OAAO,CAAC6B,cAAR,IAA0B,EAA3B,EAA+Bb;AAAjD,aAFoB,EAGpBc,EAAE,CAAC,OAAD,CAHkB,EAIpB,OAJoB,CAhCnB;;AAAA;AAgCHd,YAAAA,KAAK,CAACZ,OAhCH;;AAAA;AAwCL,gBAAI,CAAC,yBAAQyB,cAAR,CAAL,EAA8B;AAC5B,kBAAIF,aAAa,IAAI,OAAOA,aAAP,KAAyB,UAA9C,EAA0D;AACxDA,gBAAAA,aAAa,CAAC3B,OAAO,CAAC+B,EAAT,EAAa/B,OAAO,CAACgC,OAArB,EAA8B;AACzCH,kBAAAA,cAAc,EAAdA;AADyC,iBAA9B,CAAb,UAES,UAAAa,CAAC,EAAI;AACZC,kBAAAA,OAAO,CAACC,KAAR,CAAc,uBAAd,EAAuCF,CAAvC;AACD,iBAJD;AAKD;AACF;;AAED,gBAAId,kBAAkB,CAACV,UAAvB,EAAmC;AACjCH,cAAAA,KAAK,CAAC8B,SAAN,GACEjB,kBAAkB,CAACT,aAAnB,KAAqC,SAArC,GAAiD,QAAjD,GAA4D,QAD9D;AAEAH,cAAAA,KAAK,CAAC6B,SAAN,GACEjB,kBAAkB,CAACT,aAAnB,KAAqC,SAArC,GAAiD,QAAjD,GAA4D,QAD9D;AAED,aALD,MAKO;AACLJ,cAAAA,KAAK,CAAC8B,SAAN,GAAkBhC,SAAlB;AACAG,cAAAA,KAAK,CAAC6B,SAAN,GAAkBhC,SAAlB;AACD;;AAED,gBACE/B,GAAG,CAACM,IAAJ,KAAa,YAAb,KACCN,GAAG,CAACO,IAAJ,KAAa,MAAb,IAAuBP,GAAG,CAACO,IAAJ,KAAa,UADrC,CADF,EAGE;AACA0B,cAAAA,KAAK,CAAC+B,mBAAN,GAA4BlB,kBAAkB,CAACb,KAAnB,CACzBO,0BADyB,GAExBM,kBAAkB,CAACb,KAAnB,CAAyB+B,mBAFD,GAGxB,IAHJ;AAIA9B,cAAAA,KAAK,CAAC8B,mBAAN,GAA4BlB,kBAAkB,CAACZ,KAAnB,CACzBM,0BADyB,GAExBM,kBAAkB,CAACZ,KAAnB,CAAyB8B,mBAFD,GAGxB,IAHJ;AAID,aAZD,MAYO;AACL/B,cAAAA,KAAK,CAAC+B,mBAAN,GAA4B,IAA5B;AACA9B,cAAAA,KAAK,CAAC8B,mBAAN,GAA4B,IAA5B;AACD;;AAED/B,YAAAA,KAAK,CAACgC,MAAN,GAAenB,kBAAkB,CAACb,KAAnB,CAAyBM,aAAzB,GACXO,kBAAkB,CAACb,KAAnB,CAAyBgC,MADd,GAEX,IAFJ;AAGA/B,YAAAA,KAAK,CAAC+B,MAAN,GAAenB,kBAAkB,CAACZ,KAAnB,CAAyBK,aAAzB,GACXO,kBAAkB,CAACZ,KAAnB,CAAyB+B,MADd,GAEX,IAFJ;AAhFK,6CAoFE,IAAIb,OAAJ,CAAY,UAAAC,OAAO,EAAI;AAC5BA,cAAAA,OAAO,CAAC;AACN7B,gBAAAA,QAAQ,EAAExB,GAAG,CAACO,IAAJ,KAAa,QADjB;AAENA,gBAAAA,IAAI,EAAEP,GAAG,CAACO,IAFJ;AAGN0B,gBAAAA,KAAK,EAALA,KAHM;AAINC,gBAAAA,KAAK,EAALA;AAJM,eAAD,CAAP;AAMD,aAPM,CApFF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,G;;;;AA8FA,IAAMgC,kBAAkB,GAAG,SAArBA,kBAAqB;AAAA,MAACnE,KAAD,uEAAS,EAAT;AAAA,SAChC,IAAIqD,OAAJ,CAAY,UAAAC,OAAO,EAAI;AACrBA,IAAAA,OAAO,iCACFf,oBADE,GAEFvC,KAFE,EAAP;AAID,GALD,CADgC;AAAA,CAA3B;;;;AAQP,IAAMoE,SAAS,GAAG,SAAZA,SAAY,CAAAvC,CAAC;AAAA,SAAIA,CAAC,CAAClB,OAAF,KAAc,IAAlB;AAAA,CAAnB;;AAEA,IAAM0D,QAAQ,GAAG,SAAXA,QAAW,CAACC,MAAD,EAASC,WAAT,EAAsBrD,GAAtB,EAA8B;AAC7C,cAA0BoD,MAAM,IAAIA,MAAM,CAACpD,GAAD,CAAjB,IAA2B,EAApD;AAAA,4BAAQK,OAAR;AAAA,MAAQA,OAAR,8BAAkB,EAAlB;;AACA,MAAMiD,QAAQ,GAAGjD,OAAO,CAACO,MAAzB;;AACA,cAAoCyC,WAAW,IAAI,EAAnD;AAAA,MAAeE,gBAAf,SAAQnE,KAAR;;AAEA,MAAMoE,MAAM,GAAG,SAATA,MAAS,CAAA7C,CAAC;AAAA,WAAI,CAAC,CAAC,CAAC4C,gBAAgB,IAAI,EAArB,EAAyBE,IAAzB,CAA8B,UAAAC,CAAC;AAAA,aAAIA,CAAC,KAAK/C,CAAC,CAACvB,KAAZ;AAAA,KAA/B,CAAN;AAAA,GAAhB;;AACA,MAAMuE,mBAAmB,GAAG,SAAtBA,mBAAsB,CAAAhD,CAAC;AAAA,WAAIuC,SAAS,CAACvC,CAAD,CAAT,IAAgB,CAAC6C,MAAM,CAAC7C,CAAD,CAA3B;AAAA,GAA7B;;AACA,MAAMiD,kBAAkB,GAAG,SAArBA,kBAAqB,CAAAjD,CAAC;AAAA,WAAI,CAACuC,SAAS,CAACvC,CAAD,CAAV,IAAiB6C,MAAM,CAAC7C,CAAD,CAA3B;AAAA,GAA5B;;AACA,MAAMkD,cAAc,GAAGxD,OAAO,CAACyD,MAAR,CAAe,UAACC,KAAD,EAAQ9E,MAAR,EAAmB;AACvD,QAAI0E,mBAAmB,CAAC1E,MAAD,CAAnB,IAA+B2E,kBAAkB,CAAC3E,MAAD,CAArD,EAA+D;AAC7D,aAAO8E,KAAK,GAAG,CAAf;AACD,KAFD,MAEO;AACL,aAAOA,KAAP;AACD;AACF,GANsB,EAMpB1D,OAAO,CAACO,MANY,CAAvB,CAR6C,CAgB7C;;AACA,MAAI,CAACwC,MAAM,CAACY,cAAR,IAA0BH,cAAc,GAAGP,QAA/C,EAAyD;AACvD,WAAO,CAAP;AACD;;AAED,SAAOW,UAAU,CAACX,QAAQ,GAAG,CAACO,cAAc,GAAGP,QAAlB,EAA4BY,OAA5B,CAAoC,CAApC,CAAH,GAA4C,CAArD,CAAjB;AACD,CAtBD;;AAwBO,SAASC,OAAT,CAAiBf,MAAjB,EAAyBnD,OAAzB,EAAkC;AACvC,SAAO,IAAIkC,OAAJ,CAAY,UAAAC,OAAO,EAAI;AAC5B,gBAAkBnC,OAAO,IAAI,EAA7B;AAAA,QAAQb,KAAR,SAAQA,KAAR;;AAEA,QAAI,CAACa,OAAD,IAAY,CAACb,KAAjB,EAAwB;AACtBgD,MAAAA,OAAO,CAAC;AAAEgC,QAAAA,KAAK,EAAE,CAAT;AAAYC,QAAAA,MAAM,EAAE,CAApB;AAAuBC,QAAAA,MAAM,EAAE,CAA/B;AAAkCC,QAAAA,KAAK,EAAE;AAAzC,OAAD,CAAP;AACD;;AAED,QAAInF,KAAJ,EAAW;AACT,kBAAyBA,KAAK,IAAI,EAAlC;AAAA,UAAQ4B,KAAR,SAAQA,KAAR;AAAA,UAAeC,KAAf,SAAeA,KAAf;;AAEA,UAAMoD,MAAM,GAAGlB,QAAQ,CAACC,MAAD,EAASpC,KAAT,EAAgB,OAAhB,CAAvB;AACA,UAAMsD,MAAM,GAAGnB,QAAQ,CAACC,MAAD,EAASnC,KAAT,EAAgB,OAAhB,CAAvB;;AAEA,UAAI,CAACmC,MAAM,CAACY,cAAZ,EAA4B;AAC1B;AACA;AACA5B,QAAAA,OAAO,CAAC;AAAEgC,UAAAA,KAAK,EAAGC,MAAM,KAAK,CAAX,IAAgBC,MAAM,KAAK,CAA5B,GAAiC,CAAjC,GAAqC,CAA9C;AAAiDD,UAAAA,MAAM,EAANA,MAAjD;AAAyDC,UAAAA,MAAM,EAANA,MAAzD;AAAiEE,UAAAA,GAAG,EAAE;AAAtE,SAAD,CAAP;AACD,OAJD,MAIO;AACL;AACA,YAAIH,MAAM,KAAK,CAAf,EAAkB;AAChB,cAAIC,MAAM,KAAK,CAAf,EAAkB;AAChB;AACAlC,YAAAA,OAAO,CAAC;AAAEgC,cAAAA,KAAK,EAAE,CAAT;AAAYC,cAAAA,MAAM,EAANA,MAAZ;AAAoBC,cAAAA,MAAM,EAANA,MAApB;AAA4BE,cAAAA,GAAG,EAAE;AAAjC,aAAD,CAAP;AACD,WAHD,MAGO;AACL;AACApC,YAAAA,OAAO,CAAC;AAAEgC,cAAAA,KAAK,EAAE,CAAT;AAAYC,cAAAA,MAAM,EAANA,MAAZ;AAAoBC,cAAAA,MAAM,EAANA,MAApB;AAA4BE,cAAAA,GAAG,EAAE;AAAjC,aAAD,CAAP;AACD;AACF,SARD,MAQO;AACL;AACApC,UAAAA,OAAO,CAAC;AAAEgC,YAAAA,KAAK,EAAE,CAAT;AAAYC,YAAAA,MAAM,EAANA,MAAZ;AAAoBC,YAAAA,MAAM,EAANA,MAApB;AAA4BE,YAAAA,GAAG,EAAE;AAAjC,WAAD,CAAP;AACD;AACF;AACF;AACF,GAjCM,CAAP;AAkCD;;AAED,IAAMC,iBAAiB,GAAG,SAApBA,iBAAoB,CAAApE,OAAO,EAAI;AACnC,MAAIqE,OAAO,GAAG,EAAd;AAEArE,EAAAA,OAAO,CAACsE,OAAR,CAAgB,UAAAC,CAAC,EAAI;AACnB,QAAQnF,OAAR,GAA2BmF,CAA3B,CAAQnF,OAAR;AAAA,QAAiBL,KAAjB,GAA2BwF,CAA3B,CAAiBxF,KAAjB;;AACA,QAAIK,OAAJ,EAAa;AACXiF,MAAAA,OAAO,CAACG,IAAR,CAAazF,KAAb;AACD;AACF,GALD;AAMA,SAAOsF,OAAP;AACD,CAVD;;AAYO,IAAMI,4BAA4B,GAAG,SAA/BA,4BAA+B,CAAC5D,QAAD,EAAWnC,GAAX,EAAmB;AAC7D,SAAO,IAAIoD,OAAJ,CAAY,UAAAC,OAAO,EAAI;AAC5B,QAAIrD,GAAG,CAACO,IAAJ,KAAa,UAAb,IAA2BP,GAAG,CAACM,IAAJ,KAAa,YAA5C,EAA0D;AACxD,UAAQ2B,KAAR,GAAyBE,QAAzB,CAAQF,KAAR;AAAA,UAAeC,KAAf,GAAyBC,QAAzB,CAAeD,KAAf;AAEA,UAAM8D,YAAY,GAAGN,iBAAiB,CAACzD,KAAK,CAACX,OAAP,CAAtC;AACA,UAAM2E,YAAY,GAAGP,iBAAiB,CAACxD,KAAK,CAACZ,OAAP,CAAtC;AAEA+B,MAAAA,OAAO,CAAC;AACNhD,QAAAA,KAAK,EAAE;AACL4B,UAAAA,KAAK,EAAE;AACLgB,YAAAA,EAAE,EAAE,OADC;AAEL5C,YAAAA,KAAK,EAAE2F;AAFF,WADF;AAKL9D,UAAAA,KAAK,EAAE;AACLe,YAAAA,EAAE,EAAE,OADC;AAEL5C,YAAAA,KAAK,EAAE4F;AAFF;AALF,SADD;AAWNhD,QAAAA,EAAE,EAAE;AAXE,OAAD,CAAP;AAaD,KAnBD,MAmBO;AACLI,MAAAA,OAAO,CAAC,IAAD,CAAP;AACD;AACF,GAvBM,CAAP;AAwBD,CAzBM;;;;AA2BP,IAAM6C,YAAY,GAAG,SAAfA,YAAe,GAA6B;AAAA,MAA5BnG,KAA4B,uEAApB,EAAoB;AAAA,MAAhBsE,MAAgB,uEAAP,EAAO;AAChD,MAAQ/C,OAAR,GAAoBvB,KAApB,CAAQuB,OAAR;AACA,8BAAmD+C,MAAnD,CAAQ8B,gBAAR;AAAA,MAAQA,gBAAR,sCAA2B,CAA3B;AAAA,MAA8BC,gBAA9B,GAAmD/B,MAAnD,CAA8B+B,gBAA9B;AACA,MAAMC,eAAe,GAAG,oCAAI/E,OAAO,IAAI,EAAf,EAAmBgF,OAAnB,EAAxB;AACA,MAAMC,aAAa,GAAG,EAAtB;AACA,MAAIC,kBAAkB,GAAG,KAAzB;AAEAH,EAAAA,eAAe,CAACT,OAAhB,CAAwB,UAAC1F,MAAD,EAASuG,KAAT,EAAmB;AACzC,QAAQ/F,OAAR,GAAkCR,MAAlC,CAAQQ,OAAR;AAAA,QAAiBL,KAAjB,GAAkCH,MAAlC,CAAiBG,KAAjB;AAAA,QAAwBD,KAAxB,GAAkCF,MAAlC,CAAwBE,KAAxB;;AAEA,QAAIM,OAAJ,EAAa;AACX8F,MAAAA,kBAAkB,GAAG,IAArB;AACD;;AAED,QAAIpG,KAAK,KAAK,EAAV,IAAgBA,KAAK,KAAK,aAA9B,EAA6C;AAC3CmG,MAAAA,aAAa,CAAClG,KAAD,CAAb,GAAuB,8BAAvB;AACD,KAFD,MAEO;AACL,UAAMqG,eAAe,GAAGL,eAAe,CAACM,KAAhB,CAAsBF,KAAK,GAAG,CAA9B,EAAiCG,IAAjC,CAAsC,UAAAhF,CAAC;AAAA,eAAIA,CAAC,CAACxB,KAAF,KAAYA,KAAhB;AAAA,OAAvC,CAAxB;;AAEA,UAAIsG,eAAJ,EAAqB;AACnBH,QAAAA,aAAa,CAAClG,KAAD,CAAb,GAAuB,2BAAvB;AACD;AACF;AACF,GAhBD;AAkBA,MAAMwG,MAAM,GAAG,EAAf;AACA,MAAMC,WAAW,GAAG,CAACxF,OAAO,IAAI,EAAZ,EAAgBO,MAApC;;AAEA,MAAIiF,WAAW,GAAGX,gBAAlB,EAAoC;AAClCU,IAAAA,MAAM,CAACE,kBAAP,sCAAwDZ,gBAAxD;AACD,GAFD,MAEO,IAAIW,WAAW,GAAGV,gBAAlB,EAAoC;AACzCS,IAAAA,MAAM,CAACE,kBAAP,0BAA4CX,gBAA5C;AACD;;AAED,MAAI,CAACI,kBAAL,EAAyB;AACvBK,IAAAA,MAAM,CAACG,oBAAP,GAA8B,8BAA9B;AACD;;AAED,MAAI,CAAC,yBAAQT,aAAR,CAAL,EAA6B;AAC3BM,IAAAA,MAAM,CAACN,aAAP,GAAuBA,aAAvB;AACD;;AAED,SAAOM,MAAP;AACD,CA3CD;;AA6CO,IAAMI,QAAQ,GAAG,SAAXA,QAAW,GAA6B;AAAA,MAA5BlH,KAA4B,uEAApB,EAAoB;AAAA,MAAhBsE,MAAgB,uEAAP,EAAO;;AACnD,cAAyBtE,KAAK,IAAI,EAAlC;AAAA,MAAQkC,KAAR,SAAQA,KAAR;AAAA,MAAeC,KAAf,SAAeA,KAAf;;AACA,cAAmDmC,MAAM,IAAI,EAA7D;AAAA,MAAe6C,WAAf,SAAQjF,KAAR;AAAA,MAAmCkF,WAAnC,SAA4BjF,KAA5B;;AAEA,MAAMkF,WAAW,GAAGlB,YAAY,CAACjE,KAAD,EAAQiF,WAAR,CAAhC;AACA,MAAMG,WAAW,GAAGnB,YAAY,CAAChE,KAAD,EAAQiF,WAAR,CAAhC;AAEA,SAAO;AAAElF,IAAAA,KAAK,EAAEmF,WAAT;AAAsBlF,IAAAA,KAAK,EAAEmF;AAA7B,GAAP;AACD,CARM","sourcesContent":["import defaults from './defaults';\nimport { lockChoices, getShuffledChoices } from '@pie-lib/controller-utils';\nimport { isResponseCorrect } from './utils';\nimport get from 'lodash/get';\nimport isEmpty from 'lodash/isEmpty';\n\nconst prepareChoice = (model, env, defaultFeedback) => choice => {\n const out = {\n label: choice.label,\n value: choice.value\n };\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n out.rationale = model.rationaleEnabled ? choice.rationale : null;\n } else {\n out.rationale = null;\n }\n\n if (env.mode === 'evaluate') {\n out.correct = !!choice.correct;\n\n if (model.feedbackEnabled) {\n const feedbackType = (choice.feedback && choice.feedback.type) || 'none';\n\n if (feedbackType === 'default') {\n out.feedback = defaultFeedback[choice.correct ? 'correct' : 'incorrect'];\n } else if (feedbackType === 'custom') {\n out.feedback = choice.feedback.value;\n }\n }\n }\n\n return out;\n};\n\nconst parsePart = (part, key, session, env) => {\n const defaultFeedback = Object.assign(\n { correct: 'Correct', incorrect: 'Incorrect' },\n part.defaultFeedback\n );\n\n let choices = part.choices\n ? part.choices.map(prepareChoice(part, env, defaultFeedback))\n : [];\n\n return {\n ...part,\n choices,\n disabled: env.mode !== 'gather',\n complete: {\n min: part.choices.filter(c => c.correct).length\n },\n responseCorrect:\n env.mode === 'evaluate'\n ? isResponseCorrect(part, key, session)\n : undefined\n };\n};\n\nexport const normalize = ({ partA = {}, partB = {}, ...question }) => ({\n partLabels: true,\n partLabelType: 'Letters',\n ...question,\n partA: {\n ...defaults.partA,\n rationaleEnabled: true,\n feedbackEnabled: true,\n promptEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n gridColumns: '2',\n ...partA,\n choicesLayout: partA.choicesLayout || (partA.verticalMode === false && 'horizontal') || 'vertical'\n },\n partB: {\n ...defaults.partB,\n rationaleEnabled: true,\n promptEnabled: true,\n feedbackEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n gridColumns: '2',\n ...partB,\n choicesLayout: partB.choicesLayout || (partB.verticalMode === false && 'horizontal') || 'vertical'\n }\n});\n\n/**\n *\n * @param {*} question\n * @param {*} session\n * @param {*} env\n * @param {*} updateSession - optional - a function that will set the properties passed into it on the session.\n */\nexport async function model(question, session, env, updateSession) {\n const normalizedQuestion = normalize(question);\n const partA = parsePart(normalizedQuestion.partA, 'partA', session, env);\n const partB = parsePart(normalizedQuestion.partB, 'partB', session, env);\n\n const shuffledValues = {};\n\n const us = part => (id, element, update) =>\n new Promise(resolve => {\n shuffledValues[part] = update.shuffledValues;\n resolve();\n });\n\n const partASession = get(session, 'value.partA');\n const partALockChoiceOrder = lockChoices(normalizedQuestion.partA, partASession, env);\n\n const { choices: partAChoices } = partA || {};\n const { choices: partBChoices } = partB || {};\n\n if (!partALockChoiceOrder && partAChoices && partAChoices.length) {\n partA.choices = await getShuffledChoices(\n partAChoices,\n { shuffledValues: (session.shuffledValues || {}).partA },\n us('partA'),\n 'value'\n );\n }\n\n const partBSession = get(session, 'value.partB');\n const partBLockChoiceOrder = lockChoices(normalizedQuestion.partB, partBSession, env);\n\n if (!partBLockChoiceOrder && partBChoices && partBChoices.length) {\n partB.choices = await getShuffledChoices(\n partBChoices,\n { shuffledValues: (session.shuffledValues || {}).partB },\n us('partB'),\n 'value'\n );\n }\n\n if (!isEmpty(shuffledValues)) {\n if (updateSession && typeof updateSession === 'function') {\n updateSession(session.id, session.element, {\n shuffledValues\n }).catch(e => {\n console.error('update session failed', e);\n });\n }\n }\n\n if (normalizedQuestion.partLabels) {\n partA.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part A' : 'Part 1';\n partB.partLabel =\n normalizedQuestion.partLabelType === 'Letters' ? 'Part B' : 'Part 2';\n } else {\n partA.partLabel = undefined;\n partB.partLabel = undefined;\n }\n\n if (\n env.role === 'instructor' &&\n (env.mode === 'view' || env.mode === 'evaluate')\n ) {\n partA.teacherInstructions = normalizedQuestion.partA\n .teacherInstructionsEnabled\n ? normalizedQuestion.partA.teacherInstructions\n : null;\n partB.teacherInstructions = normalizedQuestion.partB\n .teacherInstructionsEnabled\n ? normalizedQuestion.partB.teacherInstructions\n : null;\n } else {\n partA.teacherInstructions = null;\n partB.teacherInstructions = null;\n }\n\n partA.prompt = normalizedQuestion.partA.promptEnabled\n ? normalizedQuestion.partA.prompt\n : null;\n partB.prompt = normalizedQuestion.partB.promptEnabled\n ? normalizedQuestion.partB.prompt\n : null;\n\n return new Promise(resolve => {\n resolve({\n disabled: env.mode !== 'gather',\n mode: env.mode,\n partA,\n partB\n });\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise(resolve => {\n resolve({\n ...defaults,\n ...model\n });\n });\n\nconst isCorrect = c => c.correct === true;\n\nconst getScore = (config, sessionPart, key) => {\n const { choices = [] } = (config && config[key]) || {};\n const maxScore = choices.length;\n const { value: sessionPartValue } = sessionPart || {};\n\n const chosen = c => !!(sessionPartValue || []).find(v => v === c.value);\n const correctAndNotChosen = c => isCorrect(c) && !chosen(c);\n const incorrectAndChosen = c => !isCorrect(c) && chosen(c);\n const correctChoices = choices.reduce((total, choice) => {\n if (correctAndNotChosen(choice) || incorrectAndChosen(choice)) {\n return total - 1;\n } else {\n return total;\n }\n }, choices.length);\n\n // determine score for a part\n if (!config.partialScoring && correctChoices < maxScore) {\n return 0;\n }\n\n return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);\n};\n\nexport function outcome(config, session) {\n return new Promise(resolve => {\n const { value } = session || {};\n\n if (!session || !value) {\n resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true });\n }\n\n if (value) {\n const { partA, partB } = value || {};\n\n const scoreA = getScore(config, partA, 'partA');\n const scoreB = getScore(config, partB, 'partB');\n\n if (!config.partialScoring) {\n // The EBSR item is worth 1 point\n // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded\n resolve({ score: (scoreA === 1 && scoreB === 1) ? 1 : 0, scoreA, scoreB, max: 1 });\n } else {\n // The EBSR item is worth 2 points\n if (scoreA === 1) {\n if (scoreB === 1) {\n // If Part A and Part B are both correct, 2 points are awarded\n resolve({ score: 2, scoreA, scoreB, max: 2 });\n } else {\n // If Part A is correct and part B is incorrect, 1 point is awarded\n resolve({ score: 1, scoreA, scoreB, max: 2 });\n }\n } else {\n // For all other combinations, no points are awarded\n resolve({ score: 0, scoreA, scoreB, max: 2 });\n }\n }\n }\n });\n}\n\nconst returnPartCorrect = choices => {\n let answers = [];\n\n choices.forEach(i => {\n const { correct, value } = i;\n if (correct) {\n answers.push(value);\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise(resolve => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { partA, partB } = question;\n\n const partACorrect = returnPartCorrect(partA.choices);\n const partBCorrect = returnPartCorrect(partB.choices);\n\n resolve({\n value: {\n partA: {\n id: 'partA',\n value: partACorrect\n },\n partB: {\n id: 'partB',\n value: partBCorrect\n }\n },\n id: '1'\n });\n } else {\n resolve(null);\n }\n });\n};\n\nconst validatePart = (model = {}, config = {}) => {\n const { choices } = model;\n const { minAnswerChoices = 2, maxAnswerChoices } = config;\n const reversedChoices = [...choices || []].reverse();\n const choicesErrors = {};\n let hasCorrectResponse = false;\n\n reversedChoices.forEach((choice, index) => {\n const { correct, value, label } = choice;\n\n if (correct) {\n hasCorrectResponse = true;\n }\n\n if (label === '' || label === '<div></div>') {\n choicesErrors[value] = 'Content should not be empty.';\n } else {\n const identicalAnswer = reversedChoices.slice(index + 1).some(c => c.label === label);\n\n if (identicalAnswer) {\n choicesErrors[value] = 'Content should be unique.';\n }\n }\n });\n\n const errors = {};\n const nbOfChoices = (choices || []).length;\n\n if (nbOfChoices < minAnswerChoices) {\n errors.answerChoicesError = `There should be at least ${minAnswerChoices} choices defined.`;\n } else if (nbOfChoices > maxAnswerChoices) {\n errors.answerChoicesError = `No more than ${maxAnswerChoices} choices should be defined.`;\n }\n\n if (!hasCorrectResponse) {\n errors.correctResponseError = 'No correct response defined.';\n }\n\n if (!isEmpty(choicesErrors)) {\n errors.choicesErrors = choicesErrors;\n }\n\n return errors;\n};\n\nexport const validate = (model = {}, config = {}) => {\n const { partA, partB } = model || {};\n const { partA: partAConfig, partB: partBConfig } = config || {};\n\n const partAErrors = validatePart(partA, partAConfig);\n const partBErrors = validatePart(partB, partBConfig);\n\n return { partA: partAErrors, partB: partBErrors };\n};\n"],"file":"index.js"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pie-element/ebsr-controller",
3
3
  "private": true,
4
- "version": "5.2.2",
4
+ "version": "6.0.5",
5
5
  "description": "",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -60,7 +60,7 @@ const parsePart = (part, key, session, env) => {
60
60
  };
61
61
  };
62
62
 
63
- export const normalize = question => ({
63
+ export const normalize = ({ partA = {}, partB = {}, ...question }) => ({
64
64
  partLabels: true,
65
65
  partLabelType: 'Letters',
66
66
  ...question,
@@ -71,8 +71,9 @@ export const normalize = question => ({
71
71
  promptEnabled: true,
72
72
  teacherInstructionsEnabled: true,
73
73
  studentInstructionsEnabled: true,
74
- verticalMode: true,
75
- ...question.partA
74
+ gridColumns: '2',
75
+ ...partA,
76
+ choicesLayout: partA.choicesLayout || (partA.verticalMode === false && 'horizontal') || 'vertical'
76
77
  },
77
78
  partB: {
78
79
  ...defaults.partB,
@@ -81,8 +82,9 @@ export const normalize = question => ({
81
82
  feedbackEnabled: true,
82
83
  teacherInstructionsEnabled: true,
83
84
  studentInstructionsEnabled: true,
84
- verticalMode: true,
85
- ...question.partB
85
+ gridColumns: '2',
86
+ ...partB,
87
+ choicesLayout: partB.choicesLayout || (partB.verticalMode === false && 'horizontal') || 'vertical'
86
88
  }
87
89
  });
88
90
 
@@ -296,3 +298,58 @@ export const createCorrectResponseSession = (question, env) => {
296
298
  }
297
299
  });
298
300
  };
301
+
302
+ const validatePart = (model = {}, config = {}) => {
303
+ const { choices } = model;
304
+ const { minAnswerChoices = 2, maxAnswerChoices } = config;
305
+ const reversedChoices = [...choices || []].reverse();
306
+ const choicesErrors = {};
307
+ let hasCorrectResponse = false;
308
+
309
+ reversedChoices.forEach((choice, index) => {
310
+ const { correct, value, label } = choice;
311
+
312
+ if (correct) {
313
+ hasCorrectResponse = true;
314
+ }
315
+
316
+ if (label === '' || label === '<div></div>') {
317
+ choicesErrors[value] = 'Content should not be empty.';
318
+ } else {
319
+ const identicalAnswer = reversedChoices.slice(index + 1).some(c => c.label === label);
320
+
321
+ if (identicalAnswer) {
322
+ choicesErrors[value] = 'Content should be unique.';
323
+ }
324
+ }
325
+ });
326
+
327
+ const errors = {};
328
+ const nbOfChoices = (choices || []).length;
329
+
330
+ if (nbOfChoices < minAnswerChoices) {
331
+ errors.answerChoicesError = `There should be at least ${minAnswerChoices} choices defined.`;
332
+ } else if (nbOfChoices > maxAnswerChoices) {
333
+ errors.answerChoicesError = `No more than ${maxAnswerChoices} choices should be defined.`;
334
+ }
335
+
336
+ if (!hasCorrectResponse) {
337
+ errors.correctResponseError = 'No correct response defined.';
338
+ }
339
+
340
+ if (!isEmpty(choicesErrors)) {
341
+ errors.choicesErrors = choicesErrors;
342
+ }
343
+
344
+ return errors;
345
+ };
346
+
347
+ export const validate = (model = {}, config = {}) => {
348
+ const { partA, partB } = model || {};
349
+ const { partA: partAConfig, partB: partBConfig } = config || {};
350
+
351
+ const partAErrors = validatePart(partA, partAConfig);
352
+ const partBErrors = validatePart(partB, partBConfig);
353
+
354
+ return { partA: partAErrors, partB: partBErrors };
355
+ };