@qti-components/processing 1.3.2 → 1.3.3

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 (112) 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 +8 -0
  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 +61 -0
  9. package/dist/components/qti-any-n/qti-any-n.js.map +1 -0
  10. package/dist/components/qti-container-size/qti-container-size.d.ts +5 -5
  11. package/dist/components/qti-container-size/qti-container-size.js +5 -5
  12. package/dist/components/qti-container-size/qti-container-size.js.map +1 -1
  13. package/dist/components/qti-correct/qti-correct.d.ts +8 -0
  14. package/dist/components/qti-correct/qti-correct.js +8 -0
  15. package/dist/components/qti-correct/qti-correct.js.map +1 -1
  16. package/dist/components/qti-default/qti-default.d.ts +5 -5
  17. package/dist/components/qti-default/qti-default.js +5 -5
  18. package/dist/components/qti-default/qti-default.js.map +1 -1
  19. package/dist/components/qti-delete/qti-delete.d.ts +8 -0
  20. package/dist/components/qti-delete/qti-delete.js +8 -0
  21. package/dist/components/qti-delete/qti-delete.js.map +1 -1
  22. package/dist/components/qti-divide/qti-divide.d.ts +13 -0
  23. package/dist/components/qti-divide/qti-divide.js +50 -0
  24. package/dist/components/qti-divide/qti-divide.js.map +1 -0
  25. package/dist/components/qti-duration-gte/qti-duration-gte.d.ts +5 -0
  26. package/dist/components/qti-duration-gte/qti-duration-gte.js +45 -0
  27. package/dist/components/qti-duration-gte/qti-duration-gte.js.map +1 -0
  28. package/dist/components/qti-duration-lt/qti-duration-lt.d.ts +13 -0
  29. package/dist/components/qti-duration-lt/qti-duration-lt.js +53 -0
  30. package/dist/components/qti-duration-lt/qti-duration-lt.js.map +1 -0
  31. package/dist/components/qti-equal/qti-equal.d.ts +9 -0
  32. package/dist/components/qti-equal/qti-equal.js +15 -0
  33. package/dist/components/qti-equal/qti-equal.js.map +1 -1
  34. package/dist/components/qti-equal-rounded/qti-equal-rounded.d.ts +9 -0
  35. package/dist/components/qti-equal-rounded/qti-equal-rounded.js +9 -0
  36. package/dist/components/qti-equal-rounded/qti-equal-rounded.js.map +1 -1
  37. package/dist/components/qti-field-value/qti-field-value.d.ts +8 -0
  38. package/dist/components/qti-field-value/qti-field-value.js +8 -0
  39. package/dist/components/qti-field-value/qti-field-value.js.map +1 -1
  40. package/dist/components/qti-index/qti-index.d.ts +8 -0
  41. package/dist/components/qti-index/qti-index.js +8 -0
  42. package/dist/components/qti-index/qti-index.js.map +1 -1
  43. package/dist/components/qti-inside/qti-inside.d.ts +7 -0
  44. package/dist/components/qti-inside/qti-inside.js +141 -0
  45. package/dist/components/qti-inside/qti-inside.js.map +1 -0
  46. package/dist/components/qti-integer-divide/qti-integer-divide.d.ts +13 -0
  47. package/dist/components/qti-integer-divide/qti-integer-divide.js +48 -0
  48. package/dist/components/qti-integer-divide/qti-integer-divide.js.map +1 -0
  49. package/dist/components/qti-integer-modulus/qti-integer-modulus.d.ts +13 -0
  50. package/dist/components/qti-integer-modulus/qti-integer-modulus.js +48 -0
  51. package/dist/components/qti-integer-modulus/qti-integer-modulus.js.map +1 -0
  52. package/dist/components/qti-integer-to-float/qti-integer-to-float.d.ts +12 -0
  53. package/dist/components/qti-integer-to-float/qti-integer-to-float.js +38 -0
  54. package/dist/components/qti-integer-to-float/qti-integer-to-float.js.map +1 -0
  55. package/dist/components/qti-is-null/qti-is-null.d.ts +8 -0
  56. package/dist/components/qti-is-null/qti-is-null.js +8 -2
  57. package/dist/components/qti-is-null/qti-is-null.js.map +1 -1
  58. package/dist/components/qti-lcm/qti-lcm.d.ts +5 -0
  59. package/dist/components/qti-lcm/qti-lcm.js +71 -0
  60. package/dist/components/qti-lcm/qti-lcm.js.map +1 -0
  61. package/dist/components/qti-map-response/qti-map-response.d.ts +8 -0
  62. package/dist/components/qti-map-response/qti-map-response.js +8 -0
  63. package/dist/components/qti-map-response/qti-map-response.js.map +1 -1
  64. package/dist/components/qti-match/qti-match.d.ts +8 -0
  65. package/dist/components/qti-match/qti-match.js +8 -0
  66. package/dist/components/qti-match/qti-match.js.map +1 -1
  67. package/dist/components/qti-max/qti-max.d.ts +13 -0
  68. package/dist/components/qti-max/qti-max.js +46 -0
  69. package/dist/components/qti-max/qti-max.js.map +1 -0
  70. package/dist/components/qti-min/qti-min.d.ts +13 -0
  71. package/dist/components/qti-min/qti-min.js +46 -0
  72. package/dist/components/qti-min/qti-min.js.map +1 -0
  73. package/dist/components/qti-not/qti-not.d.ts +8 -0
  74. package/dist/components/qti-not/qti-not.js +8 -0
  75. package/dist/components/qti-not/qti-not.js.map +1 -1
  76. package/dist/components/qti-or/qti-or.d.ts +8 -0
  77. package/dist/components/qti-or/qti-or.js +8 -0
  78. package/dist/components/qti-or/qti-or.js.map +1 -1
  79. package/dist/components/qti-pattern-match/qti-pattern-match.d.ts +13 -0
  80. package/dist/components/qti-pattern-match/qti-pattern-match.js +53 -0
  81. package/dist/components/qti-pattern-match/qti-pattern-match.js.map +1 -0
  82. package/dist/components/qti-product/qti-product.d.ts +8 -0
  83. package/dist/components/qti-product/qti-product.js +8 -0
  84. package/dist/components/qti-product/qti-product.js.map +1 -1
  85. package/dist/components/qti-repeat/qti-repeat.d.ts +15 -0
  86. package/dist/components/qti-repeat/qti-repeat.js +113 -0
  87. package/dist/components/qti-repeat/qti-repeat.js.map +1 -0
  88. package/dist/components/qti-round/qti-round.d.ts +4 -5
  89. package/dist/components/qti-round/qti-round.js +4 -5
  90. package/dist/components/qti-round/qti-round.js.map +1 -1
  91. package/dist/components/qti-set-correct-response/qti-set-correct-response.d.ts +24 -0
  92. package/dist/components/qti-set-correct-response/qti-set-correct-response.js +77 -0
  93. package/dist/components/qti-set-correct-response/qti-set-correct-response.js.map +1 -0
  94. package/dist/components/qti-set-template-value/qti-set-template-value.d.ts +24 -0
  95. package/dist/components/qti-set-template-value/qti-set-template-value.js +81 -0
  96. package/dist/components/qti-set-template-value/qti-set-template-value.js.map +1 -0
  97. package/dist/components/qti-stats-operator/qti-stats-operator.d.ts +15 -0
  98. package/dist/components/qti-stats-operator/qti-stats-operator.js +78 -0
  99. package/dist/components/qti-stats-operator/qti-stats-operator.js.map +1 -0
  100. package/dist/components/qti-substring/qti-substring.d.ts +13 -0
  101. package/dist/components/qti-substring/qti-substring.js +51 -0
  102. package/dist/components/qti-substring/qti-substring.js.map +1 -0
  103. package/dist/components/qti-subtract/qti-subtract.d.ts +8 -0
  104. package/dist/components/qti-subtract/qti-subtract.js +8 -0
  105. package/dist/components/qti-subtract/qti-subtract.js.map +1 -1
  106. package/dist/components/qti-sum/qti-sum.d.ts +8 -0
  107. package/dist/components/qti-sum/qti-sum.js +8 -0
  108. package/dist/components/qti-sum/qti-sum.js.map +1 -1
  109. package/dist/components/qti-truncate/qti-truncate.d.ts +12 -0
  110. package/dist/components/qti-truncate/qti-truncate.js +38 -0
  111. package/dist/components/qti-truncate/qti-truncate.js.map +1 -0
  112. package/package.json +3 -3
@@ -0,0 +1,13 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-duration-lt operator compares two time durations.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#durationLT
5
+ *
6
+ * Takes 2 sub-expressions with base-type duration and single cardinality.
7
+ * Returns true if the first duration is shorter than the second.
8
+ * Special cases: Returns NULL if either argument is NULL; handles variable precision.
9
+ */
10
+ export declare class QtiDurationLt extends QtiExpression<boolean | null> {
11
+ #private;
12
+ getResult(): boolean | null;
13
+ }
@@ -0,0 +1,53 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-duration-lt operator compares two time durations.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#durationLT
5
+ *
6
+ * Takes 2 sub-expressions with base-type duration and single cardinality.
7
+ * Returns true if the first duration is shorter than the second.
8
+ * Special cases: Returns NULL if either argument is NULL; handles variable precision.
9
+ */
10
+ export class QtiDurationLt extends QtiExpression {
11
+ getResult() {
12
+ const values = this.#getDurationValues();
13
+ if (!values) {
14
+ return null;
15
+ }
16
+ return values[0] < values[1];
17
+ }
18
+ #getDurationValues() {
19
+ const variables = this.getVariables();
20
+ if (variables.length !== 2) {
21
+ console.error('qti-duration-lt requires exactly 2 duration expressions');
22
+ return null;
23
+ }
24
+ // TODO: Register the built-in duration variables (`duration` and `sectionId.duration`)
25
+ // from tracked candidate/session time-spent so these operators can resolve them implicitly.
26
+ const values = variables.map(variable => this.#parseDuration(variable));
27
+ if (values.some(value => value === null)) {
28
+ return null;
29
+ }
30
+ return values;
31
+ }
32
+ #parseDuration(variable) {
33
+ if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {
34
+ console.error('qti-duration-lt requires single cardinality');
35
+ return null;
36
+ }
37
+ if (variable.baseType !== 'duration') {
38
+ console.error('qti-duration-lt requires duration base-type');
39
+ return null;
40
+ }
41
+ if (variable.value === null || variable.value === undefined) {
42
+ return null;
43
+ }
44
+ const value = Number.parseFloat(variable.value.toString());
45
+ if (Number.isNaN(value)) {
46
+ console.error(`qti-duration-lt requires duration values expressed in seconds, got "${variable.value.toString()}"`);
47
+ return null;
48
+ }
49
+ return value;
50
+ }
51
+ }
52
+ customElements.define('qti-duration-lt', QtiDurationLt);
53
+ //# sourceMappingURL=qti-duration-lt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-duration-lt.js","sourceRoot":"","sources":["../../../src/components/qti-duration-lt/qti-duration-lt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,aAAc,SAAQ,aAA6B;IAC9C,SAAS;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACzC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,kBAAkB;QAChB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QAE5D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACzE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,uFAAuF;QACvF,4FAA4F;QAC5F,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,MAA0B,CAAC;IACpC,CAAC;IAED,cAAc,CAAC,QAA0B;QACvC,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACvE,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;YAC7D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;YAC7D,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,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC3D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,uEAAuE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACnH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-duration-lt operator compares two time durations.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#durationLT\n *\n * Takes 2 sub-expressions with base-type duration and single cardinality.\n * Returns true if the first duration is shorter than the second.\n * Special cases: Returns NULL if either argument is NULL; handles variable precision.\n */\nexport class QtiDurationLt extends QtiExpression<boolean | null> {\n public override getResult(): boolean | null {\n const values = this.#getDurationValues();\n if (!values) {\n return null;\n }\n\n return values[0] < values[1];\n }\n\n #getDurationValues(): [number, number] | null {\n const variables = this.getVariables() as ResponseVariable[];\n\n if (variables.length !== 2) {\n console.error('qti-duration-lt requires exactly 2 duration expressions');\n return null;\n }\n\n // TODO: Register the built-in duration variables (`duration` and `sectionId.duration`)\n // from tracked candidate/session time-spent so these operators can resolve them implicitly.\n const values = variables.map(variable => this.#parseDuration(variable));\n if (values.some(value => value === null)) {\n return null;\n }\n\n return values as [number, number];\n }\n\n #parseDuration(variable: ResponseVariable): number | null {\n if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {\n console.error('qti-duration-lt requires single cardinality');\n return null;\n }\n if (variable.baseType !== 'duration') {\n console.error('qti-duration-lt requires duration base-type');\n return null;\n }\n if (variable.value === null || variable.value === undefined) {\n return null;\n }\n\n const value = Number.parseFloat(variable.value.toString());\n if (Number.isNaN(value)) {\n console.error(`qti-duration-lt requires duration values expressed in seconds, got \"${variable.value.toString()}\"`);\n return null;\n }\n\n return value;\n }\n}\n\ncustomElements.define('qti-duration-lt', QtiDurationLt);\n"]}
@@ -1,4 +1,13 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-equal operator checks if two numerical expressions are equal.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#equal
5
+ *
6
+ * Takes 2 sub-expressions with numerical base-types and single cardinality.
7
+ * Supports tolerance-mode (exact, absolute, relative) for floating-point comparisons.
8
+ * Returns true if numerically equal within specified tolerance, false otherwise.
9
+ * Special cases: Returns NULL if either sub-expression is NULL.
10
+ */
2
11
  export declare class QtiEqual extends QtiExpression<boolean> {
3
12
  toleranceMode: 'exact' | 'relative' | 'absolute';
4
13
  getResult(): boolean;
@@ -7,6 +7,15 @@ 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-equal operator checks if two numerical expressions are equal.
12
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#equal
13
+ *
14
+ * Takes 2 sub-expressions with numerical base-types and single cardinality.
15
+ * Supports tolerance-mode (exact, absolute, relative) for floating-point comparisons.
16
+ * Returns true if numerically equal within specified tolerance, false otherwise.
17
+ * Special cases: Returns NULL if either sub-expression is NULL.
18
+ */
10
19
  export class QtiEqual extends QtiExpression {
11
20
  constructor() {
12
21
  super(...arguments);
@@ -17,6 +26,9 @@ export class QtiEqual extends QtiExpression {
17
26
  const values = this.getVariables();
18
27
  const value1 = values[0];
19
28
  const value2 = values[1];
29
+ if (!value1 || !value2) {
30
+ return null;
31
+ }
20
32
  if (this.toleranceMode !== 'exact') {
21
33
  console.error('toleranceMode is not supported yet');
22
34
  return false;
@@ -28,6 +40,9 @@ export class QtiEqual extends QtiExpression {
28
40
  console.error('unexpected cardinality in qti equal');
29
41
  return false;
30
42
  }
43
+ if (value1.value === null || value2.value === null || value1.value === undefined || value2.value === undefined) {
44
+ return null;
45
+ }
31
46
  return ScoringHelper.compareSingleValues(value1.value, value2.value, value1.baseType);
32
47
  }
33
48
  console.error('unexpected number of children in qti-equal');
@@ -1 +1 @@
1
- {"version":3,"file":"qti-equal.js","sourceRoot":"","sources":["../../../src/components/qti-equal/qti-equal.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;AAIrD,MAAM,OAAO,QAAS,SAAQ,aAAsB;IAApD;;QAC8B,kBAAa,GAAsC,OAAO,CAAC;IAyBzF,CAAC;IAvBiB,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,IAAI,IAAI,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;gBACpD,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IACE,MAAM,CAAC,WAAW,KAAK,QAAQ;gBAC/B,MAAM,CAAC,WAAW,KAAK,QAAQ;gBAC/B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;gBAC3B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAC3B,CAAC;gBACD,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;gBACrD,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO,aAAa,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAe,EAAE,MAAM,CAAC,KAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAzB6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CAA4D;AA2BzF,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,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';\n\nexport class QtiEqual extends QtiExpression<boolean> {\n @property({ type: String }) toleranceMode: 'exact' | 'relative' | 'absolute' = 'exact';\n\n public override getResult() {\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 (this.toleranceMode !== 'exact') {\n console.error('toleranceMode is not supported yet');\n return false;\n }\n if (\n value1.cardinality !== 'single' ||\n value2.cardinality !== 'single' ||\n Array.isArray(value1.value) ||\n Array.isArray(value2.value)\n ) {\n console.error('unexpected cardinality in qti equal');\n return false;\n }\n return ScoringHelper.compareSingleValues(value1.value as string, value2.value as string, value1.baseType);\n }\n console.error('unexpected number of children in qti-equal');\n return null;\n }\n}\n\ncustomElements.define('qti-equal', QtiEqual);\n"]}
1
+ {"version":3,"file":"qti-equal.js","sourceRoot":"","sources":["../../../src/components/qti-equal/qti-equal.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;AAIrD;;;;;;;;GAQG;AACH,MAAM,OAAO,QAAS,SAAQ,aAAsB;IAApD;;QAC8B,kBAAa,GAAsC,OAAO,CAAC;IAmCzF,CAAC;IAjCiB,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;YAEzB,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;gBACvB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,IAAI,IAAI,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;gBACpD,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IACE,MAAM,CAAC,WAAW,KAAK,QAAQ;gBAC/B,MAAM,CAAC,WAAW,KAAK,QAAQ;gBAC/B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;gBAC3B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAC3B,CAAC;gBACD,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;gBACrD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC/G,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO,aAAa,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAe,EAAE,MAAM,CAAC,KAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5G,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAnC6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CAA4D;AAqCzF,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,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';\n\n/**\n * @summary The qti-equal operator checks if two numerical expressions are equal.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#equal\n *\n * Takes 2 sub-expressions with numerical base-types and single cardinality.\n * Supports tolerance-mode (exact, absolute, relative) for floating-point comparisons.\n * Returns true if numerically equal within specified tolerance, false otherwise.\n * Special cases: Returns NULL if either sub-expression is NULL.\n */\nexport class QtiEqual extends QtiExpression<boolean> {\n @property({ type: String }) toleranceMode: 'exact' | 'relative' | 'absolute' = 'exact';\n\n public override getResult() {\n if (this.children.length === 2) {\n const values = this.getVariables() as ResponseVariable[];\n const value1 = values[0];\n const value2 = values[1];\n\n if (!value1 || !value2) {\n return null;\n }\n\n if (this.toleranceMode !== 'exact') {\n console.error('toleranceMode is not supported yet');\n return false;\n }\n if (\n value1.cardinality !== 'single' ||\n value2.cardinality !== 'single' ||\n Array.isArray(value1.value) ||\n Array.isArray(value2.value)\n ) {\n console.error('unexpected cardinality in qti equal');\n return false;\n }\n\n if (value1.value === null || value2.value === null || value1.value === undefined || value2.value === undefined) {\n return null;\n }\n\n return ScoringHelper.compareSingleValues(value1.value as string, value2.value as string, value1.baseType);\n }\n console.error('unexpected number of children in qti-equal');\n return null;\n }\n}\n\ncustomElements.define('qti-equal', QtiEqual);\n"]}
@@ -1,4 +1,13 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-equal-rounded operator compares two values after rounding.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#equalRounded
5
+ *
6
+ * Takes 2 sub-expressions with numerical base-types and single cardinality.
7
+ * Requires 'figures' and 'rounding-mode' (decimalPlaces or significantFigures) attributes.
8
+ * Returns true if equal after specified rounding, false otherwise.
9
+ * Special cases: Returns NULL if either sub-expression is NULL.
10
+ */
2
11
  export declare class QtiEqualRounded extends QtiExpression<boolean> {
3
12
  roundingMode: 'decimalPlaces' | 'significantFigures';
4
13
  get figures(): number;
@@ -6,6 +6,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { property } from 'lit/decorators.js';
8
8
  import { QtiExpression } from '@qti-components/base';
9
+ /**
10
+ * @summary The qti-equal-rounded operator compares two values after rounding.
11
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#equalRounded
12
+ *
13
+ * Takes 2 sub-expressions with numerical base-types and single cardinality.
14
+ * Requires 'figures' and 'rounding-mode' (decimalPlaces or significantFigures) attributes.
15
+ * Returns true if equal after specified rounding, false otherwise.
16
+ * Special cases: Returns NULL if either sub-expression is NULL.
17
+ */
9
18
  export class QtiEqualRounded extends QtiExpression {
10
19
  constructor() {
11
20
  super(...arguments);
@@ -1 +1 @@
1
- {"version":3,"file":"qti-equal-rounded.js","sourceRoot":"","sources":["../../../src/components/qti-equal-rounded/qti-equal-rounded.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\nexport class QtiEqualRounded extends QtiExpression<boolean> {\n @property({ type: String }) roundingMode: 'decimalPlaces' | 'significantFigures' = 'significantFigures';\n\n get figures() {\n const attr = this.getAttribute('figures');\n if (!attr) {\n console.error('figures attribute is missing');\n return null;\n }\n const figures = parseInt(this.getAttribute('figures') || '0');\n if (isNaN(figures)) {\n console.error('figures attribute is not a number');\n return null;\n }\n if (figures < 0) {\n console.error('figures attribute is negative');\n return null;\n }\n if (figures < 1 && this.roundingMode === 'significantFigures') {\n console.error('figures cannot be smaller than 1 for RoundingMode significantFigures');\n return null;\n }\n return figures;\n }\n\n public override getResult() {\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 (this.roundingMode === null) {\n return null;\n }\n if (\n value1.cardinality !== 'single' ||\n value2.cardinality !== 'single' ||\n Array.isArray(value1.value) ||\n Array.isArray(value2.value)\n ) {\n console.error('unexpected cardinality in qti equal');\n return false;\n }\n switch (values[0].baseType) {\n case 'integer':\n case 'float': {\n const float1 = parseFloat(value1.value as string);\n const float2 = parseFloat(value2.value as string);\n\n if (!isNaN(float1) && !isNaN(float2)) {\n if (this.roundingMode === 'significantFigures') {\n return float1.toPrecision(this.figures) === float2.toPrecision(this.figures);\n } else {\n return (\n Math.round(float1 * Math.pow(10, this.figures)) / Math.pow(10, this.figures) ===\n Math.round(float2 * Math.pow(10, this.figures)) / Math.pow(10, this.figures)\n );\n }\n } else {\n console.error(`value cannot be casted to numeric value in equalRounded operator: ${float1}, ${float2}`);\n }\n break;\n }\n default: {\n console.error(`values other than float and int cannot be used in equalRounded operator.`);\n break;\n }\n }\n return false;\n }\n console.error('unexpected number of children in qti-equal-rounded');\n return null;\n }\n}\n\ncustomElements.define('qti-equal-rounded', QtiEqualRounded);\n"]}
1
+ {"version":3,"file":"qti-equal-rounded.js","sourceRoot":"","sources":["../../../src/components/qti-equal-rounded/qti-equal-rounded.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\n/**\n * @summary The qti-equal-rounded operator compares two values after rounding.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#equalRounded\n *\n * Takes 2 sub-expressions with numerical base-types and single cardinality.\n * Requires 'figures' and 'rounding-mode' (decimalPlaces or significantFigures) attributes.\n * Returns true if equal after specified rounding, false otherwise.\n * Special cases: Returns NULL if either sub-expression is NULL.\n */\nexport class QtiEqualRounded extends QtiExpression<boolean> {\n @property({ type: String }) roundingMode: 'decimalPlaces' | 'significantFigures' = 'significantFigures';\n\n get figures() {\n const attr = this.getAttribute('figures');\n if (!attr) {\n console.error('figures attribute is missing');\n return null;\n }\n const figures = parseInt(this.getAttribute('figures') || '0');\n if (isNaN(figures)) {\n console.error('figures attribute is not a number');\n return null;\n }\n if (figures < 0) {\n console.error('figures attribute is negative');\n return null;\n }\n if (figures < 1 && this.roundingMode === 'significantFigures') {\n console.error('figures cannot be smaller than 1 for RoundingMode significantFigures');\n return null;\n }\n return figures;\n }\n\n public override getResult() {\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 (this.roundingMode === null) {\n return null;\n }\n if (\n value1.cardinality !== 'single' ||\n value2.cardinality !== 'single' ||\n Array.isArray(value1.value) ||\n Array.isArray(value2.value)\n ) {\n console.error('unexpected cardinality in qti equal');\n return false;\n }\n switch (values[0].baseType) {\n case 'integer':\n case 'float': {\n const float1 = parseFloat(value1.value as string);\n const float2 = parseFloat(value2.value as string);\n\n if (!isNaN(float1) && !isNaN(float2)) {\n if (this.roundingMode === 'significantFigures') {\n return float1.toPrecision(this.figures) === float2.toPrecision(this.figures);\n } else {\n return (\n Math.round(float1 * Math.pow(10, this.figures)) / Math.pow(10, this.figures) ===\n Math.round(float2 * Math.pow(10, this.figures)) / Math.pow(10, this.figures)\n );\n }\n } else {\n console.error(`value cannot be casted to numeric value in equalRounded operator: ${float1}, ${float2}`);\n }\n break;\n }\n default: {\n console.error(`values other than float and int cannot be used in equalRounded operator.`);\n break;\n }\n }\n return false;\n }\n console.error('unexpected number of children in qti-equal-rounded');\n return null;\n }\n}\n\ncustomElements.define('qti-equal-rounded', QtiEqualRounded);\n"]}
@@ -1,4 +1,12 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-field-value operator retrieves a specific field from a record.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#fieldValue
5
+ *
6
+ * Takes a sub-expression with record cardinality. 'field-identifier' identifies the field.
7
+ * Returns the value of the specified field.
8
+ * Special cases: Returns NULL if sub-expression is NULL or field does not exist.
9
+ */
2
10
  export declare class QtiFieldValue extends QtiExpression<string | string[]> {
3
11
  getResult(): any;
4
12
  }
@@ -1,4 +1,12 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-field-value operator retrieves a specific field from a record.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#fieldValue
5
+ *
6
+ * Takes a sub-expression with record cardinality. 'field-identifier' identifies the field.
7
+ * Returns the value of the specified field.
8
+ * Special cases: Returns NULL if sub-expression is NULL or field does not exist.
9
+ */
2
10
  export class QtiFieldValue extends QtiExpression {
3
11
  getResult() {
4
12
  const fieldIdentifier = this.getAttribute('field-identifier');
@@ -1 +1 @@
1
- {"version":3,"file":"qti-field-value.js","sourceRoot":"","sources":["../../../src/components/qti-field-value/qti-field-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,OAAO,aAAc,SAAQ,aAAgC;IACjD,SAAS;QACvB,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;QAE9D,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,gEAAgE;QAChE,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAyB,CAAC;QAExE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,QAAQ,GAAI,IAAI,CAAC,YAAY,EAAyB,CAAC,CAAC,CAAC,CAAC;QAEhE,yCAAyC;QACzC,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,yBAAyB;QACzB,MAAM,UAAU,GAAI,QAAQ,CAAC,KAA6B,CAAC,eAAe,CAAC,CAAC;QAE5E,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,UAAU,eAAe,uBAAuB,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiFieldValue extends QtiExpression<string | string[]> {\n public override getResult() {\n const fieldIdentifier = this.getAttribute('field-identifier');\n\n if (!fieldIdentifier) {\n throw new Error('field-identifier attribute is required');\n }\n\n // Get the result from the child expression (should be a record)\n const childElements = Array.from(this.children) as QtiExpression<any>[];\n\n if (childElements.length !== 1) {\n throw new Error('qti-field-value must have exactly one child expression');\n }\n\n const variable = (this.getVariables() as ResponseVariable[])[0];\n\n // Check if the result is a record/object\n if (variable.baseType !== 'record' || variable.value === null) {\n throw new Error('qti-field-value child expression must return a record');\n }\n\n // Return the field value\n const fieldValue = (variable.value as Record<string, any>)[fieldIdentifier];\n\n if (fieldValue === undefined) {\n throw new Error(`Field \"${fieldIdentifier}\" not found in record`);\n }\n\n return fieldValue;\n }\n}\n\ncustomElements.define('qti-field-value', QtiFieldValue);\n"]}
1
+ {"version":3,"file":"qti-field-value.js","sourceRoot":"","sources":["../../../src/components/qti-field-value/qti-field-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,aAAc,SAAQ,aAAgC;IACjD,SAAS;QACvB,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;QAE9D,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,gEAAgE;QAChE,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAyB,CAAC;QAExE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,QAAQ,GAAI,IAAI,CAAC,YAAY,EAAyB,CAAC,CAAC,CAAC,CAAC;QAEhE,yCAAyC;QACzC,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,yBAAyB;QACzB,MAAM,UAAU,GAAI,QAAQ,CAAC,KAA6B,CAAC,eAAe,CAAC,CAAC;QAE5E,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,UAAU,eAAe,uBAAuB,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-field-value operator retrieves a specific field from a record.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#fieldValue\n *\n * Takes a sub-expression with record cardinality. 'field-identifier' identifies the field.\n * Returns the value of the specified field.\n * Special cases: Returns NULL if sub-expression is NULL or field does not exist.\n */\nexport class QtiFieldValue extends QtiExpression<string | string[]> {\n public override getResult() {\n const fieldIdentifier = this.getAttribute('field-identifier');\n\n if (!fieldIdentifier) {\n throw new Error('field-identifier attribute is required');\n }\n\n // Get the result from the child expression (should be a record)\n const childElements = Array.from(this.children) as QtiExpression<any>[];\n\n if (childElements.length !== 1) {\n throw new Error('qti-field-value must have exactly one child expression');\n }\n\n const variable = (this.getVariables() as ResponseVariable[])[0];\n\n // Check if the result is a record/object\n if (variable.baseType !== 'record' || variable.value === null) {\n throw new Error('qti-field-value child expression must return a record');\n }\n\n // Return the field value\n const fieldValue = (variable.value as Record<string, any>)[fieldIdentifier];\n\n if (fieldValue === undefined) {\n throw new Error(`Field \"${fieldIdentifier}\" not found in record`);\n }\n\n return fieldValue;\n }\n}\n\ncustomElements.define('qti-field-value', QtiFieldValue);\n"]}
@@ -1,4 +1,12 @@
1
1
  import { QtiExpression } from '@qti-components/base';
2
+ /**
3
+ * @summary The qti-index operator retrieves a specific item from an ordered container.
4
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#index
5
+ *
6
+ * Takes 1 ordered container sub-expression; 'n' attribute specifies 1-based index.
7
+ * Returns the nth value from the container with original base-type and single cardinality.
8
+ * Special cases: Returns NULL if container is NULL or n exceeds container size.
9
+ */
2
10
  export declare class QtiIndex extends QtiExpression<any> {
3
11
  #private;
4
12
  n: string;
@@ -6,6 +6,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { customElement, property } from 'lit/decorators.js';
8
8
  import { QtiExpression } from '@qti-components/base';
9
+ /**
10
+ * @summary The qti-index operator retrieves a specific item from an ordered container.
11
+ * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#index
12
+ *
13
+ * Takes 1 ordered container sub-expression; 'n' attribute specifies 1-based index.
14
+ * Returns the nth value from the container with original base-type and single cardinality.
15
+ * Special cases: Returns NULL if container is NULL or n exceeds container size.
16
+ */
9
17
  let QtiIndex = class QtiIndex extends QtiExpression {
10
18
  getResult() {
11
19
  if (!this.n) {
@@ -1 +1 @@
1
- {"version":3,"file":"qti-index.js","sourceRoot":"","sources":["../../../src/components/qti-index/qti-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { customElement, property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { integer } from '@qti-components/base';\nimport type { ResponseVariable } from '@qti-components/base';\n\n@customElement('qti-index')\nexport class QtiIndex extends QtiExpression<any> {\n @property({ type: String })\n n!: string; // Required attribute, can be a number or an identifier\n\n public override getResult(): any {\n if (!this.n) {\n console.error('qti-index: missing required attribute \"n\"');\n return null;\n }\n\n // Check if there is exactly one child\n if (this.children.length !== 1) {\n console.error('qti-index: must have exactly one child container element');\n return null;\n }\n\n // Get the container from the child\n const containerVariable = this.getVariables()[0] as ResponseVariable;\n if (!containerVariable) {\n console.error('qti-index: missing container');\n return null;\n }\n\n // Determine the index value - either from n as a direct number or by looking up identifier\n let index: number;\n\n if (!isNaN(Number(this.n))) {\n // n is a direct number\n index = Number(this.n);\n } else {\n // n is an identifier - need to look up its value at runtime\n // This would require access to the QTI runtime context to resolve variables\n const variableValue = this.#lookupVariableValue(this.n);\n if (variableValue === null) {\n console.error(`qti-index: variable \"${this.n}\" is not a valid number`);\n return null;\n }\n index = Number(variableValue);\n }\n\n // Check if index is a positive integer\n if (index <= 0 || !Number.isInteger(index)) {\n console.error('qti-index: index must be a positive integer');\n return null;\n }\n\n // Check if container has ordered values\n if (containerVariable.cardinality === 'ordered') {\n const containerValues = Array.isArray(containerVariable.value)\n ? containerVariable.value\n : [containerVariable.value];\n\n // Index out of bounds or container is NULL\n if (containerVariable.value === null || index > containerValues.length) {\n return null;\n }\n\n // Return the nth value (index is 1-based)\n return containerValues[index - 1];\n } else {\n console.error('qti-index: child must have ordered cardinality');\n return null;\n }\n }\n\n // Helper method to look up a variable value by identifier\n // This would need to be implemented based on your actual QTI runtime environment\n #lookupVariableValue(identifier: string): integer | null {\n const value = this.context.variables.find(v => v.identifier === identifier)?.value;\n // check if value is a number\n if (value === null || isNaN(Number(value))) {\n return null;\n }\n return Number(value) as integer;\n }\n}\n"]}
1
+ {"version":3,"file":"qti-index.js","sourceRoot":"","sources":["../../../src/components/qti-index/qti-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { customElement, property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { integer } from '@qti-components/base';\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-index operator retrieves a specific item from an ordered container.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#index\n *\n * Takes 1 ordered container sub-expression; 'n' attribute specifies 1-based index.\n * Returns the nth value from the container with original base-type and single cardinality.\n * Special cases: Returns NULL if container is NULL or n exceeds container size.\n */\n@customElement('qti-index')\nexport class QtiIndex extends QtiExpression<any> {\n @property({ type: String })\n n!: string; // Required attribute, can be a number or an identifier\n\n public override getResult(): any {\n if (!this.n) {\n console.error('qti-index: missing required attribute \"n\"');\n return null;\n }\n\n // Check if there is exactly one child\n if (this.children.length !== 1) {\n console.error('qti-index: must have exactly one child container element');\n return null;\n }\n\n // Get the container from the child\n const containerVariable = this.getVariables()[0] as ResponseVariable;\n if (!containerVariable) {\n console.error('qti-index: missing container');\n return null;\n }\n\n // Determine the index value - either from n as a direct number or by looking up identifier\n let index: number;\n\n if (!isNaN(Number(this.n))) {\n // n is a direct number\n index = Number(this.n);\n } else {\n // n is an identifier - need to look up its value at runtime\n // This would require access to the QTI runtime context to resolve variables\n const variableValue = this.#lookupVariableValue(this.n);\n if (variableValue === null) {\n console.error(`qti-index: variable \"${this.n}\" is not a valid number`);\n return null;\n }\n index = Number(variableValue);\n }\n\n // Check if index is a positive integer\n if (index <= 0 || !Number.isInteger(index)) {\n console.error('qti-index: index must be a positive integer');\n return null;\n }\n\n // Check if container has ordered values\n if (containerVariable.cardinality === 'ordered') {\n const containerValues = Array.isArray(containerVariable.value)\n ? containerVariable.value\n : [containerVariable.value];\n\n // Index out of bounds or container is NULL\n if (containerVariable.value === null || index > containerValues.length) {\n return null;\n }\n\n // Return the nth value (index is 1-based)\n return containerValues[index - 1];\n } else {\n console.error('qti-index: child must have ordered cardinality');\n return null;\n }\n }\n\n // Helper method to look up a variable value by identifier\n // This would need to be implemented based on your actual QTI runtime environment\n #lookupVariableValue(identifier: string): integer | null {\n const value = this.context.variables.find(v => v.identifier === identifier)?.value;\n // check if value is a number\n if (value === null || isNaN(Number(value))) {\n return null;\n }\n return Number(value) as integer;\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { QtiExpression } from '@qti-components/base';
2
+ export declare class QtiInside extends QtiExpression<boolean | null> {
3
+ #private;
4
+ shape: string;
5
+ coords: string;
6
+ getResult(): boolean | null;
7
+ }
@@ -0,0 +1,141 @@
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 &&
125
+ point.x < ((xj - xi) * (point.y - yi)) / ((yj - yi) || Number.EPSILON) + xi;
126
+ if (intersects) {
127
+ inside = !inside;
128
+ }
129
+ previous = current;
130
+ }
131
+ return inside;
132
+ }
133
+ }
134
+ __decorate([
135
+ property({ type: String })
136
+ ], QtiInside.prototype, "shape", void 0);
137
+ __decorate([
138
+ property({ type: String })
139
+ ], QtiInside.prototype, "coords", void 0);
140
+ customElements.define('qti-inside', QtiInside);
141
+ //# 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 &&\n 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\ncustomElements.define('qti-inside', QtiInside);\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,48 @@
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
+ customElements.define('qti-integer-divide', QtiIntegerDivide);
48
+ //# 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;AAED,cAAc,CAAC,MAAM,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC","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\ncustomElements.define('qti-integer-divide', QtiIntegerDivide);\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,48 @@
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
+ customElements.define('qti-integer-modulus', QtiIntegerModulus);
48
+ //# sourceMappingURL=qti-integer-modulus.js.map