@qti-components/processing 1.6.1-next.4 → 1.6.1-next.5

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.
@@ -19,8 +19,9 @@ export class QtiMapResponsePoint extends QtiExpression {
19
19
  console.warn(`Area mapping not found for response ${this.identifier}`);
20
20
  return null;
21
21
  }
22
- const candidateResponses = !Array.isArray(response.value) ? [response.value] : response.value;
23
- if (!candidateResponses || candidateResponses.length === 0) {
22
+ // An unanswered single response is null, not an empty list: it scores the default, not a crash.
23
+ const candidateResponses = (!Array.isArray(response.value) ? [response.value] : response.value).filter((value) => typeof value === 'string' && value.length > 0);
24
+ if (candidateResponses.length === 0) {
24
25
  console.warn(`No candidate responses for response ${this.identifier}`);
25
26
  return null;
26
27
  }
@@ -1 +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":"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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';\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 // First match wins: \"each area is tested in turn, with those listed first taking priority\n // in the case where areas overlap and a point falls in the intersection\" (QTI 3.0 §7.4).\n // Without this the point would also score every later area it happens to fall in — which\n // only became reachable once `shape=\"default\"`, an area covering the whole image, started\n // matching (Citolab/qti-components#83).\n break;\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"]}
1
+ {"version":3,"file":"qti-map-response-point.js","sourceRoot":"","sources":["../../../src/components/qti-map-response-point/qti-map-response-point.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';\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 // An unanswered single response is null, not an empty list: it scores the default, not a crash.\n const candidateResponses = (!Array.isArray(response.value) ? [response.value] : response.value).filter(\n (value): value is string => typeof value === 'string' && value.length > 0\n );\n if (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 // First match wins: \"each area is tested in turn, with those listed first taking priority\n // in the case where areas overlap and a point falls in the intersection\" (QTI 3.0 §7.4).\n // Without this the point would also score every later area it happens to fall in — which\n // only became reachable once `shape=\"default\"`, an area covering the whole image, started\n // matching (Citolab/qti-components#83).\n break;\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"]}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@qti-components/processing",
3
3
  "description": "QTI processing utilities",
4
- "version": "1.6.1-next.4",
4
+ "version": "1.6.1-next.5",
5
5
  "author": "",
6
6
  "dependencies": {
7
- "@qti-components/base": "^3.0.0-next.4",
7
+ "@qti-components/base": "^3.0.0-next.6",
8
8
  "@qti-components/utilities": "^1.3.3"
9
9
  },
10
10
  "devDependencies": {