@qti-components/processing 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/LICENSE.md +674 -0
  2. package/dist/components/index.d.ts +38 -0
  3. package/dist/components/index.js +44 -0
  4. package/dist/components/index.js.map +1 -0
  5. package/dist/components/qti-and/qti-and.d.ts +20 -0
  6. package/dist/components/qti-and/qti-and.js +56 -0
  7. package/dist/components/qti-and/qti-and.js.map +1 -0
  8. package/dist/components/qti-basevalue/qti-basevalue.d.ts +6 -0
  9. package/dist/components/qti-basevalue/qti-basevalue.js +23 -0
  10. package/dist/components/qti-basevalue/qti-basevalue.js.map +1 -0
  11. package/dist/components/qti-container-size/qti-container-size.d.ts +12 -0
  12. package/dist/components/qti-container-size/qti-container-size.js +40 -0
  13. package/dist/components/qti-container-size/qti-container-size.js.map +1 -0
  14. package/dist/components/qti-contains/qti-contains.d.ts +4 -0
  15. package/dist/components/qti-contains/qti-contains.js +38 -0
  16. package/dist/components/qti-contains/qti-contains.js.map +1 -0
  17. package/dist/components/qti-correct/qti-correct.d.ts +5 -0
  18. package/dist/components/qti-correct/qti-correct.js +18 -0
  19. package/dist/components/qti-correct/qti-correct.js.map +1 -0
  20. package/dist/components/qti-default/qti-default.d.ts +17 -0
  21. package/dist/components/qti-default/qti-default.js +87 -0
  22. package/dist/components/qti-default/qti-default.js.map +1 -0
  23. package/dist/components/qti-delete/qti-delete.d.ts +4 -0
  24. package/dist/components/qti-delete/qti-delete.js +23 -0
  25. package/dist/components/qti-delete/qti-delete.js.map +1 -0
  26. package/dist/components/qti-equal/qti-equal.d.ts +5 -0
  27. package/dist/components/qti-equal/qti-equal.js +41 -0
  28. package/dist/components/qti-equal/qti-equal.js.map +1 -0
  29. package/dist/components/qti-equal-rounded/qti-equal-rounded.d.ts +6 -0
  30. package/dist/components/qti-equal-rounded/qti-equal-rounded.js +84 -0
  31. package/dist/components/qti-equal-rounded/qti-equal-rounded.js.map +1 -0
  32. package/dist/components/qti-field-value/qti-field-value.d.ts +4 -0
  33. package/dist/components/qti-field-value/qti-field-value.js +27 -0
  34. package/dist/components/qti-field-value/qti-field-value.js.map +1 -0
  35. package/dist/components/qti-gcd/qti.gcd.d.ts +13 -0
  36. package/dist/components/qti-gcd/qti.gcd.js +119 -0
  37. package/dist/components/qti-gcd/qti.gcd.js.map +1 -0
  38. package/dist/components/qti-gt/qti-gt.d.ts +4 -0
  39. package/dist/components/qti-gt/qti-gt.js +21 -0
  40. package/dist/components/qti-gt/qti-gt.js.map +1 -0
  41. package/dist/components/qti-gte/qti-gte.d.ts +4 -0
  42. package/dist/components/qti-gte/qti-gte.js +24 -0
  43. package/dist/components/qti-gte/qti-gte.js.map +1 -0
  44. package/dist/components/qti-index/qti-index.d.ts +6 -0
  45. package/dist/components/qti-index/qti-index.js +82 -0
  46. package/dist/components/qti-index/qti-index.js.map +1 -0
  47. package/dist/components/qti-is-null/qti-is-null.d.ts +4 -0
  48. package/dist/components/qti-is-null/qti-is-null.js +19 -0
  49. package/dist/components/qti-is-null/qti-is-null.js.map +1 -0
  50. package/dist/components/qti-lookup-outcome-value/qti-lookup-outcome-value.d.ts +19 -0
  51. package/dist/components/qti-lookup-outcome-value/qti-lookup-outcome-value.js +51 -0
  52. package/dist/components/qti-lookup-outcome-value/qti-lookup-outcome-value.js.map +1 -0
  53. package/dist/components/qti-lt/qti-lt.d.ts +4 -0
  54. package/dist/components/qti-lt/qti-lt.js +21 -0
  55. package/dist/components/qti-lt/qti-lt.js.map +1 -0
  56. package/dist/components/qti-lte/qti-lte.d.ts +4 -0
  57. package/dist/components/qti-lte/qti-lte.js +24 -0
  58. package/dist/components/qti-lte/qti-lte.js.map +1 -0
  59. package/dist/components/qti-map-response/qti-map-response.d.ts +5 -0
  60. package/dist/components/qti-map-response/qti-map-response.js +52 -0
  61. package/dist/components/qti-map-response/qti-map-response.js.map +1 -0
  62. package/dist/components/qti-map-response-point/qti-map-response-point.d.ts +5 -0
  63. package/dist/components/qti-map-response-point/qti-map-response-point.js +60 -0
  64. package/dist/components/qti-map-response-point/qti-map-response-point.js.map +1 -0
  65. package/dist/components/qti-match/qti-match.d.ts +6 -0
  66. package/dist/components/qti-match/qti-match.js +84 -0
  67. package/dist/components/qti-match/qti-match.js.map +1 -0
  68. package/dist/components/qti-math-operator/qti-math-operator.d.ts +14 -0
  69. package/dist/components/qti-math-operator/qti-math-operator.js +213 -0
  70. package/dist/components/qti-math-operator/qti-math-operator.js.map +1 -0
  71. package/dist/components/qti-member/qti-member.d.ts +4 -0
  72. package/dist/components/qti-member/qti-member.js +34 -0
  73. package/dist/components/qti-member/qti-member.js.map +1 -0
  74. package/dist/components/qti-multiple/qti-multiple.d.ts +5 -0
  75. package/dist/components/qti-multiple/qti-multiple.js +26 -0
  76. package/dist/components/qti-multiple/qti-multiple.js.map +1 -0
  77. package/dist/components/qti-not/qti-not.d.ts +5 -0
  78. package/dist/components/qti-not/qti-not.js +14 -0
  79. package/dist/components/qti-not/qti-not.js.map +1 -0
  80. package/dist/components/qti-null/qti-null.d.ts +11 -0
  81. package/dist/components/qti-null/qti-null.js +15 -0
  82. package/dist/components/qti-null/qti-null.js.map +1 -0
  83. package/dist/components/qti-or/qti-or.d.ts +4 -0
  84. package/dist/components/qti-or/qti-or.js +39 -0
  85. package/dist/components/qti-or/qti-or.js.map +1 -0
  86. package/dist/components/qti-ordered/qti-ordered.d.ts +5 -0
  87. package/dist/components/qti-ordered/qti-ordered.js +19 -0
  88. package/dist/components/qti-ordered/qti-ordered.js.map +1 -0
  89. package/dist/components/qti-power/qti-power.d.ts +12 -0
  90. package/dist/components/qti-power/qti-power.js +99 -0
  91. package/dist/components/qti-power/qti-power.js.map +1 -0
  92. package/dist/components/qti-printed-variable/qti-printed-variable.d.ts +9 -0
  93. package/dist/components/qti-printed-variable/qti-printed-variable.js +29 -0
  94. package/dist/components/qti-printed-variable/qti-printed-variable.js.map +1 -0
  95. package/dist/components/qti-product/qti-product.d.ts +4 -0
  96. package/dist/components/qti-product/qti-product.js +23 -0
  97. package/dist/components/qti-product/qti-product.js.map +1 -0
  98. package/dist/components/qti-random/qti-random.d.ts +4 -0
  99. package/dist/components/qti-random/qti-random.js +19 -0
  100. package/dist/components/qti-random/qti-random.js.map +1 -0
  101. package/dist/components/qti-random-integer/qti-random-integer.d.ts +18 -0
  102. package/dist/components/qti-random-integer/qti-random-integer.js +90 -0
  103. package/dist/components/qti-random-integer/qti-random-integer.js.map +1 -0
  104. package/dist/components/qti-response-condition/qti-response-condition.d.ts +5 -0
  105. package/dist/components/qti-response-condition/qti-response-condition.js +19 -0
  106. package/dist/components/qti-response-condition/qti-response-condition.js.map +1 -0
  107. package/dist/components/qti-response-else/qti-response-else.d.ts +8 -0
  108. package/dist/components/qti-response-else/qti-response-else.js +21 -0
  109. package/dist/components/qti-response-else/qti-response-else.js.map +1 -0
  110. package/dist/components/qti-response-else-if/qti-response-else-if.d.ts +4 -0
  111. package/dist/components/qti-response-else-if/qti-response-else-if.js +9 -0
  112. package/dist/components/qti-response-else-if/qti-response-else-if.js.map +1 -0
  113. package/dist/components/qti-response-if/qti-response-if.d.ts +6 -0
  114. package/dist/components/qti-response-if/qti-response-if.js +17 -0
  115. package/dist/components/qti-response-if/qti-response-if.js.map +1 -0
  116. package/dist/components/qti-round/qti-round.d.ts +13 -0
  117. package/dist/components/qti-round/qti-round.js +66 -0
  118. package/dist/components/qti-round/qti-round.js.map +1 -0
  119. package/dist/components/qti-round-to/qti-round-to.d.ts +15 -0
  120. package/dist/components/qti-round-to/qti-round-to.js +117 -0
  121. package/dist/components/qti-round-to/qti-round-to.js.map +1 -0
  122. package/dist/components/qti-rule/qti-rule.d.ts +11 -0
  123. package/dist/components/qti-rule/qti-rule.js +21 -0
  124. package/dist/components/qti-rule/qti-rule.js.map +1 -0
  125. package/dist/components/qti-set-outcome-value/qti-set-outcome-value.d.ts +24 -0
  126. package/dist/components/qti-set-outcome-value/qti-set-outcome-value.js +63 -0
  127. package/dist/components/qti-set-outcome-value/qti-set-outcome-value.js.map +1 -0
  128. package/dist/components/qti-string-match/qti-string-match.d.ts +5 -0
  129. package/dist/components/qti-string-match/qti-string-match.js +39 -0
  130. package/dist/components/qti-string-match/qti-string-match.js.map +1 -0
  131. package/dist/components/qti-subtract/index.d.ts +7 -0
  132. package/dist/components/qti-subtract/index.js +4 -0
  133. package/dist/components/qti-subtract/index.js.map +1 -0
  134. package/dist/components/qti-subtract/qti-subtract.d.ts +20 -0
  135. package/dist/components/qti-subtract/qti-subtract.js +34 -0
  136. package/dist/components/qti-subtract/qti-subtract.js.map +1 -0
  137. package/dist/components/qti-sum/qti-sum.d.ts +12 -0
  138. package/dist/components/qti-sum/qti-sum.js +36 -0
  139. package/dist/components/qti-sum/qti-sum.js.map +1 -0
  140. package/dist/components/qti-variable/qti-variable.d.ts +4 -0
  141. package/dist/components/qti-variable/qti-variable.js +10 -0
  142. package/dist/components/qti-variable/qti-variable.js.map +1 -0
  143. package/dist/index.d.ts +7 -0
  144. package/dist/index.js +8 -0
  145. package/dist/index.js.map +1 -0
  146. package/package.json +44 -0
@@ -0,0 +1,24 @@
1
+ import { QtiConditionExpression } 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?
4
+ export class QtiLte extends QtiConditionExpression {
5
+ getResult() {
6
+ if (this.children.length === 2) {
7
+ const values = this.getVariables();
8
+ const value1 = values[0];
9
+ const value2 = values[1];
10
+ if ((value1.baseType === 'integer' || value1.baseType === 'float') &&
11
+ (value2.baseType === 'integer' || value2.baseType === 'float')) {
12
+ return +value1.value <= +value2.value;
13
+ }
14
+ else {
15
+ console.error('unexpected baseType or cardinality in qti lte');
16
+ return null;
17
+ }
18
+ }
19
+ console.log('unexpected number of children in lte');
20
+ return null;
21
+ }
22
+ }
23
+ customElements.define('qti-lte', QtiLte);
24
+ //# sourceMappingURL=qti-lte.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,5 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export declare class QtiMapResponse extends QtiExpression<number> {
3
+ identifier: string;
4
+ getResult(): number;
5
+ }
@@ -0,0 +1,52 @@
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
+ import { ScoringHelper } from '@qti-components/base';
10
+ export class QtiMapResponse extends QtiExpression {
11
+ getResult() {
12
+ const response = this.context.variables.find(r => r.identifier === this.identifier);
13
+ if (!response || !response.mapping) {
14
+ console.error(`Response ${this.identifier} can not be found`);
15
+ return null;
16
+ }
17
+ const mapping = response.mapping;
18
+ const candidateResponses = !Array.isArray(response.value) ? [response.value] : response.value;
19
+ let result = 0;
20
+ for (const candidateResponse of candidateResponses) {
21
+ const mappedValues = mapping.mapEntries.filter(entry => {
22
+ if (response.baseType === 'string' && !entry.caseSensitive) {
23
+ return ScoringHelper.compareSingleValues(entry.mapKey.toLowerCase(), candidateResponse.toLowerCase(), response.baseType);
24
+ }
25
+ else {
26
+ return ScoringHelper.compareSingleValues(entry.mapKey, candidateResponse, response.baseType);
27
+ }
28
+ });
29
+ // now find the mapped value with the highest value (if there are multiple)
30
+ const mappedValue = mappedValues.reduce((prev, current) => (prev.mappedValue > current.mappedValue ? prev : current), mappedValues.length > 0 ? mappedValues[0] : { mapKey: null, mappedValue: null } // Use the first element instead of a manual initial value
31
+ );
32
+ if (!(mappedValue === null || mappedValue.mappedValue == undefined)) {
33
+ result += mappedValue.mappedValue;
34
+ }
35
+ else {
36
+ result += mapping.defaultValue;
37
+ }
38
+ }
39
+ if (mapping?.lowerBound !== null && mapping?.lowerBound !== undefined) {
40
+ result = Math.max(mapping.lowerBound, result);
41
+ }
42
+ if (mapping?.upperBound !== null && mapping?.upperBound !== undefined) {
43
+ result = Math.min(mapping.upperBound, result);
44
+ }
45
+ return result;
46
+ }
47
+ }
48
+ __decorate([
49
+ property({ type: String })
50
+ ], QtiMapResponse.prototype, "identifier", void 0);
51
+ customElements.define('qti-map-response', QtiMapResponse);
52
+ //# sourceMappingURL=qti-map-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-map-response.js","sourceRoot":"","sources":["../../../src/components/qti-map-response/qti-map-response.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\nimport { ScoringHelper } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiMapResponse extends QtiExpression<number> {\n @property({ type: String }) identifier: string;\n\n public override getResult(): number {\n const response: ResponseVariable = this.context.variables.find(r => r.identifier === this.identifier);\n if (!response || !response.mapping) {\n console.error(`Response ${this.identifier} can not be found`);\n return null;\n }\n const mapping = response.mapping;\n const candidateResponses = !Array.isArray(response.value) ? [response.value] : response.value;\n let result = 0;\n for (const candidateResponse of candidateResponses) {\n const mappedValues = mapping.mapEntries.filter(entry => {\n if (response.baseType === 'string' && !entry.caseSensitive) {\n return ScoringHelper.compareSingleValues(\n entry.mapKey.toLowerCase(),\n candidateResponse.toLowerCase(),\n response.baseType\n );\n } else {\n return ScoringHelper.compareSingleValues(entry.mapKey, candidateResponse, response.baseType);\n }\n });\n // now find the mapped value with the highest value (if there are multiple)\n const mappedValue = mappedValues.reduce(\n (prev, current) => (prev.mappedValue > current.mappedValue ? prev : current),\n mappedValues.length > 0 ? mappedValues[0] : { mapKey: null, mappedValue: null } // Use the first element instead of a manual initial value\n );\n if (!(mappedValue === null || mappedValue.mappedValue == undefined)) {\n result += mappedValue.mappedValue;\n } else {\n result += mapping.defaultValue;\n }\n }\n if (mapping?.lowerBound !== null && mapping?.lowerBound !== undefined) {\n result = Math.max(mapping.lowerBound, result);\n }\n if (mapping?.upperBound !== null && mapping?.upperBound !== undefined) {\n result = Math.min(mapping.upperBound, result);\n }\n return result;\n }\n}\n\ncustomElements.define('qti-map-response', QtiMapResponse);\n"]}
@@ -0,0 +1,5 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export declare class QtiMapResponsePoint extends QtiExpression<number> {
3
+ identifier: string;
4
+ getResult(): number;
5
+ }
@@ -0,0 +1,60 @@
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
+ import { ScoringHelper } from '@qti-components/base';
10
+ export class QtiMapResponsePoint extends QtiExpression {
11
+ getResult() {
12
+ const response = this.context.variables.find(r => r.identifier === this.identifier);
13
+ if (!response) {
14
+ console.warn(`Response ${this.identifier} cannot be found`);
15
+ return null;
16
+ }
17
+ const areaMapping = response.areaMapping;
18
+ if (!areaMapping) {
19
+ console.warn(`Area mapping not found for response ${this.identifier}`);
20
+ return null;
21
+ }
22
+ const candidateResponses = !Array.isArray(response.value) ? [response.value] : response.value;
23
+ if (!candidateResponses || candidateResponses.length === 0) {
24
+ console.warn(`No candidate responses for response ${this.identifier}`);
25
+ return null;
26
+ }
27
+ let result = 0;
28
+ // Keep track of areas that have already been matched
29
+ const mappedAreas = new Set();
30
+ for (const candidateResponse of candidateResponses) {
31
+ for (const entry of areaMapping.areaMapEntries) {
32
+ if (mappedAreas.has(entry.coords)) {
33
+ continue; // Skip areas that have already been mapped
34
+ }
35
+ const isPointInArea = ScoringHelper.isPointInArea(candidateResponse, `${entry.shape},${entry.coords}`, response.baseType);
36
+ if (isPointInArea) {
37
+ result += entry.mappedValue ?? 0;
38
+ mappedAreas.add(entry.coords);
39
+ }
40
+ }
41
+ }
42
+ // Add default value for unmatched candidate responses
43
+ if (mappedAreas.size < candidateResponses.length) {
44
+ result += areaMapping.defaultValue;
45
+ }
46
+ // Apply bounds if defined
47
+ if (areaMapping.lowerBound != null) {
48
+ result = Math.max(areaMapping.lowerBound, result);
49
+ }
50
+ if (areaMapping.upperBound != null) {
51
+ result = Math.min(areaMapping.upperBound, result);
52
+ }
53
+ return result;
54
+ }
55
+ }
56
+ __decorate([
57
+ property({ type: String })
58
+ ], QtiMapResponsePoint.prototype, "identifier", void 0);
59
+ customElements.define('qti-map-response-point', QtiMapResponsePoint);
60
+ //# sourceMappingURL=qti-map-response-point.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-map-response-point.js","sourceRoot":"","sources":["../../../src/components/qti-map-response-point/qti-map-response-point.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAKrD,MAAM,OAAO,mBAAoB,SAAQ,aAAqB;IAG5C,SAAS;QACvB,MAAM,QAAQ,GAAqB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC;QACtG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,kBAAkB,CAAC,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,WAAW,GAAmB,QAAQ,CAAC,WAAW,CAAC;QACzD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,uCAAuC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,kBAAkB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC9F,IAAI,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,uCAAuC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,qDAAqD;QACrD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QAEtC,KAAK,MAAM,iBAAiB,IAAI,kBAAkB,EAAE,CAAC;YACnD,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,cAAc,EAAE,CAAC;gBAC/C,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;oBAClC,SAAS,CAAC,2CAA2C;gBACvD,CAAC;gBACD,MAAM,aAAa,GAAG,aAAa,CAAC,aAAa,CAC/C,iBAAiB,EACjB,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,EAChC,QAAQ,CAAC,QAAQ,CAClB,CAAC;gBACF,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;oBACjC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAED,sDAAsD;QACtD,IAAI,WAAW,CAAC,IAAI,GAAG,kBAAkB,CAAC,MAAM,EAAE,CAAC;YACjD,MAAM,IAAI,WAAW,CAAC,YAAY,CAAC;QACrC,CAAC;QAED,0BAA0B;QAC1B,IAAI,WAAW,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;YACnC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,WAAW,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;YACnC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA1D6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDAAoB;AA4DjD,cAAc,CAAC,MAAM,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAAC","sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\nimport { ScoringHelper } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\nimport type { QtiAreaMapping } from '@qti-components/base';\n\nexport class QtiMapResponsePoint extends QtiExpression<number> {\n @property({ type: String }) identifier: string;\n\n public override getResult(): number {\n const response: ResponseVariable = this.context.variables.find(r => r.identifier === this.identifier);\n if (!response) {\n console.warn(`Response ${this.identifier} cannot be found`);\n return null;\n }\n\n const areaMapping: QtiAreaMapping = response.areaMapping;\n if (!areaMapping) {\n console.warn(`Area mapping not found for response ${this.identifier}`);\n return null;\n }\n\n const candidateResponses = !Array.isArray(response.value) ? [response.value] : response.value;\n if (!candidateResponses || candidateResponses.length === 0) {\n console.warn(`No candidate responses for response ${this.identifier}`);\n return null;\n }\n\n let result = 0;\n\n // Keep track of areas that have already been matched\n const mappedAreas = new Set<string>();\n\n for (const candidateResponse of candidateResponses) {\n for (const entry of areaMapping.areaMapEntries) {\n if (mappedAreas.has(entry.coords)) {\n continue; // Skip areas that have already been mapped\n }\n const isPointInArea = ScoringHelper.isPointInArea(\n candidateResponse,\n `${entry.shape},${entry.coords}`,\n response.baseType\n );\n if (isPointInArea) {\n result += entry.mappedValue ?? 0;\n mappedAreas.add(entry.coords);\n }\n }\n }\n\n // Add default value for unmatched candidate responses\n if (mappedAreas.size < candidateResponses.length) {\n result += areaMapping.defaultValue;\n }\n\n // Apply bounds if defined\n if (areaMapping.lowerBound != null) {\n result = Math.max(areaMapping.lowerBound, result);\n }\n if (areaMapping.upperBound != null) {\n result = Math.min(areaMapping.upperBound, result);\n }\n\n return result;\n }\n}\n\ncustomElements.define('qti-map-response-point', QtiMapResponsePoint);\n"]}
@@ -0,0 +1,6 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ import type { ResponseVariable } from '@qti-components/base';
3
+ export declare class QtiMatch extends QtiExpression<boolean> {
4
+ getResult(): boolean;
5
+ static match(valueToMap: ResponseVariable, correctValueInfo: ResponseVariable): boolean;
6
+ }
@@ -0,0 +1,84 @@
1
+ import { ScoringHelper } from '@qti-components/base';
2
+ import { QtiExpression } from '@qti-components/base';
3
+ export class QtiMatch extends QtiExpression {
4
+ //PK : FIXME.
5
+ // This was a little experiment if we could call the match function as a static function,
6
+ // This can be used for all kind of things, but now especially for use in
7
+ // qti-response-condition-script
8
+ // in which we pass the expressions as pure functions, and hope for the best.
9
+ // SADLY, the getVariables throws roet in de eten.. weet nog niet precies hoe deze werkt.
10
+ // Maar ik ga erin duiken.
11
+ getResult() {
12
+ if (this.children.length === 2) {
13
+ const values = this.getVariables();
14
+ const valueToMap = values[0];
15
+ const correctValueInfo = values[1];
16
+ return QtiMatch.match(valueToMap, correctValueInfo);
17
+ }
18
+ console.error('unexpected number of children in match');
19
+ return null;
20
+ }
21
+ static match(valueToMap, correctValueInfo) {
22
+ if (valueToMap.value === null)
23
+ return false;
24
+ switch (correctValueInfo.cardinality) {
25
+ case 'single': {
26
+ if (Array.isArray(valueToMap.value) || Array.isArray(correctValueInfo.value)) {
27
+ console.error('unexpected cardinality in qti match');
28
+ return false;
29
+ }
30
+ return ScoringHelper.compareSingleValues(valueToMap.value?.toString(), correctValueInfo.value.toString(), correctValueInfo.baseType);
31
+ }
32
+ case 'ordered': {
33
+ if (!Array.isArray(valueToMap.value) || !Array.isArray(correctValueInfo.value)) {
34
+ console.error('unexpected cardinality in qti match');
35
+ return false;
36
+ }
37
+ if (valueToMap.value.length !== correctValueInfo.value.length) {
38
+ return false;
39
+ }
40
+ for (let i = 0; i < valueToMap.value.length; i++) {
41
+ const result = ScoringHelper.compareSingleValues(correctValueInfo.value[i], valueToMap.value[i], correctValueInfo.baseType);
42
+ if (!result) {
43
+ return false;
44
+ }
45
+ }
46
+ return true;
47
+ }
48
+ case 'multiple': {
49
+ if (!Array.isArray(valueToMap.value) || !Array.isArray(correctValueInfo.value)) {
50
+ console.error('unexpected cardinality in qti match');
51
+ return false;
52
+ }
53
+ if (valueToMap.value.length !== correctValueInfo.value.length) {
54
+ return false;
55
+ }
56
+ let answerIndex = 0;
57
+ for (const correctAnswer of correctValueInfo.value) {
58
+ let matchingValue = null;
59
+ const arr = [...valueToMap.value];
60
+ for (const mv of arr) {
61
+ const result = ScoringHelper.compareSingleValues(correctAnswer, mv, correctValueInfo.baseType);
62
+ if (result) {
63
+ matchingValue = mv;
64
+ break;
65
+ }
66
+ }
67
+ if (matchingValue !== null) {
68
+ arr.splice(arr.indexOf(matchingValue), 1);
69
+ }
70
+ else {
71
+ return false;
72
+ }
73
+ answerIndex++;
74
+ }
75
+ return true;
76
+ }
77
+ default:
78
+ console.error('unexpected cardinality in qti match');
79
+ return false;
80
+ }
81
+ }
82
+ }
83
+ customElements.define('qti-match', QtiMatch);
84
+ //# sourceMappingURL=qti-match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-match.js","sourceRoot":"","sources":["../../../src/components/qti-match/qti-match.ts"],"names":[],"mappings":"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","sourcesContent":["import { ScoringHelper } from '@qti-components/base';\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiMatch extends QtiExpression<boolean> {\n //PK : FIXME.\n // This was a little experiment if we could call the match function as a static function,\n // This can be used for all kind of things, but now especially for use in\n // qti-response-condition-script\n // in which we pass the expressions as pure functions, and hope for the best.\n // SADLY, the getVariables throws roet in de eten.. weet nog niet precies hoe deze werkt.\n // Maar ik ga erin duiken.\n public override getResult() {\n if (this.children.length === 2) {\n const values = this.getVariables() as ResponseVariable[];\n const valueToMap = values[0];\n const correctValueInfo = values[1];\n return QtiMatch.match(valueToMap, correctValueInfo);\n }\n\n console.error('unexpected number of children in match');\n return null;\n }\n\n public static match(valueToMap: ResponseVariable, correctValueInfo: ResponseVariable) {\n if (valueToMap.value === null) return false;\n switch (correctValueInfo.cardinality) {\n case 'single': {\n if (Array.isArray(valueToMap.value) || Array.isArray(correctValueInfo.value)) {\n console.error('unexpected cardinality in qti match');\n return false;\n }\n return ScoringHelper.compareSingleValues(\n valueToMap.value?.toString(),\n correctValueInfo.value.toString(),\n correctValueInfo.baseType\n );\n }\n\n case 'ordered': {\n if (!Array.isArray(valueToMap.value) || !Array.isArray(correctValueInfo.value)) {\n console.error('unexpected cardinality in qti match');\n return false;\n }\n if (valueToMap.value.length !== correctValueInfo.value.length) {\n return false;\n }\n for (let i = 0; i < valueToMap.value.length; i++) {\n const result = ScoringHelper.compareSingleValues(\n correctValueInfo.value[i],\n valueToMap.value[i],\n correctValueInfo.baseType\n );\n if (!result) {\n return false;\n }\n }\n return true;\n }\n\n case 'multiple': {\n if (!Array.isArray(valueToMap.value) || !Array.isArray(correctValueInfo.value)) {\n console.error('unexpected cardinality in qti match');\n return false;\n }\n if (valueToMap.value.length !== correctValueInfo.value.length) {\n return false;\n }\n let answerIndex = 0;\n for (const correctAnswer of correctValueInfo.value) {\n let matchingValue: string | null = null;\n const arr = [...valueToMap.value];\n for (const mv of arr) {\n const result = ScoringHelper.compareSingleValues(correctAnswer, mv, correctValueInfo.baseType);\n if (result) {\n matchingValue = mv;\n break;\n }\n }\n if (matchingValue !== null) {\n (arr as string[]).splice(arr.indexOf(matchingValue), 1);\n } else {\n return false;\n }\n answerIndex++;\n }\n return true;\n }\n\n default:\n console.error('unexpected cardinality in qti match');\n return false;\n }\n }\n}\n\ncustomElements.define('qti-match', QtiMatch);\n"]}
@@ -0,0 +1,14 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-math-operator performs mathematical operations on numerical values.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/impl#h.math-operator
5
+ *
6
+ * Takes 1 or more sub-expressions with single cardinality and numerical base-types.
7
+ * The result is a single float, except for signum, floor and ceil which return integers.
8
+ * Returns NULL if any argument is NULL or falls outside the function's natural domain.
9
+ */
10
+ export declare class QtiMathOperator extends QtiExpression<number | null> {
11
+ #private;
12
+ name: string;
13
+ getResult(): number | null;
14
+ }
@@ -0,0 +1,213 @@
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
+ /**
10
+ * @summary The qti-math-operator performs mathematical operations on numerical values.
11
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/impl#h.math-operator
12
+ *
13
+ * Takes 1 or more sub-expressions with single cardinality and numerical base-types.
14
+ * The result is a single float, except for signum, floor and ceil which return integers.
15
+ * Returns NULL if any argument is NULL or falls outside the function's natural domain.
16
+ */
17
+ export class QtiMathOperator extends QtiExpression {
18
+ constructor() {
19
+ super(...arguments);
20
+ this.name = '';
21
+ }
22
+ getResult() {
23
+ if (!this.name) {
24
+ console.error('qti-math-operator requires a name attribute');
25
+ return null;
26
+ }
27
+ const variables = this.getVariables();
28
+ if (!variables || variables.length === 0) {
29
+ return null;
30
+ }
31
+ // Extract numerical values and validate
32
+ const values = [];
33
+ for (const variable of variables) {
34
+ // Check cardinality
35
+ if (variable.cardinality !== 'single') {
36
+ console.error('qti-math-operator requires single cardinality');
37
+ return null;
38
+ }
39
+ // Check if value is array (shouldn't be for single cardinality)
40
+ if (Array.isArray(variable.value)) {
41
+ console.error('qti-math-operator unexpected array value for single cardinality');
42
+ return null;
43
+ }
44
+ // Handle null values
45
+ if (variable.value === null || variable.value === undefined) {
46
+ return null;
47
+ }
48
+ // Check base type
49
+ if (variable.baseType !== 'integer' && variable.baseType !== 'float') {
50
+ console.error('qti-math-operator requires numerical base-type');
51
+ return null;
52
+ }
53
+ // Convert to number
54
+ const numValue = parseFloat(variable.value);
55
+ if (isNaN(numValue)) {
56
+ console.error('qti-math-operator non-numerical value');
57
+ return null;
58
+ }
59
+ values.push(numValue);
60
+ }
61
+ // Perform the mathematical operation
62
+ return this.#performOperation(this.name, values);
63
+ }
64
+ #performOperation(operation, values) {
65
+ try {
66
+ switch (operation.toLowerCase()) {
67
+ // Single argument functions
68
+ case 'sin':
69
+ if (values.length !== 1)
70
+ return null;
71
+ return Math.sin(values[0]);
72
+ case 'cos':
73
+ if (values.length !== 1)
74
+ return null;
75
+ return Math.cos(values[0]);
76
+ case 'tan':
77
+ if (values.length !== 1)
78
+ return null;
79
+ return Math.tan(values[0]);
80
+ case 'asin':
81
+ if (values.length !== 1)
82
+ return null;
83
+ if (values[0] < -1 || values[0] > 1)
84
+ return null; // Outside domain
85
+ return Math.asin(values[0]);
86
+ case 'acos':
87
+ if (values.length !== 1)
88
+ return null;
89
+ if (values[0] < -1 || values[0] > 1)
90
+ return null; // Outside domain
91
+ return Math.acos(values[0]);
92
+ case 'atan':
93
+ if (values.length !== 1)
94
+ return null;
95
+ return Math.atan(values[0]);
96
+ case 'sinh':
97
+ if (values.length !== 1)
98
+ return null;
99
+ return Math.sinh(values[0]);
100
+ case 'cosh':
101
+ if (values.length !== 1)
102
+ return null;
103
+ return Math.cosh(values[0]);
104
+ case 'tanh':
105
+ if (values.length !== 1)
106
+ return null;
107
+ return Math.tanh(values[0]);
108
+ case 'log':
109
+ if (values.length !== 1)
110
+ return null;
111
+ if (values[0] <= 0)
112
+ return null; // Outside domain
113
+ return Math.log(values[0]);
114
+ case 'ln':
115
+ if (values.length !== 1)
116
+ return null;
117
+ if (values[0] <= 0)
118
+ return null; // Outside domain
119
+ return Math.log(values[0]);
120
+ case 'log10':
121
+ if (values.length !== 1)
122
+ return null;
123
+ if (values[0] <= 0)
124
+ return null; // Outside domain
125
+ return Math.log10(values[0]);
126
+ case 'exp':
127
+ if (values.length !== 1)
128
+ return null;
129
+ return Math.exp(values[0]);
130
+ case 'abs':
131
+ if (values.length !== 1)
132
+ return null;
133
+ return Math.abs(values[0]);
134
+ case 'sqrt':
135
+ if (values.length !== 1)
136
+ return null;
137
+ if (values[0] < 0)
138
+ return null; // Outside domain
139
+ return Math.sqrt(values[0]);
140
+ case 'signum':
141
+ if (values.length !== 1)
142
+ return null;
143
+ return Math.sign(values[0]); // Returns -1, 0, or 1 (integer)
144
+ case 'floor':
145
+ if (values.length !== 1)
146
+ return null;
147
+ return Math.floor(values[0]); // Returns integer
148
+ case 'ceil':
149
+ if (values.length !== 1)
150
+ return null;
151
+ return Math.ceil(values[0]); // Returns integer
152
+ case 'round':
153
+ if (values.length !== 1)
154
+ return null;
155
+ return Math.round(values[0]);
156
+ // Two argument functions
157
+ case 'atan2':
158
+ if (values.length !== 2)
159
+ return null;
160
+ return Math.atan2(values[0], values[1]);
161
+ case 'pow': {
162
+ if (values.length !== 2) {
163
+ return null;
164
+ }
165
+ const base = values[0];
166
+ const exponent = values[1];
167
+ // Check for invalid cases
168
+ if (base === 0 && exponent <= 0)
169
+ return null;
170
+ if (base < 0 && !Number.isInteger(exponent))
171
+ return null;
172
+ return Math.pow(base, exponent);
173
+ }
174
+ case 'log_base': {
175
+ if (values.length !== 2) {
176
+ return null;
177
+ }
178
+ const value = values[0];
179
+ const base = values[1];
180
+ if (value <= 0 || base <= 0 || base === 1)
181
+ return null; // Outside domain
182
+ return Math.log(value) / Math.log(base);
183
+ }
184
+ case 'mod':
185
+ if (values.length !== 2)
186
+ return null;
187
+ if (values[1] === 0)
188
+ return null; // Division by zero
189
+ return values[0] % values[1];
190
+ case 'max':
191
+ if (values.length < 1)
192
+ return null;
193
+ return Math.max(...values);
194
+ case 'min':
195
+ if (values.length < 1)
196
+ return null;
197
+ return Math.min(...values);
198
+ default:
199
+ console.error(`qti-math-operator: unknown operation "${operation}"`);
200
+ return null;
201
+ }
202
+ }
203
+ catch (error) {
204
+ console.error(`qti-math-operator: error performing operation "${operation}":`, error);
205
+ return null;
206
+ }
207
+ }
208
+ }
209
+ __decorate([
210
+ property({ type: String })
211
+ ], QtiMathOperator.prototype, "name", void 0);
212
+ customElements.define('qti-math-operator', QtiMathOperator);
213
+ //# sourceMappingURL=qti-math-operator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-math-operator.js","sourceRoot":"","sources":["../../../src/components/qti-math-operator/qti-math-operator.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,eAAgB,SAAQ,aAA4B;IAAjE;;QAC8B,SAAI,GAAW,EAAE,CAAC;IA0LhD,CAAC;IAxLiB,SAAS;QACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;YAC7D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QAC5D,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,wCAAwC;QACxC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,oBAAoB;YACpB,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;gBACtC,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;gBAC/D,OAAO,IAAI,CAAC;YACd,CAAC;YAED,gEAAgE;YAChE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;gBACjF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,qBAAqB;YACrB,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC5D,OAAO,IAAI,CAAC;YACd,CAAC;YAED,kBAAkB;YAClB,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACrE,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;gBAChE,OAAO,IAAI,CAAC;YACd,CAAC;YAED,oBAAoB;YACpB,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAe,CAAC,CAAC;YACtD,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;gBACvD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;QAED,qCAAqC;QACrC,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IAED,iBAAiB,CAAC,SAAiB,EAAE,MAAgB;QACnD,IAAI,CAAC;YACH,QAAQ,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;gBAChC,4BAA4B;gBAC5B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE7B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE7B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE7B,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;oBACnE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;oBACnE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;oBAClD,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE7B,KAAK,IAAI;oBACP,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;oBAClD,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE7B,KAAK,OAAO;oBACV,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;oBAClD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE/B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE7B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE7B,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;oBACjD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,KAAK,QAAQ;oBACX,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gCAAgC;gBAE/D,KAAK,OAAO;oBACV,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB;gBAElD,KAAK,MAAM;oBACT,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB;gBAEjD,KAAK,OAAO;oBACV,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE/B,yBAAyB;gBACzB,KAAK,OAAO;oBACV,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE1C,KAAK,KAAK,CAAC,CAAC,CAAC;oBACX,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACxB,OAAO,IAAI,CAAC;oBACd,CAAC;oBACD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;oBACvB,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;oBAC3B,0BAA0B;oBAC1B,IAAI,IAAI,KAAK,CAAC,IAAI,QAAQ,IAAI,CAAC;wBAAE,OAAO,IAAI,CAAC;oBAC7C,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACzD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAClC,CAAC;gBACD,KAAK,UAAU,CAAC,CAAC,CAAC;oBAChB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACxB,OAAO,IAAI,CAAC;oBACd,CAAC;oBACD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;oBACxB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;oBACvB,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;oBACzE,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1C,CAAC;gBACD,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACrC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;wBAAE,OAAO,IAAI,CAAC,CAAC,mBAAmB;oBACrD,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBAE/B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACnC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;gBAE7B,KAAK,KAAK;oBACR,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;wBAAE,OAAO,IAAI,CAAC;oBACnC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;gBAE7B;oBACE,OAAO,CAAC,KAAK,CAAC,yCAAyC,SAAS,GAAG,CAAC,CAAC;oBACrE,OAAO,IAAI,CAAC;YAChB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kDAAkD,SAAS,IAAI,EAAE,KAAK,CAAC,CAAC;YACtF,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AA1L6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CAAmB;AA4LhD,cAAc,CAAC,MAAM,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC","sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-math-operator performs mathematical operations on numerical values.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/impl#h.math-operator\n *\n * Takes 1 or more sub-expressions with single cardinality and numerical base-types.\n * The result is a single float, except for signum, floor and ceil which return integers.\n * Returns NULL if any argument is NULL or falls outside the function's natural domain.\n */\nexport class QtiMathOperator extends QtiExpression<number | null> {\n @property({ type: String }) name: string = '';\n\n public override getResult(): number | null {\n if (!this.name) {\n console.error('qti-math-operator requires a name attribute');\n return null;\n }\n\n const variables = this.getVariables() as ResponseVariable[];\n if (!variables || variables.length === 0) {\n return null;\n }\n\n // Extract numerical values and validate\n const values: number[] = [];\n for (const variable of variables) {\n // Check cardinality\n if (variable.cardinality !== 'single') {\n console.error('qti-math-operator requires single cardinality');\n return null;\n }\n\n // Check if value is array (shouldn't be for single cardinality)\n if (Array.isArray(variable.value)) {\n console.error('qti-math-operator unexpected array value for single cardinality');\n return null;\n }\n\n // Handle null values\n if (variable.value === null || variable.value === undefined) {\n return null;\n }\n\n // Check base type\n if (variable.baseType !== 'integer' && variable.baseType !== 'float') {\n console.error('qti-math-operator requires numerical base-type');\n return null;\n }\n\n // Convert to number\n const numValue = parseFloat(variable.value as string);\n if (isNaN(numValue)) {\n console.error('qti-math-operator non-numerical value');\n return null;\n }\n\n values.push(numValue);\n }\n\n // Perform the mathematical operation\n return this.#performOperation(this.name, values);\n }\n\n #performOperation(operation: string, values: number[]): number | null {\n try {\n switch (operation.toLowerCase()) {\n // Single argument functions\n case 'sin':\n if (values.length !== 1) return null;\n return Math.sin(values[0]);\n\n case 'cos':\n if (values.length !== 1) return null;\n return Math.cos(values[0]);\n\n case 'tan':\n if (values.length !== 1) return null;\n return Math.tan(values[0]);\n\n case 'asin':\n if (values.length !== 1) return null;\n if (values[0] < -1 || values[0] > 1) return null; // Outside domain\n return Math.asin(values[0]);\n\n case 'acos':\n if (values.length !== 1) return null;\n if (values[0] < -1 || values[0] > 1) return null; // Outside domain\n return Math.acos(values[0]);\n\n case 'atan':\n if (values.length !== 1) return null;\n return Math.atan(values[0]);\n\n case 'sinh':\n if (values.length !== 1) return null;\n return Math.sinh(values[0]);\n\n case 'cosh':\n if (values.length !== 1) return null;\n return Math.cosh(values[0]);\n\n case 'tanh':\n if (values.length !== 1) return null;\n return Math.tanh(values[0]);\n\n case 'log':\n if (values.length !== 1) return null;\n if (values[0] <= 0) return null; // Outside domain\n return Math.log(values[0]);\n\n case 'ln':\n if (values.length !== 1) return null;\n if (values[0] <= 0) return null; // Outside domain\n return Math.log(values[0]);\n\n case 'log10':\n if (values.length !== 1) return null;\n if (values[0] <= 0) return null; // Outside domain\n return Math.log10(values[0]);\n\n case 'exp':\n if (values.length !== 1) return null;\n return Math.exp(values[0]);\n\n case 'abs':\n if (values.length !== 1) return null;\n return Math.abs(values[0]);\n\n case 'sqrt':\n if (values.length !== 1) return null;\n if (values[0] < 0) return null; // Outside domain\n return Math.sqrt(values[0]);\n\n case 'signum':\n if (values.length !== 1) return null;\n return Math.sign(values[0]); // Returns -1, 0, or 1 (integer)\n\n case 'floor':\n if (values.length !== 1) return null;\n return Math.floor(values[0]); // Returns integer\n\n case 'ceil':\n if (values.length !== 1) return null;\n return Math.ceil(values[0]); // Returns integer\n\n case 'round':\n if (values.length !== 1) return null;\n return Math.round(values[0]);\n\n // Two argument functions\n case 'atan2':\n if (values.length !== 2) return null;\n return Math.atan2(values[0], values[1]);\n\n case 'pow': {\n if (values.length !== 2) {\n return null;\n }\n const base = values[0];\n const exponent = values[1];\n // Check for invalid cases\n if (base === 0 && exponent <= 0) return null;\n if (base < 0 && !Number.isInteger(exponent)) return null;\n return Math.pow(base, exponent);\n }\n case 'log_base': {\n if (values.length !== 2) {\n return null;\n }\n const value = values[0];\n const base = values[1];\n if (value <= 0 || base <= 0 || base === 1) return null; // Outside domain\n return Math.log(value) / Math.log(base);\n }\n case 'mod':\n if (values.length !== 2) return null;\n if (values[1] === 0) return null; // Division by zero\n return values[0] % values[1];\n\n case 'max':\n if (values.length < 1) return null;\n return Math.max(...values);\n\n case 'min':\n if (values.length < 1) return null;\n return Math.min(...values);\n\n default:\n console.error(`qti-math-operator: unknown operation \"${operation}\"`);\n return null;\n }\n } catch (error) {\n console.error(`qti-math-operator: error performing operation \"${operation}\":`, error);\n return null;\n }\n }\n}\n\ncustomElements.define('qti-math-operator', QtiMathOperator);\n"]}
@@ -0,0 +1,4 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export declare class QtiMember extends QtiExpression<boolean | null> {
3
+ getResult(): boolean;
4
+ }
@@ -0,0 +1,34 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export class QtiMember extends QtiExpression {
3
+ getResult() {
4
+ const values = this.getVariables();
5
+ if (!(this.children.length === 2)) {
6
+ console.warn('The member operator takes two sub-expressions');
7
+ }
8
+ const [value1, value2] = values;
9
+ if (!(value1.baseType === value2.baseType ||
10
+ (value1.baseType === 'integer' && value2.baseType === 'float') ||
11
+ (value1.baseType === 'float' && value2.baseType === 'integer'))) {
12
+ console.warn('Which must both have the same base-type');
13
+ }
14
+ if (!(value2.cardinality === 'multiple' || value2.cardinality === 'ordered')) {
15
+ console.warn('and the second must be a multiple or ordered container');
16
+ }
17
+ if (value1.baseType === 'float' || value2.baseType === 'float') {
18
+ console.warn('The member operator should not be used on sub-expressions with a base-type of float');
19
+ }
20
+ if (value1.baseType === 'duration' || value2.baseType === 'duration') {
21
+ console.warn('It must not be used on sub-expressions with a base-type of duration');
22
+ }
23
+ // If either sub-expression is NULL then the result of the operator is NULL
24
+ if (value1.value === null || value2.value === null) {
25
+ return null;
26
+ }
27
+ // The result is a single boolean with a value of 'true' if the value given by the first sub-expression is in the container defined by the second sub-expression.
28
+ const projection1 = value1.value;
29
+ const projection2 = value2.value;
30
+ return projection2.includes(projection1);
31
+ }
32
+ }
33
+ customElements.define('qti-member', QtiMember);
34
+ //# sourceMappingURL=qti-member.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-member.js","sourceRoot":"","sources":["../../../src/components/qti-member/qti-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,OAAO,SAAU,SAAQ,aAA6B;IAC1C,SAAS;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QAEzD,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC;QAEhC,IACE,CAAC,CACC,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ;YACnC,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC;YAC9D,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAC/D,EACD,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,KAAK,UAAU,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,EAAE,CAAC;YAC7E,OAAO,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,qFAAqF,CAAC,CAAC;QACtG,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,KAAK,UAAU,IAAI,MAAM,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACrE,OAAO,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QACtF,CAAC;QAED,2EAA2E;QAC3E,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,iKAAiK;QACjK,MAAM,WAAW,GAAG,MAAM,CAAC,KAAe,CAAC;QAC3C,MAAM,WAAW,GAAG,MAAM,CAAC,KAAiB,CAAC;QAC7C,OAAO,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiMember extends QtiExpression<boolean | null> {\n public override getResult() {\n const values = this.getVariables() as ResponseVariable[];\n\n if (!(this.children.length === 2)) {\n console.warn('The member operator takes two sub-expressions');\n }\n\n const [value1, value2] = values;\n\n if (\n !(\n value1.baseType === value2.baseType ||\n (value1.baseType === 'integer' && value2.baseType === 'float') ||\n (value1.baseType === 'float' && value2.baseType === 'integer')\n )\n ) {\n console.warn('Which must both have the same base-type');\n }\n if (!(value2.cardinality === 'multiple' || value2.cardinality === 'ordered')) {\n console.warn('and the second must be a multiple or ordered container');\n }\n if (value1.baseType === 'float' || value2.baseType === 'float') {\n console.warn('The member operator should not be used on sub-expressions with a base-type of float');\n }\n if (value1.baseType === 'duration' || value2.baseType === 'duration') {\n console.warn('It must not be used on sub-expressions with a base-type of duration');\n }\n\n // If either sub-expression is NULL then the result of the operator is NULL\n if (value1.value === null || value2.value === null) {\n return null;\n }\n\n // The result is a single boolean with a value of 'true' if the value given by the first sub-expression is in the container defined by the second sub-expression.\n const projection1 = value1.value as string;\n const projection2 = value2.value as string[];\n return projection2.includes(projection1);\n }\n}\n\ncustomElements.define('qti-member', QtiMember);\n"]}
@@ -0,0 +1,5 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ import type { ResponseVariable, VariableDeclaration } from '@qti-components/base';
3
+ export declare class QtiMultiple extends QtiExpression<VariableDeclaration<string | string[]>[]> {
4
+ getResult(): ResponseVariable[];
5
+ }
@@ -0,0 +1,26 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export class QtiMultiple extends QtiExpression {
3
+ getResult() {
4
+ console.debug('qti-multiple getResult called', this.innerHTML);
5
+ const variables = this.getVariables();
6
+ if (variables.length === 0) {
7
+ console.error('unexpected number of children in qti multiple');
8
+ return null;
9
+ }
10
+ for (const variable of variables) {
11
+ if (variable.cardinality !== 'multiple' && variable.cardinality !== 'single') {
12
+ console.error('unexpected cardinality in qti multiple');
13
+ return [];
14
+ }
15
+ }
16
+ // const values = variables.map(v => v.value);
17
+ // console.log(variables);
18
+ // const flattenedArray = values.reduce((acc: string[], value: string | string[]) => {
19
+ // return acc.concat(Array.isArray(value) ? [...value] : value);
20
+ // }, []);
21
+ // return flattenedArray;
22
+ return variables;
23
+ }
24
+ }
25
+ customElements.define('qti-multiple', QtiMultiple);
26
+ //# sourceMappingURL=qti-multiple.js.map