@pie-element/graphing-solution-set 7.0.4-next.20261011174919 → 7.0.4

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.
@@ -50,83 +50,85 @@ var c = /* @__PURE__ */ e(i(), 1), l = {
50
50
  rationaleEnabled: !0,
51
51
  teacherInstructionsEnabled: !0,
52
52
  studentInstructionsEnabled: !0
53
- }, u = (e, t) => o(e.from, t.from) && o(e.to, t.to) || o(e.to, t.from) && o(e.from, t.to), d = (e) => Object.keys(e || {}).sort().reduce((t, n) => (n !== "correctAnswer" && (t[n] = e[n]), t), {}), f = (e) => {
54
- e = {
55
- ...e,
56
- to: { ...e.to },
57
- from: { ...e.from }
58
- };
59
- let t = e.from.x, n = e.from.y, r = e.to.x, i = e.to.y;
53
+ }, u = (e) => ({ ...e }), d = (e, t) => o(e.from, t.from) && o(e.to, t.to) || o(e.to, t.from) && o(e.from, t.to), f = (e) => Object.keys(e || {}).sort().reduce((t, n) => (e && n !== "correctAnswer" && (t[n] = e[n]), t), {}), p = (e) => {
54
+ let t = u(e.from), n = u(e.to), r = t.x, i = t.y, a = n.x, o = n.y;
60
55
  return {
61
- a: i - n,
62
- b: t - r,
63
- c: r * n - t * i
56
+ a: o - i,
57
+ b: r - a,
58
+ c: a * i - r * o
64
59
  };
65
- }, p = (e) => Math.round(e * 1e4) / 1e4, m = (e, t) => {
66
- let { a: n, b: r, c: i } = f(e), { a, b: o, c } = f(t), l = [];
67
- if (a !== 0) l.push(p(n / a));
60
+ }, m = (e) => Math.round(e * 1e4) / 1e4, h = (e, t) => {
61
+ let { a: n, b: r, c: i } = p(e), { a, b: o, c } = p(t), l = [];
62
+ if (a !== 0) l.push(m(n / a));
68
63
  else if (n !== a) return !1;
69
- if (o !== 0) l.push(p(r / o));
64
+ if (o !== 0) l.push(m(r / o));
70
65
  else if (r !== o) return !1;
71
- if (c !== 0) l.push(p(i / c));
66
+ if (c !== 0) l.push(m(i / c));
72
67
  else if (i !== c) return !1;
73
68
  return s(l).length === 1 && e.fill === t.fill;
74
- }, h = (e) => (e || []).map((t, n) => ({
75
- from: t,
76
- to: e[(n + 1) % e.length]
77
- })), g = (e) => (e ||= [], n(e, (e, t) => u(e, t))), _ = (e) => (e ||= [], e.filter((e) => !o(e.from, e.to))), v = (e, n) => {
78
- let { points: r } = e, { points: i } = n, a = h(r), o = h(i), s = g(_(a)), c = g(_(o)), l = t(s, c, u), d = t(c, s, u);
79
- return (!l || !l.length) && (!d || !d.length);
80
- }, y = {
81
- line: (e, t) => m(e, t),
82
- polygon: (e, t) => v(e, t)
83
- }, b = (e) => e && Number.isFinite(e.x) && Number.isFinite(e.y), x = {
84
- point: b,
85
- line: (e) => e && x.point(e.from) && x.point(e.to),
86
- polygon: (e) => e && e.points && e.points.length && (e.points.filter((e) => b(e)) || []).length === e.points.length
87
- }, S = (e) => e ? (e || []).filter(({ type: e, ...t }) => x[e] ? x[e](t) : !1) : [], C = (0, c.default)("@pie-element:graphing-solution-set:controller"), w = () => ({ line: [] }), T = (e, t) => !!(e && t && e.type === t.type && y[e.type] && y[e.type](e, t)), E = ({ sessionAnswers: e, marks: t }) => {
88
- e ||= [], t ||= [];
89
- let n = a(e).reduce((e, n) => (n.correctness = t.find((e) => T(n, e)) ? "correct" : "incorrect", [...e, n]), []), r = a(t).reduce((t, n) => e.find((e) => T(n, e)) ? t : [...t, {
90
- ...n,
69
+ }, g = (e) => {
70
+ let t = e || [];
71
+ return t.map((e, n) => ({
72
+ from: e,
73
+ to: t[(n + 1) % t.length]
74
+ }));
75
+ }, _ = (e) => (e ||= [], n(e, (e, t) => d(e, t))), v = (e) => (e ||= [], e.filter((e) => !o(e.from, e.to))), y = (e, n) => {
76
+ let { points: r } = e, { points: i } = n, a = g(r), o = g(i), s = _(v(a)), c = _(v(o)), l = t(s, c, d), u = t(c, s, d);
77
+ return (!l || !l.length) && (!u || !u.length);
78
+ }, b = {
79
+ line: (e, t) => h(e, t),
80
+ polygon: (e, t) => y(e, t)
81
+ }, x = (e) => e && Number.isFinite(e.x) && Number.isFinite(e.y), S = {
82
+ point: x,
83
+ line: (e) => e && S.point(e.from) && S.point(e.to),
84
+ polygon: (e) => e && e.points && e.points.length && (e.points.filter((e) => x(e)) || []).length === e.points.length
85
+ }, C = (e) => e ? (e || []).filter(({ type: e, ...t }) => S[e] ? S[e](t) : !1) : [], w = (0, c.default)("@pie-element:graphing-solution-set:controller"), T = () => ({ line: [] }), E = (e, t) => !!(e && t && e.type === t.type && b[e.type] && b[e.type](e, t)), D = ({ sessionAnswers: e, marks: t }) => {
86
+ let n = e || [], r = t || [], i = a(n).reduce((e, t) => {
87
+ let n = r.find((e) => E(t, e)) ? "correct" : "incorrect", i = Object.assign(t, { correctness: n });
88
+ return [...e, i];
89
+ }, []), o = a(r).reduce((e, t) => n.find((e) => E(t, e)) ? e : [...e, {
90
+ ...t,
91
91
  correctness: "missing"
92
92
  }], []);
93
- return [...n, ...r];
94
- }, D = (e, t, i = {}) => {
95
- let { answers: o = {}, scoringType: s } = e || {}, { answer: c } = t || {};
93
+ return [...i, ...o];
94
+ }, O = (e, t, i = {}) => {
95
+ let o = e?.answers ?? {}, { answer: s } = t || {};
96
96
  Object.entries(o || {}).forEach(([e, t]) => o[e] = {
97
97
  ...t,
98
98
  marks: t?.marks.filter((e) => !e.building)
99
- }), c ||= [], o = r(o) ? { correctAnswer: w() } : {
99
+ });
100
+ let c = s || [], l;
101
+ l = r(o) ? { correctAnswer: T() } : {
100
102
  correctAnswer: o.correctAnswer,
101
- ...d(o)
103
+ ...f(o)
102
104
  };
103
- let l = n(c, T);
104
- return Object.entries(o).reduce((e, t) => {
105
+ let u = n(c, E);
106
+ return Object.entries(l).reduce((e, t) => {
105
107
  let n = t[0], { marks: r } = t[1] || {};
106
108
  if (!r || !r.length) return e;
107
- let i = E({
108
- sessionAnswers: l,
109
+ let i = D({
110
+ sessionAnswers: u,
109
111
  marks: r
110
112
  }), a = i.filter((e) => e.correctness === "correct"), o = i.filter((e) => e.correctness !== "missing"), s = r.length, c = a.length;
111
113
  return o.length > s && (c -= o.length - s), c < 0 && (c = 0), (c / s > e.bestScore || !e.foundOneSolution) && (e.bestScore = Math.floor(c / s), e.bestScoreAnswerKey = n, e.answersCorrected = i, e.foundOneSolution = !0), e;
112
114
  }, {
113
115
  bestScore: 0,
114
116
  bestScoreAnswerKey: null,
115
- answersCorrected: a(l).map((e) => ({
117
+ answersCorrected: a(u).map((e) => ({
116
118
  ...e,
117
119
  correctness: "incorrect"
118
120
  })),
119
121
  foundOneSolution: !1
120
122
  });
121
- }, O = (e) => ({
123
+ }, k = (e) => ({
122
124
  ...l,
123
125
  ...e
124
126
  });
125
- function k(e, t, n) {
127
+ function A(e, t, n) {
126
128
  return new Promise((i) => {
127
- let a = O(e);
128
- t.answer = S(t.answer);
129
- let { defaultTool: o, extraCSSRules: s, prompt: c, promptEnabled: l, graph: u, answers: d, toolbarTools: f, ...p } = a || {}, { arrows: m } = a, { mode: h, role: g } = n || {};
129
+ let a = k(e);
130
+ t.answer = C(t.answer);
131
+ let { defaultTool: o, extraCSSRules: s, prompt: c, promptEnabled: l, graph: u, answers: d, toolbarTools: f, ...p } = a, { arrows: m } = a, h = n?.mode, g = n?.role;
130
132
  typeof m == "boolean" && (m = m ? {
131
133
  left: !0,
132
134
  right: !0,
@@ -153,27 +155,27 @@ function k(e, t, n) {
153
155
  extraCSSRules: s
154
156
  };
155
157
  if (g === "instructor" && (h === "view" || h === "evaluate")) {
156
- let { rationale: e, rationaleEnabled: t, teacherInstructions: n, teacherInstructionsEnabled: r } = a || {};
158
+ let { rationale: e, rationaleEnabled: t, teacherInstructions: n, teacherInstructionsEnabled: r } = a;
157
159
  _.rationale = t ? e : null, _.teacherInstructions = r ? n : null;
158
160
  }
159
161
  if (h === "evaluate") if (!r(d) && d.correctAnswer && d.correctAnswer.marks && !r(d.correctAnswer.marks)) {
160
- let { answersCorrected: e, bestScoreAnswerKey: r, bestScore: i } = D(a, t, n);
162
+ let { answersCorrected: e, bestScoreAnswerKey: r, bestScore: i } = O(a, t, n);
161
163
  _.answersCorrected = e, _.correctResponse = r ? (d[r] || {}).marks : [], _.showToggle = _.showToggle && i !== 1;
162
164
  } else _.answersCorrected = t && t.answer || [], _.correctResponse = [];
163
- C("base: ", _), i(_);
165
+ w("base: ", _), i(_);
164
166
  });
165
167
  }
166
- function A(e, t, n = {}) {
168
+ function j(e, t, n = {}) {
167
169
  return new Promise((i) => {
168
170
  (!t || r(t)) && i({
169
171
  score: 0,
170
172
  empty: !0
171
173
  }), (n.mode !== "evaluate" || r(e.answers) || e.answers && e.answers.correctAnswer && r(e.answers.correctAnswer.marks)) && i({ score: 0 });
172
- let { bestScore: a } = D(e, t, n);
174
+ let { bestScore: a } = O(e, t, n);
173
175
  i({ score: a });
174
176
  });
175
177
  }
176
- var j = (e, t) => new Promise((n) => {
178
+ var M = (e, t) => new Promise((n) => {
177
179
  if (t.mode !== "evaluate" && t.role === "instructor") {
178
180
  let { answers: t } = e || {}, r = [];
179
181
  t && Object.values(t) && (r = (t.correctAnswer || Object.values(t)[0] || {}).marks || []), n({
@@ -181,13 +183,13 @@ var j = (e, t) => new Promise((n) => {
181
183
  id: "1"
182
184
  });
183
185
  } else n(null);
184
- }), M = (e = {}) => {
186
+ }), N = (e = {}) => {
185
187
  let { answers: t, gssLineData: n } = e, i = {}, a = {}, o = !1;
186
188
  n.numberOfLines === 1 ? t.correctAnswer.marks.length < 1 ? (o = !0, a.correctAnswer = "At least 1 line object should be defined.") : t.correctAnswer.marks.length === 1 && t.correctAnswer.marks[0].building && (o = !0, a.correctAnswer = "1 or more graph object should be correctly defined.") : t.correctAnswer.marks.length < 2 ? (o = !0, a.correctAnswer = "At least 2 line object should be defined.") : t.correctAnswer.marks.length === 2 && (t.correctAnswer.marks[0].building || t.correctAnswer.marks[1].building) && (o = !0, a.correctAnswer = "1 or more graph object should be correctly defined.");
187
189
  let s = t.correctAnswer.marks.find((e) => e.type === "polygon");
188
190
  return !o && (!n.selectedTool === "solutionSet" || !s) && (a.correctAnswer = "Please select a solution set for the graphing solution set item."), r(a) || (i.correctAnswerErrors = a), i;
189
191
  };
190
192
  //#endregion
191
- export { T as compareMarks, j as createCorrectResponseSession, E as getAnswerCorrected, D as getBestAnswer, k as model, O as normalize, A as outcome, M as validate };
193
+ export { E as compareMarks, M as createCorrectResponseSession, D as getAnswerCorrected, O as getBestAnswer, A as model, k as normalize, j as outcome, N as validate };
192
194
 
193
195
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/controller/defaults.ts","../../../../src/controller/utils.ts","../../../../src/controller/index.ts"],"sourcesContent":["// @ts-nocheck\n\n/*\n * This file contains the default configuration for the Graphing Solution Set Item Type.\n * Model is similar to the one used in graphing item type except for the gssLineData object which handles\n * the configuration for the lines and the solution set.\n *\n * Same model is used in configure/src default.js\n * */\nexport default {\n answers: {\n correctAnswer: {\n name: 'Correct Answer',\n marks: [],\n },\n },\n arrows: {\n left: true,\n right: true,\n up: true,\n down: true,\n },\n marks: [],\n defaultGridConfiguration: 0,\n domain: {\n min: -5,\n max: 5,\n step: 1,\n labelStep: 1,\n axisLabel: 'x',\n },\n graph: {\n width: 500,\n height: 500,\n },\n gssLineData: {\n numberOfLines: 1,\n selectedTool: 'lineA',\n sections: [],\n lineA: {\n lineType: 'Solid',\n },\n },\n includeAxes: true,\n labels: {},\n labelsEnabled: true,\n padding: true,\n prompt: '',\n range: {\n min: -5,\n max: 5,\n step: 1,\n labelStep: 1,\n axisLabel: 'y',\n },\n rationale: '',\n standardGrid: false,\n title: '',\n coordinatesOnHover: false,\n promptEnabled: true,\n rationaleEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n};\n","// @ts-nocheck\n\nimport { isEqual, differenceWith, uniq, uniqWith } from '@pie-element/shared-lodash';\n\n/*\n * Constant to check equal segments\n * @param {Object} segment1 - segment 1\n * @param {Object} segment2 - segment 2\n * */\nexport const equalSegment = (segment1, segment2) => {\n // A.from = B.from, A.to = B.to OR A.from = B.to, A.to = B.from\n // x1 = x3 & y1 = y3 & x2 = x4 & y2 = y4\n return (\n (isEqual(segment1.from, segment2.from) && isEqual(segment1.to, segment2.to)) ||\n (isEqual(segment1.to, segment2.from) && isEqual(segment1.from, segment2.to))\n );\n};\n\n// this function is implemented in configure as well\n/*\n * Constant to get sorted answers\n * @param {Object} answers - answers\n * */\nexport const sortedAnswers = (answers) =>\n Object.keys(answers || {})\n .sort()\n .reduce((result, key) => {\n if (key !== 'correctAnswer') {\n result[key] = answers[key];\n }\n return result;\n }, {});\n\n/*\n * Constant to return line equation coefficients\n * @param {Object} line - line\n * */\nconst returnLineEquationCoefficients = (line) => {\n line = { ...line, to: { ...line.to }, from: { ...line.from } };\n const xA = line.from.x;\n const yA = line.from.y;\n const xB = line.to.x;\n const yB = line.to.y;\n return {\n a: yB - yA,\n b: xA - xB,\n c: xB * yA - xA * yB,\n };\n};\n\n/*\n * Constant to get significant decimals\n * @param {Number} number - number\n * */\nconst getSignificantDecimals = (number) => Math.round(number * 10000) / 10000;\n\n/*\n * Constant to check equal lines\n * @param {Object} line1 - line 1\n * @param {Object} line2 - line 2\n * */\nexport const equalLine = (line1, line2) => {\n // line equation: ax + by + c = 0\n // 2 lines are equal if a1/a2 = b1/b2 = c1/c2, where a, b, c are the coefficients in line equation\n // line equation knowing 2 points: (y - yA) / (yB - yA) = (x - xA) / (xB - xA)\n // extending this equation, we get: x * (yB - yA) + y * (xA - xB) + (xB * yA - xA * yB) = 0\n // where a = yB - yA; b = xA - xB; c = xB * yA - xA * yB\n const { a: a1, b: b1, c: c1 } = returnLineEquationCoefficients(line1);\n const { a: a2, b: b2, c: c2 } = returnLineEquationCoefficients(line2);\n const proportions = [];\n if (a2 !== 0) {\n proportions.push(getSignificantDecimals(a1 / a2));\n } else if (a1 !== a2) {\n return false;\n }\n if (b2 !== 0) {\n proportions.push(getSignificantDecimals(b1 / b2));\n } else if (b1 !== b2) {\n return false;\n }\n if (c2 !== 0) {\n proportions.push(getSignificantDecimals(c1 / c2));\n } else if (c1 !== c2) {\n return false;\n }\n return uniq(proportions).length === 1 && line1.fill === line2.fill;\n // (y2 - y1)/(x2 - x1) = (y4 - y3)/(x4 - x3);\n // return ((Math.abs((line1.to.y - line1.from.y) / (line1.to.x - line1.from.x))) === (Math.abs((line2.to.y - line2.from.y) / (line2.to.x - line2.from.x))));\n};\n\n/*\n * Constant to construct segments from points\n * @param {Array} points - points\n * */\nexport const constructSegmentsFromPoints = (points) => {\n // takes the list of points that represent a polygon and transforms it into a list of segments; eg.:\n // points: A, B, C, D => segments: AB, BC, CD, DA\n return (points || []).map((point, index) => ({ from: point, to: points[(index + 1) % points.length] }));\n};\n\n/*\n * Constant to remove duplicate segments\n * @param {Array} segments - segments\n * */\nexport const removeDuplicateSegments = (segments) => {\n segments = segments || [];\n // removes segments that are duplicates; eg. These segments are the same, so one will be removed:\n // segment1: from: { x: 1, y: 1 }, to: { x: 2, y: 1 }\n // segment2: from: { x: 2, y: 1 }, to: { x: 1, y: 1 }\n return uniqWith(segments, (s1, s2) => equalSegment(s1, s2));\n};\n\n/*\n * Constant to remove invalid segments\n * @param {Array} segments - segments\n * */\nexport const removeInvalidSegments = (segments) => {\n segments = segments || [];\n // removes segments that start in a point and end in the same point (eg.: from: { x: 1, y: 1 }, to: { x: 1, y: 1 })\n return segments.filter((segment) => !isEqual(segment.from, segment.to));\n};\n\n/*\n * Constant to check equal polygons\n * @param {Object} poly1 - polygon 1 points\n * @param {Object} poly2 - polygon 2 points\n * */\nexport const equalPolygon = (poly1, poly2) => {\n const { points: points1 } = poly1;\n const { points: points2 } = poly2;\n // generate segments\n const segments1 = constructSegmentsFromPoints(points1);\n const segments2 = constructSegmentsFromPoints(points2);\n const segments1NoDuplicates = removeDuplicateSegments(removeInvalidSegments(segments1));\n const segments2NoDuplicates = removeDuplicateSegments(removeInvalidSegments(segments2));\n const differentSegments1 = differenceWith(segments1NoDuplicates, segments2NoDuplicates, equalSegment);\n const differentSegments2 = differenceWith(segments2NoDuplicates, segments1NoDuplicates, equalSegment);\n return (!differentSegments1 || !differentSegments1.length) && (!differentSegments2 || !differentSegments2.length);\n};\n\n/*\n * Constant to compare equal marks\n * */\nexport const equalMarks = {\n line: (sessAnswer, mark) => equalLine(sessAnswer, mark),\n polygon: (sessAnswer, poly) => equalPolygon(sessAnswer, poly),\n};\n\n/*\n * Check if a point is correct and complete\n * @param {Object} point - point object\n * */\nconst completePoint = (point) => point && Number.isFinite(point.x) && Number.isFinite(point.y);\n\n/*\n * Check if a line is complete\n * @param {Object} item - mark object\n * */\nconst completeFromTo = (item) => item && completeMark.point(item.from) && completeMark.point(item.to);\n\n/*\n * Check if a point is correct and complete\n * @param {Object} item - mark object\n * */\nconst completePoints = (item) =>\n item &&\n item.points &&\n item.points.length &&\n (item.points.filter((point) => completePoint(point)) || []).length === item.points.length;\n\n/*\n * Complete mark object for line and point\n * */\nconst completeMark = {\n point: completePoint,\n line: completeFromTo,\n polygon: completePoints,\n};\n\n/*\n * Function to remove invalid answers\n * @param {Array} answers - answers array\n * */\nexport const removeInvalidAnswers = (answers) =>\n answers\n ? (answers || []).filter(({ type, ...answer }) => (completeMark[type] ? completeMark[type](answer) : false))\n : [];\n","// @ts-nocheck\n\nimport debug from 'debug';\nimport { cloneDeep, isEmpty, uniqWith } from '@pie-element/shared-lodash';\nimport defaults from './defaults.js';\nimport { equalMarks, sortedAnswers, removeInvalidAnswers } from './utils.js';\n\nconst log = debug('@pie-element:graphing-solution-set:controller');\n\nconst initializeGraphMap = () => ({\n line: [],\n});\n\n/*\n * Function to compare two marks\n * @param {Object} mark1 - first mark\n * @param {Object} mark2 - second mark\n * */\nexport const compareMarks = (mark1, mark2) => {\n // marks can be compared with equalMarks[type] function only if they have the same type;\n // if type is different, they are clearly not equal\n return !!(\n mark1 &&\n mark2 &&\n mark1.type === mark2.type &&\n equalMarks[mark1.type] &&\n equalMarks[mark1.type](mark1, mark2)\n );\n};\n\n/*\n * Function to get the corrected answer\n * @param {Object} sessionAnswers - array of marks from session\n * @param {Object} marks - array of marks from correct answer\n * */\nexport const getAnswerCorrected = ({ sessionAnswers, marks: correctAnswers }) => {\n sessionAnswers = sessionAnswers || [];\n correctAnswers = correctAnswers || [];\n const rez = cloneDeep(sessionAnswers).reduce((correctedAnswer, answer) => {\n const answerIsCorrect = correctAnswers.find((mark) => compareMarks(answer, mark));\n answer.correctness = answerIsCorrect ? 'correct' : 'incorrect';\n return [...correctedAnswer, answer];\n }, []);\n // add missing objects from correct answer\n const missingAnswers = cloneDeep(correctAnswers).reduce((correctedAnswer, answer) => {\n const answerIndex = sessionAnswers.find((mark) => compareMarks(answer, mark));\n if (!answerIndex) {\n // means that corrected answer is missing from session, so we mark it as missing object\n return [...correctedAnswer, { ...answer, correctness: 'missing' }];\n }\n return correctedAnswer;\n }, []);\n return [...rez, ...missingAnswers];\n};\n\n/*\n * Function to get the best answer\n * @param {Object} question - question object\n * @param {Object} session - session object\n * @param {Object} env - env object\n * */\nexport const getBestAnswer = (question, session, env = {}) => {\n // questionPossibleAnswers contains all possible answers (correct response and alternates);\n let { answers: questionPossibleAnswers = {}, scoringType } = question || {};\n let { answer } = session || {};\n // filter the incomplete objects\n Object.entries(questionPossibleAnswers || {}).forEach(\n ([key, value]) =>\n (questionPossibleAnswers[key] = { ...value, marks: value?.marks.filter((mark) => !mark.building) }),\n );\n // initialize answer if no values\n answer = answer || [];\n // initialize one possible answer if no values\n if (isEmpty(questionPossibleAnswers)) {\n questionPossibleAnswers = { correctAnswer: initializeGraphMap() };\n } else {\n questionPossibleAnswers = {\n correctAnswer: questionPossibleAnswers.correctAnswer,\n ...sortedAnswers(questionPossibleAnswers),\n };\n }\n // student's answers without DUPLICATES\n const sessionAnswers = uniqWith(answer, compareMarks);\n // array of possible answers entries\n const possibleAnswers = Object.entries(questionPossibleAnswers);\n return possibleAnswers.reduce(\n (acc, entry) => {\n // iterating each possible answer (main + alternates)\n const possibleAnswerKey = entry[0];\n const possibleAnswer = entry[1] || {};\n let { marks } = possibleAnswer;\n if (!marks || !marks.length) {\n return acc;\n }\n // returns array of marks, each having 'correctness' property\n const correctedAnswer = getAnswerCorrected({ sessionAnswers, marks });\n const correctMarks = correctedAnswer.filter((answer) => answer.correctness === 'correct');\n // filter out missing objects because they do not affect the calculation of the score\n // only correct and incorrect are needed\n const scoredCorrectedAnswer = correctedAnswer.filter((answer) => answer.correctness !== 'missing');\n const maxScore = marks.length;\n let score = correctMarks.length;\n // if extra placements\n if (scoredCorrectedAnswer.length > maxScore) {\n score -= scoredCorrectedAnswer.length - maxScore;\n }\n if (score < 0) {\n score = 0;\n }\n if (score / maxScore > acc.bestScore || !acc.foundOneSolution) {\n acc.bestScore = Math.floor(score / maxScore);\n acc.bestScoreAnswerKey = possibleAnswerKey;\n acc.answersCorrected = correctedAnswer;\n acc.foundOneSolution = true;\n }\n return acc;\n },\n {\n bestScore: 0,\n bestScoreAnswerKey: null,\n // initially we just suppose all the answers are incorrect\n answersCorrected: cloneDeep(sessionAnswers).map((answer) => ({ ...answer, correctness: 'incorrect' })),\n foundOneSolution: false,\n },\n );\n};\n\n/*\n * Constant normalize\n * @param {Object} question - question object\n * */\nexport const normalize = (question) => ({ ...defaults, ...question });\n\n/*\n * Function to set model\n * @param {Object} question - question object\n * @param {Object} session - session object\n * @param {Object} env - env object\n * */\nexport function model(question, session, env) {\n return new Promise((resolve) => {\n const normalizedQuestion = normalize(question);\n // ensure removing of invalid answers\n // need this if undo redo was last operation\n session.answer = removeInvalidAnswers(session.answer);\n // console.log('normalizedQuestion', normalizedQuestion);\n const { defaultTool, extraCSSRules, prompt, promptEnabled, graph, answers, toolbarTools, ...questionProps } =\n normalizedQuestion || {};\n let { arrows } = normalizedQuestion;\n const { mode, role } = env || {};\n\n // This is used for offering support for old models which have the property arrows: boolean\n // Same thing is set in authoring : packages/graphing/configure/src/configure.jsx - componentDidMount\n if (typeof arrows === 'boolean') {\n if (arrows) {\n arrows = {\n left: true,\n right: true,\n up: true,\n down: true,\n };\n } else {\n arrows = {\n left: false,\n right: false,\n up: false,\n down: false,\n };\n }\n }\n\n const base = {\n ...questionProps,\n answers,\n arrows,\n defaultTool: 'line',\n disabled: env.mode !== 'gather',\n prompt: promptEnabled ? prompt : null,\n rationale: null,\n size: graph,\n showToggle:\n env.mode === 'evaluate' &&\n !isEmpty(answers) &&\n answers.correctAnswer &&\n answers.correctAnswer.marks &&\n !isEmpty(answers.correctAnswer.marks),\n teacherInstructions: null,\n toolbarTools,\n extraCSSRules,\n };\n\n if (role === 'instructor' && (mode === 'view' || mode === 'evaluate')) {\n const { rationale, rationaleEnabled, teacherInstructions, teacherInstructionsEnabled } = normalizedQuestion || {};\n\n base.rationale = rationaleEnabled ? rationale : null;\n base.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;\n }\n\n if (mode === 'evaluate') {\n if (\n !isEmpty(answers) &&\n answers.correctAnswer &&\n answers.correctAnswer.marks &&\n !isEmpty(answers.correctAnswer.marks)\n ) {\n const { answersCorrected, bestScoreAnswerKey, bestScore } = getBestAnswer(normalizedQuestion, session, env);\n // array of marks from session with 'correctness' property set\n base.answersCorrected = answersCorrected;\n base.correctResponse = bestScoreAnswerKey ? (answers[bestScoreAnswerKey] || {}).marks : [];\n base.showToggle = base.showToggle && bestScore !== 1;\n } else {\n base.answersCorrected = (session && session.answer) || [];\n base.correctResponse = [];\n }\n }\n\n log('base: ', base);\n resolve(base);\n });\n}\n\n/*\n * Function to check the outcome\n * @param {Object} question - question object\n * @param {Object} session - session object\n * @param {Object} env - env object\n * */\nexport function outcome(question, session, env = {}) {\n return new Promise((resolve) => {\n if (!session || isEmpty(session)) {\n resolve({ score: 0, empty: true });\n }\n if (\n env.mode !== 'evaluate' ||\n isEmpty(question.answers) ||\n (question.answers && question.answers.correctAnswer && isEmpty(question.answers.correctAnswer.marks))\n ) {\n resolve({ score: 0 });\n }\n const { bestScore } = getBestAnswer(question, session, env);\n resolve({ score: bestScore });\n });\n}\n\n/*\n * Constant to create correct response session\n * @param {Object} question - question object\n * @param {Object} env - env object\n * */\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { answers } = question || {};\n let marks = [];\n if (answers && Object.values(answers)) {\n const correctAnswer = answers.correctAnswer || Object.values(answers)[0] || {};\n marks = correctAnswer.marks || [];\n }\n resolve({\n answer: marks,\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n\n/*\n * Constant to validate model before saving item\n * @param {Object} model - model object\n * */\nexport const validate = (model = {}) => {\n const { answers, gssLineData } = model;\n const errors = {};\n const correctAnswerErrors = {};\n let found = false;\n if (gssLineData.numberOfLines === 1) {\n if (answers.correctAnswer.marks.length < 1) {\n found = true;\n correctAnswerErrors.correctAnswer = 'At least 1 line object should be defined.';\n } else if (answers.correctAnswer.marks.length === 1 && answers.correctAnswer.marks[0].building) {\n found = true;\n correctAnswerErrors.correctAnswer = '1 or more graph object should be correctly defined.';\n }\n } else {\n if (answers.correctAnswer.marks.length < 2) {\n found = true;\n correctAnswerErrors.correctAnswer = 'At least 2 line object should be defined.';\n } else if (answers.correctAnswer.marks.length === 2) {\n if (answers.correctAnswer.marks[0].building || answers.correctAnswer.marks[1].building) {\n found = true;\n correctAnswerErrors.correctAnswer = '1 or more graph object should be correctly defined.';\n }\n }\n }\n let polygon = answers.correctAnswer.marks.find((mark) => mark.type === 'polygon');\n if (!found && (!gssLineData.selectedTool === 'solutionSet' || !polygon)) {\n correctAnswerErrors.correctAnswer = 'Please select a solution set for the graphing solution set item.';\n }\n if (!isEmpty(correctAnswerErrors)) {\n errors.correctAnswerErrors = correctAnswerErrors;\n }\n return errors;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/controller/defaults.ts","../../../../src/controller/utils.ts","../../../../src/controller/index.ts"],"sourcesContent":["import type { GraphingSolutionSetModel, Mark, Point } from '../types.js';\n\n/*\n * This file contains the default configuration for the Graphing Solution Set Item Type.\n * Model is similar to the one used in graphing item type except for the gssLineData object which handles\n * the configuration for the lines and the solution set.\n *\n * Same model is used in configure/src default.js\n * */\nexport default {\n answers: {\n correctAnswer: {\n name: 'Correct Answer',\n marks: [] as Mark[],\n },\n },\n arrows: {\n left: true,\n right: true,\n up: true,\n down: true,\n },\n marks: [] as Mark[],\n defaultGridConfiguration: 0,\n domain: {\n min: -5,\n max: 5,\n step: 1,\n labelStep: 1,\n axisLabel: 'x',\n },\n graph: {\n width: 500,\n height: 500,\n },\n gssLineData: {\n numberOfLines: 1,\n selectedTool: 'lineA',\n sections: [] as Point[][],\n lineA: {\n lineType: 'Solid',\n },\n },\n includeAxes: true,\n labels: {},\n labelsEnabled: true,\n padding: true,\n prompt: '',\n range: {\n min: -5,\n max: 5,\n step: 1,\n labelStep: 1,\n axisLabel: 'y',\n },\n rationale: '',\n standardGrid: false,\n title: '',\n coordinatesOnHover: false,\n promptEnabled: true,\n rationaleEnabled: true,\n teacherInstructionsEnabled: true,\n studentInstructionsEnabled: true,\n} satisfies Omit<GraphingSolutionSetModel, 'id' | 'element'>;\n","import { isEqual, differenceWith, uniq, uniqWith } from '@pie-element/shared-lodash';\nimport type { Mark, MarkPoint, MarkType, Point } from '../types.js';\n\n/** Two endpoints: a line mark, or one side of a polygon. */\ntype Segment = { from?: MarkPoint; to?: MarkPoint; fill?: Mark['fill'] };\n\ntype MarkComparator = (sessAnswer: Mark, mark: Mark) => boolean;\n\n/** Copies a point; a missing point copies to an empty object, whose coordinates read as undefined. */\nconst copyPoint = (point: Partial<Point> | undefined): Point => ({ ...point }) as Point;\n\n/*\n * Constant to check equal segments\n * @param {Object} segment1 - segment 1\n * @param {Object} segment2 - segment 2\n * */\nexport const equalSegment = (segment1: Segment, segment2: Segment) => {\n // A.from = B.from, A.to = B.to OR A.from = B.to, A.to = B.from\n // x1 = x3 & y1 = y3 & x2 = x4 & y2 = y4\n return (\n (isEqual(segment1.from, segment2.from) && isEqual(segment1.to, segment2.to)) ||\n (isEqual(segment1.to, segment2.from) && isEqual(segment1.from, segment2.to))\n );\n};\n\n// this function is implemented in configure as well\n/*\n * Constant to get sorted answers\n * @param {Object} answers - answers\n * */\nexport const sortedAnswers = <T>(answers: Record<string, T> | undefined) =>\n Object.keys(answers || {})\n .sort()\n .reduce<Record<string, T>>((result, key) => {\n if (answers && key !== 'correctAnswer') {\n result[key] = answers[key];\n }\n return result;\n }, {});\n\n/*\n * Constant to return line equation coefficients\n * @param {Object} line - line\n * */\nconst returnLineEquationCoefficients = (line: Segment) => {\n const from = copyPoint(line.from);\n const to = copyPoint(line.to);\n const xA = from.x;\n const yA = from.y;\n const xB = to.x;\n const yB = to.y;\n return {\n a: yB - yA,\n b: xA - xB,\n c: xB * yA - xA * yB,\n };\n};\n\n/*\n * Constant to get significant decimals\n * @param {Number} number - number\n * */\nconst getSignificantDecimals = (number: number) => Math.round(number * 10000) / 10000;\n\n/*\n * Constant to check equal lines\n * @param {Object} line1 - line 1\n * @param {Object} line2 - line 2\n * */\nexport const equalLine = (line1: Segment, line2: Segment) => {\n // line equation: ax + by + c = 0\n // 2 lines are equal if a1/a2 = b1/b2 = c1/c2, where a, b, c are the coefficients in line equation\n // line equation knowing 2 points: (y - yA) / (yB - yA) = (x - xA) / (xB - xA)\n // extending this equation, we get: x * (yB - yA) + y * (xA - xB) + (xB * yA - xA * yB) = 0\n // where a = yB - yA; b = xA - xB; c = xB * yA - xA * yB\n const { a: a1, b: b1, c: c1 } = returnLineEquationCoefficients(line1);\n const { a: a2, b: b2, c: c2 } = returnLineEquationCoefficients(line2);\n const proportions: number[] = [];\n if (a2 !== 0) {\n proportions.push(getSignificantDecimals(a1 / a2));\n } else if (a1 !== a2) {\n return false;\n }\n if (b2 !== 0) {\n proportions.push(getSignificantDecimals(b1 / b2));\n } else if (b1 !== b2) {\n return false;\n }\n if (c2 !== 0) {\n proportions.push(getSignificantDecimals(c1 / c2));\n } else if (c1 !== c2) {\n return false;\n }\n return uniq(proportions).length === 1 && line1.fill === line2.fill;\n // (y2 - y1)/(x2 - x1) = (y4 - y3)/(x4 - x3);\n // return ((Math.abs((line1.to.y - line1.from.y) / (line1.to.x - line1.from.x))) === (Math.abs((line2.to.y - line2.from.y) / (line2.to.x - line2.from.x))));\n};\n\n/*\n * Constant to construct segments from points\n * @param {Array} points - points\n * */\nexport const constructSegmentsFromPoints = (points: MarkPoint[] | undefined): Segment[] => {\n // takes the list of points that represent a polygon and transforms it into a list of segments; eg.:\n // points: A, B, C, D => segments: AB, BC, CD, DA\n const list = points || [];\n return list.map((point, index) => ({ from: point, to: list[(index + 1) % list.length] }));\n};\n\n/*\n * Constant to remove duplicate segments\n * @param {Array} segments - segments\n * */\nexport const removeDuplicateSegments = (segments: Segment[] | undefined) => {\n segments = segments || [];\n // removes segments that are duplicates; eg. These segments are the same, so one will be removed:\n // segment1: from: { x: 1, y: 1 }, to: { x: 2, y: 1 }\n // segment2: from: { x: 2, y: 1 }, to: { x: 1, y: 1 }\n return uniqWith(segments, (s1, s2) => equalSegment(s1, s2));\n};\n\n/*\n * Constant to remove invalid segments\n * @param {Array} segments - segments\n * */\nexport const removeInvalidSegments = (segments: Segment[] | undefined) => {\n segments = segments || [];\n // removes segments that start in a point and end in the same point (eg.: from: { x: 1, y: 1 }, to: { x: 1, y: 1 })\n return segments.filter((segment) => !isEqual(segment.from, segment.to));\n};\n\n/*\n * Constant to check equal polygons\n * @param {Object} poly1 - polygon 1 points\n * @param {Object} poly2 - polygon 2 points\n * */\nexport const equalPolygon = (poly1: Mark, poly2: Mark) => {\n const { points: points1 } = poly1;\n const { points: points2 } = poly2;\n // generate segments\n const segments1 = constructSegmentsFromPoints(points1);\n const segments2 = constructSegmentsFromPoints(points2);\n const segments1NoDuplicates = removeDuplicateSegments(removeInvalidSegments(segments1));\n const segments2NoDuplicates = removeDuplicateSegments(removeInvalidSegments(segments2));\n const differentSegments1 = differenceWith(segments1NoDuplicates, segments2NoDuplicates, equalSegment);\n const differentSegments2 = differenceWith(segments2NoDuplicates, segments1NoDuplicates, equalSegment);\n return (!differentSegments1 || !differentSegments1.length) && (!differentSegments2 || !differentSegments2.length);\n};\n\n/*\n * Constant to compare equal marks\n * */\nexport const equalMarks: Record<MarkType, MarkComparator> = {\n line: (sessAnswer, mark) => equalLine(sessAnswer, mark),\n polygon: (sessAnswer, poly) => equalPolygon(sessAnswer, poly),\n};\n\n/*\n * Check if a point is correct and complete\n * @param {Object} point - point object\n * */\nconst completePoint = (point: Partial<Point> | undefined): boolean | undefined =>\n point && Number.isFinite(point.x) && Number.isFinite(point.y);\n\n/*\n * Check if a line is complete\n * @param {Object} item - mark object\n * */\nconst completeFromTo = (item: Partial<Mark> | undefined): boolean | undefined =>\n item && completeMark.point(item.from) && completeMark.point(item.to);\n\n/*\n * Check if a point is correct and complete\n * @param {Object} item - mark object\n * */\nconst completePoints = (item: Partial<Mark> | undefined): boolean | number | undefined =>\n item &&\n item.points &&\n item.points.length &&\n (item.points.filter((point) => completePoint(point)) || []).length === item.points.length;\n\n/*\n * Complete mark object for line and point\n * */\nconst completeMark = {\n point: completePoint,\n line: completeFromTo,\n polygon: completePoints,\n};\n\n/*\n * Function to remove invalid answers\n * @param {Array} answers - answers array\n * */\nexport const removeInvalidAnswers = (answers: Mark[] | undefined): Mark[] =>\n answers\n ? (answers || []).filter(({ type, ...answer }) => (completeMark[type] ? completeMark[type](answer) : false))\n : [];\n","import debug from 'debug';\nimport { cloneDeep, isEmpty, uniqWith } from '@pie-element/shared-lodash';\nimport type { PieEnvironment } from '@pie-element/shared-types';\nimport defaults from './defaults.js';\nimport { equalMarks, sortedAnswers, removeInvalidAnswers } from './utils.js';\nimport type {\n Answer,\n Arrows,\n Graph,\n GraphingSolutionSetModel,\n GraphingSolutionSetSession,\n Mark,\n} from '../types.js';\n\nconst log = debug('@pie-element:graphing-solution-set:controller');\n\ntype Correctness = 'correct' | 'incorrect' | 'missing';\n\n/** A session mark scored against an answer. */\ntype CorrectedMark = Mark & { correctness: Correctness };\n\n/** An answer as scoring reads it; the placeholder `initializeGraphMap()` holds no marks. */\ntype PossibleAnswer = Partial<Answer>;\n\ntype BestAnswer = {\n bestScore: number;\n bestScoreAnswerKey: string | null;\n answersCorrected: CorrectedMark[];\n foundOneSolution: boolean;\n};\n\n/** The model the delivery view receives. */\ntype GraphingSolutionSetViewModel = Omit<\n GraphingSolutionSetModel,\n 'arrows' | 'graph' | 'prompt' | 'rationale' | 'teacherInstructions'\n> & {\n arrows?: Arrows;\n defaultTool: 'line';\n disabled: boolean;\n prompt?: string | null;\n rationale?: string | null;\n size?: Graph;\n showToggle: boolean;\n teacherInstructions?: string | null;\n /** Not read by the delivery view, which offers the line and polygon tools. */\n toolbarTools?: unknown;\n /** Session marks; in evaluate mode with a correct answer, each carries `correctness` */\n answersCorrected?: Mark[];\n correctResponse?: Mark[];\n};\n\n/** Errors `validate()` reports; `correctAnswerErrors` is keyed by answer key. */\nexport type GraphingSolutionSetValidationErrors = {\n correctAnswerErrors?: Record<string, string>;\n};\n\nconst initializeGraphMap = (): PossibleAnswer & { line: Mark[] } => ({\n line: [],\n});\n\n/*\n * Function to compare two marks\n * @param {Object} mark1 - first mark\n * @param {Object} mark2 - second mark\n * */\nexport const compareMarks = (mark1: Mark | undefined, mark2: Mark | undefined) => {\n // marks can be compared with equalMarks[type] function only if they have the same type;\n // if type is different, they are clearly not equal\n return !!(\n mark1 &&\n mark2 &&\n mark1.type === mark2.type &&\n equalMarks[mark1.type] &&\n equalMarks[mark1.type](mark1, mark2)\n );\n};\n\n/*\n * Function to get the corrected answer\n * @param {Object} sessionAnswers - array of marks from session\n * @param {Object} marks - array of marks from correct answer\n * */\nexport const getAnswerCorrected = ({\n sessionAnswers: sessionAnswersInput,\n marks: correctAnswersInput,\n}: {\n sessionAnswers?: Mark[];\n marks?: Mark[];\n}): CorrectedMark[] => {\n const sessionAnswers = sessionAnswersInput || [];\n const correctAnswers = correctAnswersInput || [];\n const rez = cloneDeep(sessionAnswers).reduce<CorrectedMark[]>((correctedAnswer, sessionMark) => {\n const answerIsCorrect = correctAnswers.find((mark) => compareMarks(sessionMark, mark));\n const correctness: Correctness = answerIsCorrect ? 'correct' : 'incorrect';\n const answer: CorrectedMark = Object.assign(sessionMark, { correctness });\n return [...correctedAnswer, answer];\n }, []);\n // add missing objects from correct answer\n const missingAnswers = cloneDeep(correctAnswers).reduce<CorrectedMark[]>((correctedAnswer, answer) => {\n const answerIndex = sessionAnswers.find((mark) => compareMarks(answer, mark));\n if (!answerIndex) {\n // means that corrected answer is missing from session, so we mark it as missing object\n return [...correctedAnswer, { ...answer, correctness: 'missing' }];\n }\n return correctedAnswer;\n }, []);\n return [...rez, ...missingAnswers];\n};\n\n/*\n * Function to get the best answer\n * @param {Object} question - question object\n * @param {Object} session - session object\n * @param {Object} env - env object\n * */\nexport const getBestAnswer = (\n question: GraphingSolutionSetModel | undefined,\n session: GraphingSolutionSetSession | undefined,\n _env: Partial<PieEnvironment> = {},\n): BestAnswer => {\n // questionAnswers contains all possible answers (correct response and alternates);\n const questionAnswers: Record<string, Answer> = question?.answers ?? {};\n const { answer: sessionAnswer } = session || {};\n // filter the incomplete objects\n Object.entries(questionAnswers || {}).forEach(\n ([key, value]) => (questionAnswers[key] = { ...value, marks: value?.marks.filter((mark) => !mark.building) }),\n );\n // initialize answer if no values\n const answer = sessionAnswer || [];\n let questionPossibleAnswers: Record<string, PossibleAnswer | undefined>;\n // initialize one possible answer if no values\n if (isEmpty(questionAnswers)) {\n questionPossibleAnswers = { correctAnswer: initializeGraphMap() };\n } else {\n questionPossibleAnswers = {\n correctAnswer: questionAnswers.correctAnswer,\n ...sortedAnswers<PossibleAnswer>(questionAnswers),\n };\n }\n // student's answers without DUPLICATES\n const sessionAnswers = uniqWith(answer, compareMarks);\n // array of possible answers entries\n const possibleAnswers = Object.entries(questionPossibleAnswers);\n return possibleAnswers.reduce<BestAnswer>(\n (acc, entry) => {\n // iterating each possible answer (main + alternates)\n const possibleAnswerKey = entry[0];\n const possibleAnswer = entry[1] || {};\n const { marks } = possibleAnswer;\n if (!marks || !marks.length) {\n return acc;\n }\n // returns array of marks, each having 'correctness' property\n const correctedAnswer = getAnswerCorrected({ sessionAnswers, marks });\n const correctMarks = correctedAnswer.filter((answer) => answer.correctness === 'correct');\n // filter out missing objects because they do not affect the calculation of the score\n // only correct and incorrect are needed\n const scoredCorrectedAnswer = correctedAnswer.filter((answer) => answer.correctness !== 'missing');\n const maxScore = marks.length;\n let score = correctMarks.length;\n // if extra placements\n if (scoredCorrectedAnswer.length > maxScore) {\n score -= scoredCorrectedAnswer.length - maxScore;\n }\n if (score < 0) {\n score = 0;\n }\n if (score / maxScore > acc.bestScore || !acc.foundOneSolution) {\n acc.bestScore = Math.floor(score / maxScore);\n acc.bestScoreAnswerKey = possibleAnswerKey;\n acc.answersCorrected = correctedAnswer;\n acc.foundOneSolution = true;\n }\n return acc;\n },\n {\n bestScore: 0,\n bestScoreAnswerKey: null,\n // initially we just suppose all the answers are incorrect\n answersCorrected: cloneDeep(sessionAnswers).map((answer): CorrectedMark => ({ ...answer, correctness: 'incorrect' })),\n foundOneSolution: false,\n },\n );\n};\n\n/*\n * Constant normalize\n * @param {Object} question - question object\n * */\nexport const normalize = (question: GraphingSolutionSetModel): GraphingSolutionSetModel => ({ ...defaults, ...question });\n\n/*\n * Function to set model\n * @param {Object} question - question object\n * @param {Object} session - session object\n * @param {Object} env - env object\n * */\nexport function model(\n question: GraphingSolutionSetModel,\n session: GraphingSolutionSetSession,\n env: PieEnvironment,\n): Promise<GraphingSolutionSetViewModel> {\n return new Promise((resolve) => {\n const normalizedQuestion = normalize(question);\n // ensure removing of invalid answers\n // need this if undo redo was last operation\n session.answer = removeInvalidAnswers(session.answer);\n // console.log('normalizedQuestion', normalizedQuestion);\n // `defaultTool` and `toolbarTools` are not model keys; destructuring keeps them out of `questionProps`.\n const { defaultTool, extraCSSRules, prompt, promptEnabled, graph, answers, toolbarTools, ...questionProps } =\n normalizedQuestion as GraphingSolutionSetModel & { defaultTool?: unknown; toolbarTools?: unknown };\n let { arrows } = normalizedQuestion;\n const mode = env?.mode;\n const role = env?.role;\n\n // This is used for offering support for old models which have the property arrows: boolean\n // Same thing is set in authoring : packages/graphing/configure/src/configure.jsx - componentDidMount\n if (typeof arrows === 'boolean') {\n if (arrows) {\n arrows = {\n left: true,\n right: true,\n up: true,\n down: true,\n };\n } else {\n arrows = {\n left: false,\n right: false,\n up: false,\n down: false,\n };\n }\n }\n\n const base: GraphingSolutionSetViewModel = {\n ...questionProps,\n answers,\n arrows,\n defaultTool: 'line',\n disabled: env.mode !== 'gather',\n prompt: promptEnabled ? prompt : null,\n rationale: null,\n size: graph,\n showToggle:\n env.mode === 'evaluate' &&\n !isEmpty(answers) &&\n answers.correctAnswer &&\n answers.correctAnswer.marks &&\n !isEmpty(answers.correctAnswer.marks),\n teacherInstructions: null,\n toolbarTools,\n extraCSSRules,\n };\n\n if (role === 'instructor' && (mode === 'view' || mode === 'evaluate')) {\n const { rationale, rationaleEnabled, teacherInstructions, teacherInstructionsEnabled } = normalizedQuestion;\n\n base.rationale = rationaleEnabled ? rationale : null;\n base.teacherInstructions = teacherInstructionsEnabled ? teacherInstructions : null;\n }\n\n if (mode === 'evaluate') {\n if (\n !isEmpty(answers) &&\n answers.correctAnswer &&\n answers.correctAnswer.marks &&\n !isEmpty(answers.correctAnswer.marks)\n ) {\n const { answersCorrected, bestScoreAnswerKey, bestScore } = getBestAnswer(normalizedQuestion, session, env);\n // array of marks from session with 'correctness' property set\n base.answersCorrected = answersCorrected;\n base.correctResponse = bestScoreAnswerKey ? (answers[bestScoreAnswerKey] || {}).marks : [];\n base.showToggle = base.showToggle && bestScore !== 1;\n } else {\n base.answersCorrected = (session && session.answer) || [];\n base.correctResponse = [];\n }\n }\n\n log('base: ', base);\n resolve(base);\n });\n}\n\n/*\n * Function to check the outcome\n * @param {Object} question - question object\n * @param {Object} session - session object\n * @param {Object} env - env object\n * */\nexport function outcome(\n question: GraphingSolutionSetModel,\n session: GraphingSolutionSetSession | undefined,\n env: Partial<PieEnvironment> = {},\n) {\n return new Promise<{ score: number; empty?: boolean }>((resolve) => {\n if (!session || isEmpty(session)) {\n resolve({ score: 0, empty: true });\n }\n if (\n env.mode !== 'evaluate' ||\n isEmpty(question.answers) ||\n (question.answers && question.answers.correctAnswer && isEmpty(question.answers.correctAnswer.marks))\n ) {\n resolve({ score: 0 });\n }\n const { bestScore } = getBestAnswer(question, session, env);\n resolve({ score: bestScore });\n });\n}\n\n/*\n * Constant to create correct response session\n * @param {Object} question - question object\n * @param {Object} env - env object\n * */\nexport const createCorrectResponseSession = (question: GraphingSolutionSetModel, env: PieEnvironment) => {\n return new Promise<GraphingSolutionSetSession | null>((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { answers } = question || {};\n let marks: Mark[] = [];\n if (answers && Object.values(answers)) {\n const correctAnswer = answers.correctAnswer || Object.values(answers)[0] || {};\n marks = correctAnswer.marks || [];\n }\n resolve({\n answer: marks,\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n\n/*\n * Constant to validate model before saving item\n * @param {Object} model - model object\n * */\nexport const validate = (model: Partial<GraphingSolutionSetModel> = {}): GraphingSolutionSetValidationErrors => {\n // Read unguarded: validate throws on a model without answers or gssLineData.\n const { answers, gssLineData } = model as Required<Pick<GraphingSolutionSetModel, 'answers' | 'gssLineData'>>;\n const errors: GraphingSolutionSetValidationErrors = {};\n const correctAnswerErrors: Record<string, string> = {};\n let found = false;\n if (gssLineData.numberOfLines === 1) {\n if (answers.correctAnswer.marks.length < 1) {\n found = true;\n correctAnswerErrors.correctAnswer = 'At least 1 line object should be defined.';\n } else if (answers.correctAnswer.marks.length === 1 && answers.correctAnswer.marks[0].building) {\n found = true;\n correctAnswerErrors.correctAnswer = '1 or more graph object should be correctly defined.';\n }\n } else {\n if (answers.correctAnswer.marks.length < 2) {\n found = true;\n correctAnswerErrors.correctAnswer = 'At least 2 line object should be defined.';\n } else if (answers.correctAnswer.marks.length === 2) {\n if (answers.correctAnswer.marks[0].building || answers.correctAnswer.marks[1].building) {\n found = true;\n correctAnswerErrors.correctAnswer = '1 or more graph object should be correctly defined.';\n }\n }\n }\n const polygon = answers.correctAnswer.marks.find((mark) => mark.type === 'polygon');\n // `!selectedTool` is a boolean, so this comparison is always false and the check reduces to `!polygon`.\n if (!found && ((!gssLineData.selectedTool as unknown) === 'solutionSet' || !polygon)) {\n correctAnswerErrors.correctAnswer = 'Please select a solution set for the graphing solution set item.';\n }\n if (!isEmpty(correctAnswerErrors)) {\n errors.correctAnswerErrors = correctAnswerErrors;\n }\n return errors;\n};\n"],"mappings":"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"}
@@ -1,17 +1,18 @@
1
+ import type { Mark, Point } from '../types.js';
1
2
  declare const _default: {
2
3
  answers: {
3
4
  correctAnswer: {
4
5
  name: string;
5
- marks: never[];
6
+ marks: Mark[];
6
7
  };
7
8
  };
8
9
  arrows: {
9
- left: boolean;
10
- right: boolean;
11
- up: boolean;
12
- down: boolean;
10
+ left: true;
11
+ right: true;
12
+ up: true;
13
+ down: true;
13
14
  };
14
- marks: never[];
15
+ marks: Mark[];
15
16
  defaultGridConfiguration: number;
16
17
  domain: {
17
18
  min: number;
@@ -26,16 +27,16 @@ declare const _default: {
26
27
  };
27
28
  gssLineData: {
28
29
  numberOfLines: number;
29
- selectedTool: string;
30
- sections: never[];
30
+ selectedTool: "lineA";
31
+ sections: Point[][];
31
32
  lineA: {
32
- lineType: string;
33
+ lineType: "Solid";
33
34
  };
34
35
  };
35
- includeAxes: boolean;
36
+ includeAxes: true;
36
37
  labels: {};
37
- labelsEnabled: boolean;
38
- padding: boolean;
38
+ labelsEnabled: true;
39
+ padding: true;
39
40
  prompt: string;
40
41
  range: {
41
42
  min: number;
@@ -45,12 +46,12 @@ declare const _default: {
45
46
  axisLabel: string;
46
47
  };
47
48
  rationale: string;
48
- standardGrid: boolean;
49
+ standardGrid: false;
49
50
  title: string;
50
- coordinatesOnHover: boolean;
51
- promptEnabled: boolean;
52
- rationaleEnabled: boolean;
53
- teacherInstructionsEnabled: boolean;
54
- studentInstructionsEnabled: boolean;
51
+ coordinatesOnHover: false;
52
+ promptEnabled: true;
53
+ rationaleEnabled: true;
54
+ teacherInstructionsEnabled: true;
55
+ studentInstructionsEnabled: true;
55
56
  };
56
57
  export default _default;
@@ -1,16 +1,48 @@
1
- export declare const compareMarks: (mark1: any, mark2: any) => boolean;
2
- export declare const getAnswerCorrected: ({ sessionAnswers, marks: correctAnswers }: {
3
- sessionAnswers: any;
4
- marks: any;
5
- }) => any[];
6
- export declare const getBestAnswer: (question: any, session: any, env?: {}) => {
1
+ import type { PieEnvironment } from '@pie-element/shared-types';
2
+ import type { Arrows, Graph, GraphingSolutionSetModel, GraphingSolutionSetSession, Mark } from '../types.js';
3
+ type Correctness = 'correct' | 'incorrect' | 'missing';
4
+ /** A session mark scored against an answer. */
5
+ type CorrectedMark = Mark & {
6
+ correctness: Correctness;
7
+ };
8
+ type BestAnswer = {
7
9
  bestScore: number;
8
- bestScoreAnswerKey: null;
9
- answersCorrected: any[];
10
+ bestScoreAnswerKey: string | null;
11
+ answersCorrected: CorrectedMark[];
10
12
  foundOneSolution: boolean;
11
13
  };
12
- export declare const normalize: (question: any) => any;
13
- export declare function model(question: any, session: any, env: any): Promise<unknown>;
14
- export declare function outcome(question: any, session: any, env?: {}): Promise<unknown>;
15
- export declare const createCorrectResponseSession: (question: any, env: any) => Promise<unknown>;
16
- export declare const validate: (model?: {}) => {};
14
+ /** The model the delivery view receives. */
15
+ type GraphingSolutionSetViewModel = Omit<GraphingSolutionSetModel, 'arrows' | 'graph' | 'prompt' | 'rationale' | 'teacherInstructions'> & {
16
+ arrows?: Arrows;
17
+ defaultTool: 'line';
18
+ disabled: boolean;
19
+ prompt?: string | null;
20
+ rationale?: string | null;
21
+ size?: Graph;
22
+ showToggle: boolean;
23
+ teacherInstructions?: string | null;
24
+ /** Not read by the delivery view, which offers the line and polygon tools. */
25
+ toolbarTools?: unknown;
26
+ /** Session marks; in evaluate mode with a correct answer, each carries `correctness` */
27
+ answersCorrected?: Mark[];
28
+ correctResponse?: Mark[];
29
+ };
30
+ /** Errors `validate()` reports; `correctAnswerErrors` is keyed by answer key. */
31
+ export type GraphingSolutionSetValidationErrors = {
32
+ correctAnswerErrors?: Record<string, string>;
33
+ };
34
+ export declare const compareMarks: (mark1: Mark | undefined, mark2: Mark | undefined) => boolean;
35
+ export declare const getAnswerCorrected: ({ sessionAnswers: sessionAnswersInput, marks: correctAnswersInput, }: {
36
+ sessionAnswers?: Mark[];
37
+ marks?: Mark[];
38
+ }) => CorrectedMark[];
39
+ export declare const getBestAnswer: (question: GraphingSolutionSetModel | undefined, session: GraphingSolutionSetSession | undefined, _env?: Partial<PieEnvironment>) => BestAnswer;
40
+ export declare const normalize: (question: GraphingSolutionSetModel) => GraphingSolutionSetModel;
41
+ export declare function model(question: GraphingSolutionSetModel, session: GraphingSolutionSetSession, env: PieEnvironment): Promise<GraphingSolutionSetViewModel>;
42
+ export declare function outcome(question: GraphingSolutionSetModel, session: GraphingSolutionSetSession | undefined, env?: Partial<PieEnvironment>): Promise<{
43
+ score: number;
44
+ empty?: boolean;
45
+ }>;
46
+ export declare const createCorrectResponseSession: (question: GraphingSolutionSetModel, env: PieEnvironment) => Promise<GraphingSolutionSetSession | null>;
47
+ export declare const validate: (model?: Partial<GraphingSolutionSetModel>) => GraphingSolutionSetValidationErrors;
48
+ export {};
@@ -4,34 +4,38 @@ import i from "debug";
4
4
  import { cloneDeep as a, isEmpty as o, uniqWith as s } from "@pie-element/shared-lodash";
5
5
  //#region src/controller/index.ts
6
6
  var c = i("@pie-element:graphing-solution-set:controller"), l = () => ({ line: [] }), u = (e, n) => !!(e && n && e.type === n.type && t[e.type] && t[e.type](e, n)), d = ({ sessionAnswers: e, marks: t }) => {
7
- e ||= [], t ||= [];
8
- let n = a(e).reduce((e, n) => (n.correctness = t.find((e) => u(n, e)) ? "correct" : "incorrect", [...e, n]), []), r = a(t).reduce((t, n) => e.find((e) => u(n, e)) ? t : [...t, {
9
- ...n,
7
+ let n = e || [], r = t || [], i = a(n).reduce((e, t) => {
8
+ let n = r.find((e) => u(t, e)) ? "correct" : "incorrect", i = Object.assign(t, { correctness: n });
9
+ return [...e, i];
10
+ }, []), o = a(r).reduce((e, t) => n.find((e) => u(t, e)) ? e : [...e, {
11
+ ...t,
10
12
  correctness: "missing"
11
13
  }], []);
12
- return [...n, ...r];
14
+ return [...i, ...o];
13
15
  }, f = (e, t, n = {}) => {
14
- let { answers: i = {}, scoringType: c } = e || {}, { answer: f } = t || {};
16
+ let i = e?.answers ?? {}, { answer: c } = t || {};
15
17
  Object.entries(i || {}).forEach(([e, t]) => i[e] = {
16
18
  ...t,
17
19
  marks: t?.marks.filter((e) => !e.building)
18
- }), f ||= [], i = o(i) ? { correctAnswer: l() } : {
20
+ });
21
+ let f = c || [], p;
22
+ p = o(i) ? { correctAnswer: l() } : {
19
23
  correctAnswer: i.correctAnswer,
20
24
  ...r(i)
21
25
  };
22
- let p = s(f, u);
23
- return Object.entries(i).reduce((e, t) => {
26
+ let m = s(f, u);
27
+ return Object.entries(p).reduce((e, t) => {
24
28
  let n = t[0], { marks: r } = t[1] || {};
25
29
  if (!r || !r.length) return e;
26
30
  let i = d({
27
- sessionAnswers: p,
31
+ sessionAnswers: m,
28
32
  marks: r
29
33
  }), a = i.filter((e) => e.correctness === "correct"), o = i.filter((e) => e.correctness !== "missing"), s = r.length, c = a.length;
30
34
  return o.length > s && (c -= o.length - s), c < 0 && (c = 0), (c / s > e.bestScore || !e.foundOneSolution) && (e.bestScore = Math.floor(c / s), e.bestScoreAnswerKey = n, e.answersCorrected = i, e.foundOneSolution = !0), e;
31
35
  }, {
32
36
  bestScore: 0,
33
37
  bestScoreAnswerKey: null,
34
- answersCorrected: a(p).map((e) => ({
38
+ answersCorrected: a(m).map((e) => ({
35
39
  ...e,
36
40
  correctness: "incorrect"
37
41
  })),
@@ -45,7 +49,7 @@ function m(e, t, r) {
45
49
  return new Promise((i) => {
46
50
  let a = p(e);
47
51
  t.answer = n(t.answer);
48
- let { defaultTool: s, extraCSSRules: l, prompt: u, promptEnabled: d, graph: m, answers: h, toolbarTools: g, ..._ } = a || {}, { arrows: v } = a, { mode: y, role: b } = r || {};
52
+ let { defaultTool: s, extraCSSRules: l, prompt: u, promptEnabled: d, graph: m, answers: h, toolbarTools: g, ..._ } = a, { arrows: v } = a, y = r?.mode, b = r?.role;
49
53
  typeof v == "boolean" && (v = v ? {
50
54
  left: !0,
51
55
  right: !0,
@@ -72,7 +76,7 @@ function m(e, t, r) {
72
76
  extraCSSRules: l
73
77
  };
74
78
  if (b === "instructor" && (y === "view" || y === "evaluate")) {
75
- let { rationale: e, rationaleEnabled: t, teacherInstructions: n, teacherInstructionsEnabled: r } = a || {};
79
+ let { rationale: e, rationaleEnabled: t, teacherInstructions: n, teacherInstructionsEnabled: r } = a;
76
80
  x.rationale = t ? e : null, x.teacherInstructions = r ? n : null;
77
81
  }
78
82
  if (y === "evaluate") if (!o(h) && h.correctAnswer && h.correctAnswer.marks && !o(h.correctAnswer.marks)) {
@@ -1,12 +1,18 @@
1
- export declare const equalSegment: (segment1: any, segment2: any) => boolean;
2
- export declare const sortedAnswers: (answers: any) => {};
3
- export declare const equalLine: (line1: any, line2: any) => boolean;
4
- export declare const constructSegmentsFromPoints: (points: any) => any;
5
- export declare const removeDuplicateSegments: (segments: any) => unknown[];
6
- export declare const removeInvalidSegments: (segments: any) => any;
7
- export declare const equalPolygon: (poly1: any, poly2: any) => boolean;
8
- export declare const equalMarks: {
9
- line: (sessAnswer: any, mark: any) => boolean;
10
- polygon: (sessAnswer: any, poly: any) => boolean;
1
+ import type { Mark, MarkPoint, MarkType } from '../types.js';
2
+ /** Two endpoints: a line mark, or one side of a polygon. */
3
+ type Segment = {
4
+ from?: MarkPoint;
5
+ to?: MarkPoint;
6
+ fill?: Mark['fill'];
11
7
  };
12
- export declare const removeInvalidAnswers: (answers: any) => any;
8
+ type MarkComparator = (sessAnswer: Mark, mark: Mark) => boolean;
9
+ export declare const equalSegment: (segment1: Segment, segment2: Segment) => boolean;
10
+ export declare const sortedAnswers: <T>(answers: Record<string, T> | undefined) => Record<string, T>;
11
+ export declare const equalLine: (line1: Segment, line2: Segment) => boolean;
12
+ export declare const constructSegmentsFromPoints: (points: MarkPoint[] | undefined) => Segment[];
13
+ export declare const removeDuplicateSegments: (segments: Segment[] | undefined) => Segment[];
14
+ export declare const removeInvalidSegments: (segments: Segment[] | undefined) => Segment[];
15
+ export declare const equalPolygon: (poly1: Mark, poly2: Mark) => boolean;
16
+ export declare const equalMarks: Record<MarkType, MarkComparator>;
17
+ export declare const removeInvalidAnswers: (answers: Mark[] | undefined) => Mark[];
18
+ export {};
@@ -1,39 +1,37 @@
1
1
  import { differenceWith as e, isEqual as t, uniq as n, uniqWith as r } from "@pie-element/shared-lodash";
2
2
  //#region src/controller/utils.ts
3
- var i = (e, n) => t(e.from, n.from) && t(e.to, n.to) || t(e.to, n.from) && t(e.from, n.to), a = (e) => Object.keys(e || {}).sort().reduce((t, n) => (n !== "correctAnswer" && (t[n] = e[n]), t), {}), o = (e) => {
4
- e = {
5
- ...e,
6
- to: { ...e.to },
7
- from: { ...e.from }
8
- };
9
- let t = e.from.x, n = e.from.y, r = e.to.x, i = e.to.y;
3
+ var i = (e) => ({ ...e }), a = (e, n) => t(e.from, n.from) && t(e.to, n.to) || t(e.to, n.from) && t(e.from, n.to), o = (e) => Object.keys(e || {}).sort().reduce((t, n) => (e && n !== "correctAnswer" && (t[n] = e[n]), t), {}), s = (e) => {
4
+ let t = i(e.from), n = i(e.to), r = t.x, a = t.y, o = n.x, s = n.y;
10
5
  return {
11
- a: i - n,
12
- b: t - r,
13
- c: r * n - t * i
6
+ a: s - a,
7
+ b: r - o,
8
+ c: o * a - r * s
14
9
  };
15
- }, s = (e) => Math.round(e * 1e4) / 1e4, c = (e, t) => {
16
- let { a: r, b: i, c: a } = o(e), { a: c, b: l, c: u } = o(t), d = [];
17
- if (c !== 0) d.push(s(r / c));
18
- else if (r !== c) return !1;
19
- if (l !== 0) d.push(s(i / l));
10
+ }, c = (e) => Math.round(e * 1e4) / 1e4, l = (e, t) => {
11
+ let { a: r, b: i, c: a } = s(e), { a: o, b: l, c: u } = s(t), d = [];
12
+ if (o !== 0) d.push(c(r / o));
13
+ else if (r !== o) return !1;
14
+ if (l !== 0) d.push(c(i / l));
20
15
  else if (i !== l) return !1;
21
- if (u !== 0) d.push(s(a / u));
16
+ if (u !== 0) d.push(c(a / u));
22
17
  else if (a !== u) return !1;
23
18
  return n(d).length === 1 && e.fill === t.fill;
24
- }, l = (e) => (e || []).map((t, n) => ({
25
- from: t,
26
- to: e[(n + 1) % e.length]
27
- })), u = (e) => (e ||= [], r(e, (e, t) => i(e, t))), d = (e) => (e ||= [], e.filter((e) => !t(e.from, e.to))), f = (t, n) => {
28
- let { points: r } = t, { points: a } = n, o = l(r), s = l(a), c = u(d(o)), f = u(d(s)), p = e(c, f, i), m = e(f, c, i);
19
+ }, u = (e) => {
20
+ let t = e || [];
21
+ return t.map((e, n) => ({
22
+ from: e,
23
+ to: t[(n + 1) % t.length]
24
+ }));
25
+ }, d = (e) => (e ||= [], r(e, (e, t) => a(e, t))), f = (e) => (e ||= [], e.filter((e) => !t(e.from, e.to))), p = (t, n) => {
26
+ let { points: r } = t, { points: i } = n, o = u(r), s = u(i), c = d(f(o)), l = d(f(s)), p = e(c, l, a), m = e(l, c, a);
29
27
  return (!p || !p.length) && (!m || !m.length);
30
- }, p = {
31
- line: (e, t) => c(e, t),
32
- polygon: (e, t) => f(e, t)
33
- }, m = (e) => e && Number.isFinite(e.x) && Number.isFinite(e.y), h = {
34
- point: m,
35
- line: (e) => e && h.point(e.from) && h.point(e.to),
36
- polygon: (e) => e && e.points && e.points.length && (e.points.filter((e) => m(e)) || []).length === e.points.length
37
- }, g = (e) => e ? (e || []).filter(({ type: e, ...t }) => h[e] ? h[e](t) : !1) : [];
28
+ }, m = {
29
+ line: (e, t) => l(e, t),
30
+ polygon: (e, t) => p(e, t)
31
+ }, h = (e) => e && Number.isFinite(e.x) && Number.isFinite(e.y), g = {
32
+ point: h,
33
+ line: (e) => e && g.point(e.from) && g.point(e.to),
34
+ polygon: (e) => e && e.points && e.points.length && (e.points.filter((e) => h(e)) || []).length === e.points.length
35
+ }, _ = (e) => e ? (e || []).filter(({ type: e, ...t }) => g[e] ? g[e](t) : !1) : [];
38
36
  //#endregion
39
- export { l as constructSegmentsFromPoints, c as equalLine, p as equalMarks, f as equalPolygon, i as equalSegment, u as removeDuplicateSegments, g as removeInvalidAnswers, d as removeInvalidSegments, a as sortedAnswers };
37
+ export { u as constructSegmentsFromPoints, l as equalLine, m as equalMarks, p as equalPolygon, a as equalSegment, d as removeDuplicateSegments, _ as removeInvalidAnswers, f as removeInvalidSegments, o as sortedAnswers };
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { default } from './delivery/index.js';
2
+ export type * from './types.js';