@qti-components/processing 1.3.2 → 1.3.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.
Files changed (178) hide show
  1. package/dist/components/index.d.ts +18 -0
  2. package/dist/components/index.js +18 -0
  3. package/dist/components/index.js.map +1 -1
  4. package/dist/components/qti-and/qti-and.d.ts +8 -0
  5. package/dist/components/qti-and/qti-and.js +10 -13
  6. package/dist/components/qti-and/qti-and.js.map +1 -1
  7. package/dist/components/qti-any-n/qti-any-n.d.ts +15 -0
  8. package/dist/components/qti-any-n/qti-any-n.js +60 -0
  9. package/dist/components/qti-any-n/qti-any-n.js.map +1 -0
  10. package/dist/components/qti-basevalue/qti-basevalue.js +0 -1
  11. package/dist/components/qti-basevalue/qti-basevalue.js.map +1 -1
  12. package/dist/components/qti-container-size/qti-container-size.d.ts +5 -5
  13. package/dist/components/qti-container-size/qti-container-size.js +5 -6
  14. package/dist/components/qti-container-size/qti-container-size.js.map +1 -1
  15. package/dist/components/qti-contains/qti-contains.js +0 -1
  16. package/dist/components/qti-contains/qti-contains.js.map +1 -1
  17. package/dist/components/qti-correct/qti-correct.d.ts +8 -0
  18. package/dist/components/qti-correct/qti-correct.js +8 -1
  19. package/dist/components/qti-correct/qti-correct.js.map +1 -1
  20. package/dist/components/qti-default/qti-default.d.ts +5 -5
  21. package/dist/components/qti-default/qti-default.js +5 -6
  22. package/dist/components/qti-default/qti-default.js.map +1 -1
  23. package/dist/components/qti-delete/qti-delete.d.ts +8 -0
  24. package/dist/components/qti-delete/qti-delete.js +8 -1
  25. package/dist/components/qti-delete/qti-delete.js.map +1 -1
  26. package/dist/components/qti-divide/qti-divide.d.ts +13 -0
  27. package/dist/components/qti-divide/qti-divide.js +49 -0
  28. package/dist/components/qti-divide/qti-divide.js.map +1 -0
  29. package/dist/components/qti-duration-gte/qti-duration-gte.d.ts +5 -0
  30. package/dist/components/qti-duration-gte/qti-duration-gte.js +44 -0
  31. package/dist/components/qti-duration-gte/qti-duration-gte.js.map +1 -0
  32. package/dist/components/qti-duration-lt/qti-duration-lt.d.ts +13 -0
  33. package/dist/components/qti-duration-lt/qti-duration-lt.js +52 -0
  34. package/dist/components/qti-duration-lt/qti-duration-lt.js.map +1 -0
  35. package/dist/components/qti-equal/qti-equal.d.ts +9 -0
  36. package/dist/components/qti-equal/qti-equal.js +15 -1
  37. package/dist/components/qti-equal/qti-equal.js.map +1 -1
  38. package/dist/components/qti-equal-rounded/qti-equal-rounded.d.ts +9 -0
  39. package/dist/components/qti-equal-rounded/qti-equal-rounded.js +9 -1
  40. package/dist/components/qti-equal-rounded/qti-equal-rounded.js.map +1 -1
  41. package/dist/components/qti-field-value/qti-field-value.d.ts +8 -0
  42. package/dist/components/qti-field-value/qti-field-value.js +8 -1
  43. package/dist/components/qti-field-value/qti-field-value.js.map +1 -1
  44. package/dist/components/qti-gcd/qti.gcd.js +0 -1
  45. package/dist/components/qti-gcd/qti.gcd.js.map +1 -1
  46. package/dist/components/qti-gt/qti-gt.js +0 -1
  47. package/dist/components/qti-gt/qti-gt.js.map +1 -1
  48. package/dist/components/qti-gte/qti-gte.js +0 -1
  49. package/dist/components/qti-gte/qti-gte.js.map +1 -1
  50. package/dist/components/qti-index/qti-index.d.ts +8 -0
  51. package/dist/components/qti-index/qti-index.js +11 -7
  52. package/dist/components/qti-index/qti-index.js.map +1 -1
  53. package/dist/components/qti-inside/qti-inside.d.ts +7 -0
  54. package/dist/components/qti-inside/qti-inside.js +139 -0
  55. package/dist/components/qti-inside/qti-inside.js.map +1 -0
  56. package/dist/components/qti-integer-divide/qti-integer-divide.d.ts +13 -0
  57. package/dist/components/qti-integer-divide/qti-integer-divide.js +47 -0
  58. package/dist/components/qti-integer-divide/qti-integer-divide.js.map +1 -0
  59. package/dist/components/qti-integer-modulus/qti-integer-modulus.d.ts +13 -0
  60. package/dist/components/qti-integer-modulus/qti-integer-modulus.js +47 -0
  61. package/dist/components/qti-integer-modulus/qti-integer-modulus.js.map +1 -0
  62. package/dist/components/qti-integer-to-float/qti-integer-to-float.d.ts +12 -0
  63. package/dist/components/qti-integer-to-float/qti-integer-to-float.js +37 -0
  64. package/dist/components/qti-integer-to-float/qti-integer-to-float.js.map +1 -0
  65. package/dist/components/qti-is-null/qti-is-null.d.ts +8 -0
  66. package/dist/components/qti-is-null/qti-is-null.js +8 -3
  67. package/dist/components/qti-is-null/qti-is-null.js.map +1 -1
  68. package/dist/components/qti-lcm/qti-lcm.d.ts +5 -0
  69. package/dist/components/qti-lcm/qti-lcm.js +70 -0
  70. package/dist/components/qti-lcm/qti-lcm.js.map +1 -0
  71. package/dist/components/qti-lookup-outcome-value/qti-lookup-outcome-value.js +0 -1
  72. package/dist/components/qti-lookup-outcome-value/qti-lookup-outcome-value.js.map +1 -1
  73. package/dist/components/qti-lt/qti-lt.js +0 -1
  74. package/dist/components/qti-lt/qti-lt.js.map +1 -1
  75. package/dist/components/qti-lte/qti-lte.js +0 -1
  76. package/dist/components/qti-lte/qti-lte.js.map +1 -1
  77. package/dist/components/qti-map-response/qti-map-response.d.ts +8 -0
  78. package/dist/components/qti-map-response/qti-map-response.js +8 -1
  79. package/dist/components/qti-map-response/qti-map-response.js.map +1 -1
  80. package/dist/components/qti-map-response-point/qti-map-response-point.js +0 -1
  81. package/dist/components/qti-map-response-point/qti-map-response-point.js.map +1 -1
  82. package/dist/components/qti-match/qti-match.d.ts +8 -0
  83. package/dist/components/qti-match/qti-match.js +8 -1
  84. package/dist/components/qti-match/qti-match.js.map +1 -1
  85. package/dist/components/qti-math-operator/qti-math-operator.js +0 -1
  86. package/dist/components/qti-math-operator/qti-math-operator.js.map +1 -1
  87. package/dist/components/qti-max/qti-max.d.ts +13 -0
  88. package/dist/components/qti-max/qti-max.js +45 -0
  89. package/dist/components/qti-max/qti-max.js.map +1 -0
  90. package/dist/components/qti-member/qti-member.js +0 -1
  91. package/dist/components/qti-member/qti-member.js.map +1 -1
  92. package/dist/components/qti-min/qti-min.d.ts +13 -0
  93. package/dist/components/qti-min/qti-min.js +45 -0
  94. package/dist/components/qti-min/qti-min.js.map +1 -0
  95. package/dist/components/qti-multiple/qti-multiple.js +0 -1
  96. package/dist/components/qti-multiple/qti-multiple.js.map +1 -1
  97. package/dist/components/qti-not/qti-not.d.ts +8 -0
  98. package/dist/components/qti-not/qti-not.js +8 -1
  99. package/dist/components/qti-not/qti-not.js.map +1 -1
  100. package/dist/components/qti-null/qti-null.js +0 -1
  101. package/dist/components/qti-null/qti-null.js.map +1 -1
  102. package/dist/components/qti-or/qti-or.d.ts +8 -0
  103. package/dist/components/qti-or/qti-or.js +8 -1
  104. package/dist/components/qti-or/qti-or.js.map +1 -1
  105. package/dist/components/qti-ordered/qti-ordered.js +0 -1
  106. package/dist/components/qti-ordered/qti-ordered.js.map +1 -1
  107. package/dist/components/qti-pattern-match/qti-pattern-match.d.ts +13 -0
  108. package/dist/components/qti-pattern-match/qti-pattern-match.js +52 -0
  109. package/dist/components/qti-pattern-match/qti-pattern-match.js.map +1 -0
  110. package/dist/components/qti-power/qti-power.js +0 -1
  111. package/dist/components/qti-power/qti-power.js.map +1 -1
  112. package/dist/components/qti-printed-variable/qti-printed-variable.js +0 -1
  113. package/dist/components/qti-printed-variable/qti-printed-variable.js.map +1 -1
  114. package/dist/components/qti-product/qti-product.d.ts +8 -0
  115. package/dist/components/qti-product/qti-product.js +8 -1
  116. package/dist/components/qti-product/qti-product.js.map +1 -1
  117. package/dist/components/qti-random/qti-random.js +0 -1
  118. package/dist/components/qti-random/qti-random.js.map +1 -1
  119. package/dist/components/qti-random-integer/qti-random-integer.js +0 -1
  120. package/dist/components/qti-random-integer/qti-random-integer.js.map +1 -1
  121. package/dist/components/qti-repeat/qti-repeat.d.ts +15 -0
  122. package/dist/components/qti-repeat/qti-repeat.js +112 -0
  123. package/dist/components/qti-repeat/qti-repeat.js.map +1 -0
  124. package/dist/components/qti-response-condition/qti-response-condition.js +0 -1
  125. package/dist/components/qti-response-condition/qti-response-condition.js.map +1 -1
  126. package/dist/components/qti-response-else/qti-response-else.js +0 -1
  127. package/dist/components/qti-response-else/qti-response-else.js.map +1 -1
  128. package/dist/components/qti-response-else-if/qti-response-else-if.js +0 -1
  129. package/dist/components/qti-response-else-if/qti-response-else-if.js.map +1 -1
  130. package/dist/components/qti-response-if/qti-response-if.js +0 -1
  131. package/dist/components/qti-response-if/qti-response-if.js.map +1 -1
  132. package/dist/components/qti-round/qti-round.d.ts +4 -5
  133. package/dist/components/qti-round/qti-round.js +4 -6
  134. package/dist/components/qti-round/qti-round.js.map +1 -1
  135. package/dist/components/qti-round-to/qti-round-to.js +0 -1
  136. package/dist/components/qti-round-to/qti-round-to.js.map +1 -1
  137. package/dist/components/qti-rule/qti-rule.js +2 -13
  138. package/dist/components/qti-rule/qti-rule.js.map +1 -1
  139. package/dist/components/qti-set-correct-response/qti-set-correct-response.d.ts +24 -0
  140. package/dist/components/qti-set-correct-response/qti-set-correct-response.js +76 -0
  141. package/dist/components/qti-set-correct-response/qti-set-correct-response.js.map +1 -0
  142. package/dist/components/qti-set-outcome-value/qti-set-outcome-value.js +0 -1
  143. package/dist/components/qti-set-outcome-value/qti-set-outcome-value.js.map +1 -1
  144. package/dist/components/qti-set-template-value/qti-set-template-value.d.ts +24 -0
  145. package/dist/components/qti-set-template-value/qti-set-template-value.js +80 -0
  146. package/dist/components/qti-set-template-value/qti-set-template-value.js.map +1 -0
  147. package/dist/components/qti-stats-operator/qti-stats-operator.d.ts +15 -0
  148. package/dist/components/qti-stats-operator/qti-stats-operator.js +77 -0
  149. package/dist/components/qti-stats-operator/qti-stats-operator.js.map +1 -0
  150. package/dist/components/qti-string-match/qti-string-match.js +0 -1
  151. package/dist/components/qti-string-match/qti-string-match.js.map +1 -1
  152. package/dist/components/qti-substring/qti-substring.d.ts +13 -0
  153. package/dist/components/qti-substring/qti-substring.js +53 -0
  154. package/dist/components/qti-substring/qti-substring.js.map +1 -0
  155. package/dist/components/qti-subtract/index.d.ts +1 -1
  156. package/dist/components/qti-subtract/index.js +0 -2
  157. package/dist/components/qti-subtract/index.js.map +1 -1
  158. package/dist/components/qti-subtract/qti-subtract.d.ts +8 -0
  159. package/dist/components/qti-subtract/qti-subtract.js +8 -0
  160. package/dist/components/qti-subtract/qti-subtract.js.map +1 -1
  161. package/dist/components/qti-sum/qti-sum.d.ts +8 -0
  162. package/dist/components/qti-sum/qti-sum.js +8 -1
  163. package/dist/components/qti-sum/qti-sum.js.map +1 -1
  164. package/dist/components/qti-truncate/qti-truncate.d.ts +12 -0
  165. package/dist/components/qti-truncate/qti-truncate.js +37 -0
  166. package/dist/components/qti-truncate/qti-truncate.js.map +1 -0
  167. package/dist/components/qti-variable/qti-variable.js +0 -1
  168. package/dist/components/qti-variable/qti-variable.js.map +1 -1
  169. package/dist/elements.d.ts +254 -0
  170. package/dist/elements.js +130 -0
  171. package/dist/elements.js.map +1 -0
  172. package/dist/index.d.ts +1 -0
  173. package/dist/index.js +1 -0
  174. package/dist/index.js.map +1 -1
  175. package/dist/register.d.ts +1 -0
  176. package/dist/register.js +7 -0
  177. package/dist/register.js.map +1 -0
  178. package/package.json +18 -3
@@ -0,0 +1,139 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { property } from 'lit/decorators.js';
8
+ import { QtiExpression } from '@qti-components/base';
9
+ export class QtiInside extends QtiExpression {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.shape = '';
13
+ this.coords = '';
14
+ }
15
+ getResult() {
16
+ const variables = this.getVariables();
17
+ if (variables.length !== 1) {
18
+ console.error('qti-inside requires exactly one point expression');
19
+ return null;
20
+ }
21
+ const variable = variables[0];
22
+ if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {
23
+ console.error('qti-inside requires single cardinality');
24
+ return null;
25
+ }
26
+ if (variable.value === null || variable.value === undefined) {
27
+ return null;
28
+ }
29
+ if (!this.shape || !this.coords) {
30
+ console.error('qti-inside requires shape and coords attributes');
31
+ return null;
32
+ }
33
+ const point = this.#parsePoint(variable.value.toString());
34
+ const coords = this.#parseCoords(this.coords);
35
+ if (!point || coords.length === 0) {
36
+ return null;
37
+ }
38
+ switch (this.shape.toLowerCase()) {
39
+ case 'circle':
40
+ return this.#isInsideCircle(point, coords);
41
+ case 'rect':
42
+ return this.#isInsideRect(point, coords);
43
+ case 'ellipse':
44
+ return this.#isInsideEllipse(point, coords);
45
+ case 'poly':
46
+ case 'polygon':
47
+ return this.#isInsidePolygon(point, coords);
48
+ default:
49
+ console.error(`qti-inside does not support shape "${this.shape}"`);
50
+ return null;
51
+ }
52
+ }
53
+ #parsePoint(value) {
54
+ const tokens = value
55
+ .split(/[,\s]+/)
56
+ .map(token => token.trim())
57
+ .filter(Boolean);
58
+ if (tokens.length !== 2) {
59
+ console.error('qti-inside requires a point value formatted as "x y" or "x,y"');
60
+ return null;
61
+ }
62
+ const x = Number.parseFloat(tokens[0]);
63
+ const y = Number.parseFloat(tokens[1]);
64
+ if (Number.isNaN(x) || Number.isNaN(y)) {
65
+ console.error('qti-inside requires numeric point coordinates');
66
+ return null;
67
+ }
68
+ return { x, y };
69
+ }
70
+ #parseCoords(value) {
71
+ const coords = value
72
+ .split(',')
73
+ .map(token => token.trim())
74
+ .filter(Boolean)
75
+ .map(token => Number.parseFloat(token));
76
+ if (coords.some(coord => Number.isNaN(coord))) {
77
+ console.error('qti-inside requires numeric coords');
78
+ return [];
79
+ }
80
+ return coords;
81
+ }
82
+ #isInsideCircle(point, coords) {
83
+ if (coords.length !== 3) {
84
+ console.error('qti-inside circle requires x,y,r');
85
+ return null;
86
+ }
87
+ const [centerX, centerY, radius] = coords;
88
+ return (point.x - centerX) ** 2 + (point.y - centerY) ** 2 <= radius ** 2;
89
+ }
90
+ #isInsideRect(point, coords) {
91
+ if (coords.length !== 4) {
92
+ console.error('qti-inside rect requires left,top,right,bottom');
93
+ return null;
94
+ }
95
+ const [x1, y1, x2, y2] = coords;
96
+ const left = Math.min(x1, x2);
97
+ const right = Math.max(x1, x2);
98
+ const top = Math.min(y1, y2);
99
+ const bottom = Math.max(y1, y2);
100
+ return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;
101
+ }
102
+ #isInsideEllipse(point, coords) {
103
+ if (coords.length !== 4) {
104
+ console.error('qti-inside ellipse requires centerX,centerY,radiusX,radiusY');
105
+ return null;
106
+ }
107
+ const [centerX, centerY, radiusX, radiusY] = coords;
108
+ if (radiusX === 0 || radiusY === 0) {
109
+ return false;
110
+ }
111
+ return (point.x - centerX) ** 2 / radiusX ** 2 + (point.y - centerY) ** 2 / radiusY ** 2 <= 1;
112
+ }
113
+ #isInsidePolygon(point, coords) {
114
+ if (coords.length < 6 || coords.length % 2 !== 0) {
115
+ console.error('qti-inside polygon requires at least 3 coordinate pairs');
116
+ return null;
117
+ }
118
+ let inside = false;
119
+ for (let current = 0, previous = coords.length - 2; current < coords.length; current += 2) {
120
+ const xi = coords[current];
121
+ const yi = coords[current + 1];
122
+ const xj = coords[previous];
123
+ const yj = coords[previous + 1];
124
+ const intersects = yi > point.y !== yj > point.y && point.x < ((xj - xi) * (point.y - yi)) / (yj - yi || Number.EPSILON) + xi;
125
+ if (intersects) {
126
+ inside = !inside;
127
+ }
128
+ previous = current;
129
+ }
130
+ return inside;
131
+ }
132
+ }
133
+ __decorate([
134
+ property({ type: String })
135
+ ], QtiInside.prototype, "shape", void 0);
136
+ __decorate([
137
+ property({ type: String })
138
+ ], QtiInside.prototype, "coords", void 0);
139
+ //# sourceMappingURL=qti-inside.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-inside.js","sourceRoot":"","sources":["../../../src/components/qti-inside/qti-inside.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\ntype Point = { x: number; y: number };\n\nexport class QtiInside extends QtiExpression<boolean | null> {\n @property({ type: String }) shape = '';\n\n @property({ type: String }) coords = '';\n\n public override getResult(): boolean | null {\n const variables = this.getVariables() as ResponseVariable[];\n\n if (variables.length !== 1) {\n console.error('qti-inside requires exactly one point expression');\n return null;\n }\n\n const variable = variables[0];\n if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {\n console.error('qti-inside requires single cardinality');\n return null;\n }\n if (variable.value === null || variable.value === undefined) {\n return null;\n }\n if (!this.shape || !this.coords) {\n console.error('qti-inside requires shape and coords attributes');\n return null;\n }\n\n const point = this.#parsePoint(variable.value.toString());\n const coords = this.#parseCoords(this.coords);\n\n if (!point || coords.length === 0) {\n return null;\n }\n\n switch (this.shape.toLowerCase()) {\n case 'circle':\n return this.#isInsideCircle(point, coords);\n case 'rect':\n return this.#isInsideRect(point, coords);\n case 'ellipse':\n return this.#isInsideEllipse(point, coords);\n case 'poly':\n case 'polygon':\n return this.#isInsidePolygon(point, coords);\n default:\n console.error(`qti-inside does not support shape \"${this.shape}\"`);\n return null;\n }\n }\n\n #parsePoint(value: string): Point | null {\n const tokens = value\n .split(/[,\\s]+/)\n .map(token => token.trim())\n .filter(Boolean);\n\n if (tokens.length !== 2) {\n console.error('qti-inside requires a point value formatted as \"x y\" or \"x,y\"');\n return null;\n }\n\n const x = Number.parseFloat(tokens[0]);\n const y = Number.parseFloat(tokens[1]);\n\n if (Number.isNaN(x) || Number.isNaN(y)) {\n console.error('qti-inside requires numeric point coordinates');\n return null;\n }\n\n return { x, y };\n }\n\n #parseCoords(value: string): number[] {\n const coords = value\n .split(',')\n .map(token => token.trim())\n .filter(Boolean)\n .map(token => Number.parseFloat(token));\n\n if (coords.some(coord => Number.isNaN(coord))) {\n console.error('qti-inside requires numeric coords');\n return [];\n }\n\n return coords;\n }\n\n #isInsideCircle(point: Point, coords: number[]): boolean | null {\n if (coords.length !== 3) {\n console.error('qti-inside circle requires x,y,r');\n return null;\n }\n\n const [centerX, centerY, radius] = coords;\n return (point.x - centerX) ** 2 + (point.y - centerY) ** 2 <= radius ** 2;\n }\n\n #isInsideRect(point: Point, coords: number[]): boolean | null {\n if (coords.length !== 4) {\n console.error('qti-inside rect requires left,top,right,bottom');\n return null;\n }\n\n const [x1, y1, x2, y2] = coords;\n const left = Math.min(x1, x2);\n const right = Math.max(x1, x2);\n const top = Math.min(y1, y2);\n const bottom = Math.max(y1, y2);\n\n return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;\n }\n\n #isInsideEllipse(point: Point, coords: number[]): boolean | null {\n if (coords.length !== 4) {\n console.error('qti-inside ellipse requires centerX,centerY,radiusX,radiusY');\n return null;\n }\n\n const [centerX, centerY, radiusX, radiusY] = coords;\n if (radiusX === 0 || radiusY === 0) {\n return false;\n }\n\n return (point.x - centerX) ** 2 / radiusX ** 2 + (point.y - centerY) ** 2 / radiusY ** 2 <= 1;\n }\n\n #isInsidePolygon(point: Point, coords: number[]): boolean | null {\n if (coords.length < 6 || coords.length % 2 !== 0) {\n console.error('qti-inside polygon requires at least 3 coordinate pairs');\n return null;\n }\n\n let inside = false;\n\n for (let current = 0, previous = coords.length - 2; current < coords.length; current += 2) {\n const xi = coords[current];\n const yi = coords[current + 1];\n const xj = coords[previous];\n const yj = coords[previous + 1];\n\n const intersects =\n yi > point.y !== yj > point.y && point.x < ((xj - xi) * (point.y - yi)) / (yj - yi || Number.EPSILON) + xi;\n\n if (intersects) {\n inside = !inside;\n }\n\n previous = current;\n }\n\n return inside;\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-integer-divide operator performs integer division rounded down.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerDivide
5
+ *
6
+ * Takes 2 sub-expressions with base-type integer and single cardinality.
7
+ * Returns result of (x / y) rounded down toward negative infinity.
8
+ * Special cases: Returns NULL if any argument is NULL or if divisor is 0.
9
+ */
10
+ export declare class QtiIntegerDivide extends QtiExpression<number | null> {
11
+ #private;
12
+ getResult(): number | null;
13
+ }
@@ -0,0 +1,47 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-integer-divide operator performs integer division rounded down.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerDivide
5
+ *
6
+ * Takes 2 sub-expressions with base-type integer and single cardinality.
7
+ * Returns result of (x / y) rounded down toward negative infinity.
8
+ * Special cases: Returns NULL if any argument is NULL or if divisor is 0.
9
+ */
10
+ export class QtiIntegerDivide extends QtiExpression {
11
+ getResult() {
12
+ const values = this.#collectIntegerValues(this.getVariables());
13
+ if (values.length !== 2) {
14
+ console.error('qti-integer-divide requires exactly 2 integer values');
15
+ return null;
16
+ }
17
+ if (values[1] === 0) {
18
+ console.error('qti-integer-divide: division by zero');
19
+ return null;
20
+ }
21
+ return Math.floor(values[0] / values[1]);
22
+ }
23
+ #collectIntegerValues(variables) {
24
+ const values = [];
25
+ for (const variable of variables) {
26
+ if (variable.baseType !== 'integer') {
27
+ console.error('qti-integer-divide requires integer base-type');
28
+ return [];
29
+ }
30
+ if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {
31
+ console.error('qti-integer-divide requires single cardinality');
32
+ return [];
33
+ }
34
+ if (variable.value === null || variable.value === undefined) {
35
+ return [];
36
+ }
37
+ const value = Number.parseInt(variable.value, 10);
38
+ if (Number.isNaN(value)) {
39
+ console.error('qti-integer-divide requires integer values');
40
+ return [];
41
+ }
42
+ values.push(value);
43
+ }
44
+ return values;
45
+ }
46
+ }
47
+ //# sourceMappingURL=qti-integer-divide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-integer-divide.js","sourceRoot":"","sources":["../../../src/components/qti-integer-divide/qti-integer-divide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAiB,SAAQ,aAA4B;IAChD,SAAS;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,YAAY,EAAwB,CAAC,CAAC;QAErF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;YACtE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,qBAAqB,CAAC,SAA6B;QACjD,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;gBAC/D,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvE,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;gBAChE,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC5D,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAe,EAAE,EAAE,CAAC,CAAC;YAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAC5D,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-integer-divide operator performs integer division rounded down.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerDivide\n *\n * Takes 2 sub-expressions with base-type integer and single cardinality.\n * Returns result of (x / y) rounded down toward negative infinity.\n * Special cases: Returns NULL if any argument is NULL or if divisor is 0.\n */\nexport class QtiIntegerDivide extends QtiExpression<number | null> {\n public override getResult(): number | null {\n const values = this.#collectIntegerValues(this.getVariables() as ResponseVariable[]);\n\n if (values.length !== 2) {\n console.error('qti-integer-divide requires exactly 2 integer values');\n return null;\n }\n\n if (values[1] === 0) {\n console.error('qti-integer-divide: division by zero');\n return null;\n }\n\n return Math.floor(values[0] / values[1]);\n }\n\n #collectIntegerValues(variables: ResponseVariable[]): number[] {\n const values: number[] = [];\n\n for (const variable of variables) {\n if (variable.baseType !== 'integer') {\n console.error('qti-integer-divide requires integer base-type');\n return [];\n }\n if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {\n console.error('qti-integer-divide requires single cardinality');\n return [];\n }\n if (variable.value === null || variable.value === undefined) {\n return [];\n }\n\n const value = Number.parseInt(variable.value as string, 10);\n if (Number.isNaN(value)) {\n console.error('qti-integer-divide requires integer values');\n return [];\n }\n values.push(value);\n }\n\n return values;\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-integer-modulus operator returns the remainder of integer division.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerModulus
5
+ *
6
+ * Takes 2 sub-expressions with base-type integer and single cardinality.
7
+ * Returns the remainder (x % y).
8
+ * Special cases: Returns NULL if any argument is NULL or if divisor is 0.
9
+ */
10
+ export declare class QtiIntegerModulus extends QtiExpression<number | null> {
11
+ #private;
12
+ getResult(): number | null;
13
+ }
@@ -0,0 +1,47 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-integer-modulus operator returns the remainder of integer division.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerModulus
5
+ *
6
+ * Takes 2 sub-expressions with base-type integer and single cardinality.
7
+ * Returns the remainder (x % y).
8
+ * Special cases: Returns NULL if any argument is NULL or if divisor is 0.
9
+ */
10
+ export class QtiIntegerModulus extends QtiExpression {
11
+ getResult() {
12
+ const values = this.#collectIntegerValues(this.getVariables());
13
+ if (values.length !== 2) {
14
+ console.error('qti-integer-modulus requires exactly 2 integer values');
15
+ return null;
16
+ }
17
+ if (values[1] === 0) {
18
+ console.error('qti-integer-modulus: division by zero');
19
+ return null;
20
+ }
21
+ return values[0] % values[1];
22
+ }
23
+ #collectIntegerValues(variables) {
24
+ const values = [];
25
+ for (const variable of variables) {
26
+ if (variable.baseType !== 'integer') {
27
+ console.error('qti-integer-modulus requires integer base-type');
28
+ return [];
29
+ }
30
+ if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {
31
+ console.error('qti-integer-modulus requires single cardinality');
32
+ return [];
33
+ }
34
+ if (variable.value === null || variable.value === undefined) {
35
+ return [];
36
+ }
37
+ const value = Number.parseInt(variable.value, 10);
38
+ if (Number.isNaN(value)) {
39
+ console.error('qti-integer-modulus requires integer values');
40
+ return [];
41
+ }
42
+ values.push(value);
43
+ }
44
+ return values;
45
+ }
46
+ }
47
+ //# sourceMappingURL=qti-integer-modulus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-integer-modulus.js","sourceRoot":"","sources":["../../../src/components/qti-integer-modulus/qti-integer-modulus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,aAA4B;IACjD,SAAS;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,YAAY,EAAwB,CAAC,CAAC;QAErF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,qBAAqB,CAAC,SAA6B;QACjD,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;gBAChE,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvE,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;gBACjE,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC5D,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAe,EAAE,EAAE,CAAC,CAAC;YAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;gBAC7D,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-integer-modulus operator returns the remainder of integer division.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerModulus\n *\n * Takes 2 sub-expressions with base-type integer and single cardinality.\n * Returns the remainder (x % y).\n * Special cases: Returns NULL if any argument is NULL or if divisor is 0.\n */\nexport class QtiIntegerModulus extends QtiExpression<number | null> {\n public override getResult(): number | null {\n const values = this.#collectIntegerValues(this.getVariables() as ResponseVariable[]);\n\n if (values.length !== 2) {\n console.error('qti-integer-modulus requires exactly 2 integer values');\n return null;\n }\n\n if (values[1] === 0) {\n console.error('qti-integer-modulus: division by zero');\n return null;\n }\n\n return values[0] % values[1];\n }\n\n #collectIntegerValues(variables: ResponseVariable[]): number[] {\n const values: number[] = [];\n\n for (const variable of variables) {\n if (variable.baseType !== 'integer') {\n console.error('qti-integer-modulus requires integer base-type');\n return [];\n }\n if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {\n console.error('qti-integer-modulus requires single cardinality');\n return [];\n }\n if (variable.value === null || variable.value === undefined) {\n return [];\n }\n\n const value = Number.parseInt(variable.value as string, 10);\n if (Number.isNaN(value)) {\n console.error('qti-integer-modulus requires integer values');\n return [];\n }\n values.push(value);\n }\n\n return values;\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-integer-to-float operator converts an integer to a float.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerToFloat
5
+ *
6
+ * Takes 1 sub-expression with base-type integer and single cardinality.
7
+ * Returns a value of base-type float with the same numeric value.
8
+ * Special cases: Returns NULL if sub-expression is NULL.
9
+ */
10
+ export declare class QtiIntegerToFloat extends QtiExpression<number | null> {
11
+ getResult(): number | null;
12
+ }
@@ -0,0 +1,37 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-integer-to-float operator converts an integer to a float.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerToFloat
5
+ *
6
+ * Takes 1 sub-expression with base-type integer and single cardinality.
7
+ * Returns a value of base-type float with the same numeric value.
8
+ * Special cases: Returns NULL if sub-expression is NULL.
9
+ */
10
+ export class QtiIntegerToFloat extends QtiExpression {
11
+ getResult() {
12
+ const variables = this.getVariables();
13
+ if (variables.length !== 1) {
14
+ console.error('qti-integer-to-float requires exactly one child expression');
15
+ return null;
16
+ }
17
+ const variable = variables[0];
18
+ if (variable.baseType !== 'integer') {
19
+ console.error('qti-integer-to-float requires integer base-type');
20
+ return null;
21
+ }
22
+ if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {
23
+ console.error('qti-integer-to-float requires single cardinality');
24
+ return null;
25
+ }
26
+ if (variable.value === null || variable.value === undefined) {
27
+ return null;
28
+ }
29
+ const value = Number.parseInt(variable.value, 10);
30
+ if (Number.isNaN(value)) {
31
+ console.error('qti-integer-to-float requires an integer value');
32
+ return null;
33
+ }
34
+ return value;
35
+ }
36
+ }
37
+ //# sourceMappingURL=qti-integer-to-float.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-integer-to-float.js","sourceRoot":"","sources":["../../../src/components/qti-integer-to-float/qti-integer-to-float.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,aAA4B;IACjD,SAAS;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QAE5D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;YAC5E,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACvE,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAe,EAAE,EAAE,CAAC,CAAC;QAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-integer-to-float operator converts an integer to a float.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#integerToFloat\n *\n * Takes 1 sub-expression with base-type integer and single cardinality.\n * Returns a value of base-type float with the same numeric value.\n * Special cases: Returns NULL if sub-expression is NULL.\n */\nexport class QtiIntegerToFloat extends QtiExpression<number | null> {\n public override getResult(): number | null {\n const variables = this.getVariables() as ResponseVariable[];\n\n if (variables.length !== 1) {\n console.error('qti-integer-to-float requires exactly one child expression');\n return null;\n }\n\n const variable = variables[0];\n if (variable.baseType !== 'integer') {\n console.error('qti-integer-to-float requires integer base-type');\n return null;\n }\n if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {\n console.error('qti-integer-to-float requires single cardinality');\n return null;\n }\n if (variable.value === null || variable.value === undefined) {\n return null;\n }\n\n const value = Number.parseInt(variable.value as string, 10);\n if (Number.isNaN(value)) {\n console.error('qti-integer-to-float requires an integer value');\n return null;\n }\n\n return value;\n }\n}\n"]}
@@ -1,4 +1,12 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-is-null operator checks if a variable or expression is missing its value.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#isNull
5
+ *
6
+ * Takes 1 sub-expression with any base-type or cardinality.
7
+ * Returns true if the sub-expression is NULL, false otherwise.
8
+ * Special cases: Empty containers and empty strings are treated as NULL.
9
+ */
2
10
  export declare class QtiIsNull extends QtiExpression<boolean> {
3
11
  getResult(): boolean;
4
12
  }
@@ -1,6 +1,12 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
- // PK: For the contains we assume the expressions to calculate are all directedPairs
3
- // I don't know it this in QTI is always the case however?
2
+ /**
3
+ * @summary The qti-is-null operator checks if a variable or expression is missing its value.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#isNull
5
+ *
6
+ * Takes 1 sub-expression with any base-type or cardinality.
7
+ * Returns true if the sub-expression is NULL, false otherwise.
8
+ * Special cases: Empty containers and empty strings are treated as NULL.
9
+ */
4
10
  export class QtiIsNull extends QtiExpression {
5
11
  getResult() {
6
12
  if (this.children.length === 1) {
@@ -15,5 +21,4 @@ export class QtiIsNull extends QtiExpression {
15
21
  return null;
16
22
  }
17
23
  }
18
- customElements.define('qti-is-null', QtiIsNull);
19
24
  //# sourceMappingURL=qti-is-null.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"qti-is-null.js","sourceRoot":"","sources":["../../../src/components/qti-is-null/qti-is-null.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,oFAAoF;AACpF,0DAA0D;AAC1D,MAAM,OAAO,SAAU,SAAQ,aAAsB;IACnC,SAAS;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;YAC5D,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACjC,OAAO,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC;QAC7D,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n// PK: For the contains we assume the expressions to calculate are all directedPairs\n// I don't know it this in QTI is always the case however?\nexport class QtiIsNull extends QtiExpression<boolean> {\n public override getResult(): boolean {\n if (this.children.length === 1) {\n const variables = this.getVariables() as ResponseVariable[];\n if (!variables) {\n return true;\n }\n const value = variables[0].value;\n return value == null || value == undefined || value === '';\n }\n console.error('unexpected number of children in qti Null');\n return null;\n }\n}\n\ncustomElements.define('qti-is-null', QtiIsNull);\n"]}
1
+ {"version":3,"file":"qti-is-null.js","sourceRoot":"","sources":["../../../src/components/qti-is-null/qti-is-null.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,SAAU,SAAQ,aAAsB;IACnC,SAAS;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;YAC5D,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACjC,OAAO,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC;QAC7D,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-is-null operator checks if a variable or expression is missing its value.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#isNull\n *\n * Takes 1 sub-expression with any base-type or cardinality.\n * Returns true if the sub-expression is NULL, false otherwise.\n * Special cases: Empty containers and empty strings are treated as NULL.\n */\nexport class QtiIsNull extends QtiExpression<boolean> {\n public override getResult(): boolean {\n if (this.children.length === 1) {\n const variables = this.getVariables() as ResponseVariable[];\n if (!variables) {\n return true;\n }\n const value = variables[0].value;\n return value == null || value == undefined || value === '';\n }\n console.error('unexpected number of children in qti Null');\n return null;\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export declare class QtiLcm extends QtiExpression<number | null> {
3
+ #private;
4
+ getResult(): number | null;
5
+ }
@@ -0,0 +1,70 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export class QtiLcm extends QtiExpression {
3
+ getResult() {
4
+ const values = this.#collectIntegerValues(this.getVariables());
5
+ if (values.length === 0) {
6
+ console.error('qti-lcm requires at least one integer value');
7
+ return null;
8
+ }
9
+ return values.reduce((accumulator, value) => this.#lcm(accumulator, value));
10
+ }
11
+ #collectIntegerValues(variables) {
12
+ const values = [];
13
+ for (const variable of variables) {
14
+ if (variable.baseType !== 'integer') {
15
+ console.error('qti-lcm requires integer base-type');
16
+ return [];
17
+ }
18
+ if (variable.value === null || variable.value === undefined) {
19
+ return [];
20
+ }
21
+ if (variable.cardinality === 'single') {
22
+ if (Array.isArray(variable.value)) {
23
+ console.error('qti-lcm unexpected array value for single cardinality');
24
+ return [];
25
+ }
26
+ const value = Number.parseInt(variable.value, 10);
27
+ if (Number.isNaN(value)) {
28
+ console.error('qti-lcm requires integer values');
29
+ return [];
30
+ }
31
+ values.push(value);
32
+ continue;
33
+ }
34
+ if (variable.cardinality !== 'multiple' && variable.cardinality !== 'ordered') {
35
+ console.error('qti-lcm unsupported cardinality');
36
+ return [];
37
+ }
38
+ if (!Array.isArray(variable.value)) {
39
+ console.error('qti-lcm expected array value for container cardinality');
40
+ return [];
41
+ }
42
+ for (const entry of variable.value) {
43
+ const value = Number.parseInt(entry, 10);
44
+ if (Number.isNaN(value)) {
45
+ console.error('qti-lcm requires integer values');
46
+ return [];
47
+ }
48
+ values.push(value);
49
+ }
50
+ }
51
+ return values;
52
+ }
53
+ #gcd(a, b) {
54
+ let left = Math.abs(a);
55
+ let right = Math.abs(b);
56
+ while (right !== 0) {
57
+ const remainder = left % right;
58
+ left = right;
59
+ right = remainder;
60
+ }
61
+ return left;
62
+ }
63
+ #lcm(a, b) {
64
+ if (a === 0 || b === 0) {
65
+ return 0;
66
+ }
67
+ return Math.abs((a * b) / this.#gcd(a, b));
68
+ }
69
+ }
70
+ //# sourceMappingURL=qti-lcm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-lcm.js","sourceRoot":"","sources":["../../../src/components/qti-lcm/qti-lcm.ts"],"names":[],"mappings":"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","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiLcm extends QtiExpression<number | null> {\n public override getResult(): number | null {\n const values = this.#collectIntegerValues(this.getVariables() as ResponseVariable[]);\n\n if (values.length === 0) {\n console.error('qti-lcm requires at least one integer value');\n return null;\n }\n\n return values.reduce((accumulator, value) => this.#lcm(accumulator, value));\n }\n\n #collectIntegerValues(variables: ResponseVariable[]): number[] {\n const values: number[] = [];\n\n for (const variable of variables) {\n if (variable.baseType !== 'integer') {\n console.error('qti-lcm requires integer base-type');\n return [];\n }\n if (variable.value === null || variable.value === undefined) {\n return [];\n }\n\n if (variable.cardinality === 'single') {\n if (Array.isArray(variable.value)) {\n console.error('qti-lcm unexpected array value for single cardinality');\n return [];\n }\n\n const value = Number.parseInt(variable.value as string, 10);\n if (Number.isNaN(value)) {\n console.error('qti-lcm requires integer values');\n return [];\n }\n values.push(value);\n continue;\n }\n\n if (variable.cardinality !== 'multiple' && variable.cardinality !== 'ordered') {\n console.error('qti-lcm unsupported cardinality');\n return [];\n }\n\n if (!Array.isArray(variable.value)) {\n console.error('qti-lcm expected array value for container cardinality');\n return [];\n }\n\n for (const entry of variable.value) {\n const value = Number.parseInt(entry as string, 10);\n if (Number.isNaN(value)) {\n console.error('qti-lcm requires integer values');\n return [];\n }\n values.push(value);\n }\n }\n\n return values;\n }\n\n #gcd(a: number, b: number): number {\n let left = Math.abs(a);\n let right = Math.abs(b);\n\n while (right !== 0) {\n const remainder = left % right;\n left = right;\n right = remainder;\n }\n\n return left;\n }\n\n #lcm(a: number, b: number): number {\n if (a === 0 || b === 0) {\n return 0;\n }\n\n return Math.abs((a * b) / this.#gcd(a, b));\n }\n}\n"]}
@@ -47,5 +47,4 @@ __decorate([
47
47
  consume({ context: itemContext, subscribe: true }),
48
48
  state()
49
49
  ], QtiLookupOutcomeValue.prototype, "context", void 0);
50
- customElements.define('qti-lookup-outcome-value', QtiLookupOutcomeValue);
51
50
  //# sourceMappingURL=qti-lookup-outcome-value.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"qti-lookup-outcome-value.js","sourceRoot":"","sources":["../../../src/components/qti-lookup-outcome-value/qti-lookup-outcome-value.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAM/C;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,OAAO;IAOhD,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,iBAA0C,CAAC;IACzD,CAAC;IAEe,OAAO;QACrB,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QAEnD,MAAM,eAAe,GACnB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC;QAExE,IAAI,KAAK,CAAC;QACV,IAAI,eAAe,CAAC,kBAAkB,EAAE,CAAC;YACvC,KAAK,GAAG,eAAe,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC/D,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAA0D,uBAAuB,EAAE;YAChG,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,iBAAiB,EAAE,IAAI,CAAC,UAAU;gBAClC,KAAK,EAAE,8BAA8B,CAAC,KAAK,CAAC;aAC7C;SACF,CAAC,CACH,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AApC6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yDAAoB;AAIrC;IAFT,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAClD,KAAK,EAAE;sDACwB;AAiClC,cAAc,CAAC,MAAM,CAAC,0BAA0B,EAAE,qBAAqB,CAAC,CAAC","sourcesContent":["import { property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport { convertNumberToUniversalFormat } from '@qti-components/base';\nimport { itemContext } from '@qti-components/base';\n\nimport { QtiRule } from '../qti-rule/qti-rule';\n\nimport type { QtiExpression } from '@qti-components/base';\nimport type { OutcomeVariable } from '@qti-components/base';\nimport type { ItemContext } from '@qti-components/base';\n\n/**\n * The lookupOutcomeValue rule sets the value of an outcome variable to the value obtained\n * by looking up the value of the associated expression in the lookupTable associated\n * with the outcome's declaration.\n */\nexport class QtiLookupOutcomeValue extends QtiRule {\n @property({ type: String }) identifier: string;\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n protected context?: ItemContext;\n\n get childExpression(): QtiExpression<string> {\n return this.firstElementChild as QtiExpression<string>;\n }\n\n public override process(): number {\n const identifier = this.getAttribute('identifier');\n\n const outcomeVariable: OutcomeVariable | null =\n this.context.variables.find(v => v.identifier === identifier) || null;\n\n let value;\n if (outcomeVariable.interpolationTable) {\n value = outcomeVariable.interpolationTable.get(parseFloat(this.childExpression.calculate()));\n }\n if (value === null || value === undefined) {\n console.warn('lookupOutcomeValue: value is null or undefined');\n return 0;\n }\n this.dispatchEvent(\n new CustomEvent<{ outcomeIdentifier: string; value: string | string[] }>('qti-set-outcome-value', {\n bubbles: true,\n composed: true,\n detail: {\n outcomeIdentifier: this.identifier,\n value: convertNumberToUniversalFormat(value)\n }\n })\n );\n return value;\n }\n}\ncustomElements.define('qti-lookup-outcome-value', QtiLookupOutcomeValue);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-lookup-outcome-value': QtiLookupOutcomeValue;\n }\n}\n"]}
1
+ {"version":3,"file":"qti-lookup-outcome-value.js","sourceRoot":"","sources":["../../../src/components/qti-lookup-outcome-value/qti-lookup-outcome-value.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAM/C;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,OAAO;IAOhD,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,iBAA0C,CAAC;IACzD,CAAC;IAEe,OAAO;QACrB,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QAEnD,MAAM,eAAe,GACnB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC;QAExE,IAAI,KAAK,CAAC;QACV,IAAI,eAAe,CAAC,kBAAkB,EAAE,CAAC;YACvC,KAAK,GAAG,eAAe,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC/D,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAA0D,uBAAuB,EAAE;YAChG,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,iBAAiB,EAAE,IAAI,CAAC,UAAU;gBAClC,KAAK,EAAE,8BAA8B,CAAC,KAAK,CAAC;aAC7C;SACF,CAAC,CACH,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AApC6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yDAAoB;AAIrC;IAFT,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAClD,KAAK,EAAE;sDACwB","sourcesContent":["import { property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport { convertNumberToUniversalFormat } from '@qti-components/base';\nimport { itemContext } from '@qti-components/base';\n\nimport { QtiRule } from '../qti-rule/qti-rule';\n\nimport type { QtiExpression } from '@qti-components/base';\nimport type { OutcomeVariable } from '@qti-components/base';\nimport type { ItemContext } from '@qti-components/base';\n\n/**\n * The lookupOutcomeValue rule sets the value of an outcome variable to the value obtained\n * by looking up the value of the associated expression in the lookupTable associated\n * with the outcome's declaration.\n */\nexport class QtiLookupOutcomeValue extends QtiRule {\n @property({ type: String }) identifier: string;\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n protected context?: ItemContext;\n\n get childExpression(): QtiExpression<string> {\n return this.firstElementChild as QtiExpression<string>;\n }\n\n public override process(): number {\n const identifier = this.getAttribute('identifier');\n\n const outcomeVariable: OutcomeVariable | null =\n this.context.variables.find(v => v.identifier === identifier) || null;\n\n let value;\n if (outcomeVariable.interpolationTable) {\n value = outcomeVariable.interpolationTable.get(parseFloat(this.childExpression.calculate()));\n }\n if (value === null || value === undefined) {\n console.warn('lookupOutcomeValue: value is null or undefined');\n return 0;\n }\n this.dispatchEvent(\n new CustomEvent<{ outcomeIdentifier: string; value: string | string[] }>('qti-set-outcome-value', {\n bubbles: true,\n composed: true,\n detail: {\n outcomeIdentifier: this.identifier,\n value: convertNumberToUniversalFormat(value)\n }\n })\n );\n return value;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-lookup-outcome-value': QtiLookupOutcomeValue;\n }\n}\n"]}
@@ -17,5 +17,4 @@ export class QtiLt extends QtiExpression {
17
17
  return null;
18
18
  }
19
19
  }
20
- customElements.define('qti-lt', QtiLt);
21
20
  //# sourceMappingURL=qti-lt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"qti-lt.js","sourceRoot":"","sources":["../../../src/components/qti-lt/qti-lt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,OAAO,KAAM,SAAQ,aAAsB;IAC/B,SAAS;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,IACE,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC;gBAC9D,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,EAC9D,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiLt extends QtiExpression<boolean> {\n public override getResult(): boolean {\n if (this.children.length === 2) {\n const values = this.getVariables() as ResponseVariable[];\n const value1 = values[0];\n const value2 = values[1];\n if (\n (value1.baseType === 'integer' || value1.baseType === 'float') &&\n (value2.baseType === 'integer' || value2.baseType === 'float')\n ) {\n return +value1.value < +value2.value;\n } else {\n console.error('unexpected baseType or cardinality in qti lt');\n }\n }\n console.error('unexpected number of children in lt');\n return null;\n }\n}\n\ncustomElements.define('qti-lt', QtiLt);\n"]}
1
+ {"version":3,"file":"qti-lt.js","sourceRoot":"","sources":["../../../src/components/qti-lt/qti-lt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,OAAO,KAAM,SAAQ,aAAsB;IAC/B,SAAS;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,IACE,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC;gBAC9D,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,EAC9D,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiLt extends QtiExpression<boolean> {\n public override getResult(): boolean {\n if (this.children.length === 2) {\n const values = this.getVariables() as ResponseVariable[];\n const value1 = values[0];\n const value2 = values[1];\n if (\n (value1.baseType === 'integer' || value1.baseType === 'float') &&\n (value2.baseType === 'integer' || value2.baseType === 'float')\n ) {\n return +value1.value < +value2.value;\n } else {\n console.error('unexpected baseType or cardinality in qti lt');\n }\n }\n console.error('unexpected number of children in lt');\n return null;\n }\n}\n"]}
@@ -20,5 +20,4 @@ export class QtiLte extends QtiConditionExpression {
20
20
  return null;
21
21
  }
22
22
  }
23
- customElements.define('qti-lte', QtiLte);
24
23
  //# sourceMappingURL=qti-lte.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"qti-lte.js","sourceRoot":"","sources":["../../../src/components/qti-lte/qti-lte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAI9D,oFAAoF;AACpF,0DAA0D;AAC1D,MAAM,OAAO,MAAO,SAAQ,sBAAsB;IAChC,SAAS;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,IACE,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC;gBAC9D,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,EAC9D,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;gBAC/D,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC","sourcesContent":["import { QtiConditionExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n// PK: For the contains we assume the expressions to calculate are all directedPairs\n// I don't know it this in QTI is always the case however?\nexport class QtiLte extends QtiConditionExpression {\n public override getResult(): boolean {\n if (this.children.length === 2) {\n const values = this.getVariables() as ResponseVariable[];\n const value1 = values[0];\n const value2 = values[1];\n if (\n (value1.baseType === 'integer' || value1.baseType === 'float') &&\n (value2.baseType === 'integer' || value2.baseType === 'float')\n ) {\n return +value1.value <= +value2.value;\n } else {\n console.error('unexpected baseType or cardinality in qti lte');\n return null;\n }\n }\n console.log('unexpected number of children in lte');\n return null;\n }\n}\n\ncustomElements.define('qti-lte', QtiLte);\n"]}
1
+ {"version":3,"file":"qti-lte.js","sourceRoot":"","sources":["../../../src/components/qti-lte/qti-lte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAI9D,oFAAoF;AACpF,0DAA0D;AAC1D,MAAM,OAAO,MAAO,SAAQ,sBAAsB;IAChC,SAAS;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,IACE,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC;gBAC9D,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,EAC9D,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;gBAC/D,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import { QtiConditionExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n// PK: For the contains we assume the expressions to calculate are all directedPairs\n// I don't know it this in QTI is always the case however?\nexport class QtiLte extends QtiConditionExpression {\n public override getResult(): boolean {\n if (this.children.length === 2) {\n const values = this.getVariables() as ResponseVariable[];\n const value1 = values[0];\n const value2 = values[1];\n if (\n (value1.baseType === 'integer' || value1.baseType === 'float') &&\n (value2.baseType === 'integer' || value2.baseType === 'float')\n ) {\n return +value1.value <= +value2.value;\n } else {\n console.error('unexpected baseType or cardinality in qti lte');\n return null;\n }\n }\n console.log('unexpected number of children in lte');\n return null;\n }\n}\n"]}
@@ -1,4 +1,12 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-map-response operator applies a mapping to a candidate's response.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#mapResponse
5
+ *
6
+ * Transforms the bound response variable using the declaration's qti-mapping.
7
+ * Returns a single float representing the mapped score (or sum of mapped values).
8
+ * Special cases: Returns 0.0 if response is NULL; counts identical values in containers once.
9
+ */
2
10
  export declare class QtiMapResponse extends QtiExpression<number> {
3
11
  identifier: string;
4
12
  getResult(): number;
@@ -7,6 +7,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { property } from 'lit/decorators.js';
8
8
  import { QtiExpression } from '@qti-components/base';
9
9
  import { ScoringHelper } from '@qti-components/base';
10
+ /**
11
+ * @summary The qti-map-response operator applies a mapping to a candidate's response.
12
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#mapResponse
13
+ *
14
+ * Transforms the bound response variable using the declaration's qti-mapping.
15
+ * Returns a single float representing the mapped score (or sum of mapped values).
16
+ * Special cases: Returns 0.0 if response is NULL; counts identical values in containers once.
17
+ */
10
18
  export class QtiMapResponse extends QtiExpression {
11
19
  getResult() {
12
20
  const response = this.context.variables.find(r => r.identifier === this.identifier);
@@ -48,5 +56,4 @@ export class QtiMapResponse extends QtiExpression {
48
56
  __decorate([
49
57
  property({ type: String })
50
58
  ], QtiMapResponse.prototype, "identifier", void 0);
51
- customElements.define('qti-map-response', QtiMapResponse);
52
59
  //# sourceMappingURL=qti-map-response.js.map