@conform-ed/qti-react 0.0.17 → 0.0.19

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.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export declare const qtiReactPackageName = "@conform-ed/qti-react";
2
2
  export { v0ContentModel, v0InteractionKinds, isAllowedFlowElement, isInteractionKind, sanitizeAttributes, type ContentModel, type V0InteractionKind, } from "./content-model";
3
3
  export { foldString, mapResponse, matchCorrect, mapResponsePoint, scoreResponse } from "./response-processing";
4
+ export { effectiveItemScore, type EffectiveItemScore } from "./item-score";
4
5
  export { assessmentItemViewFromNormalized, assessmentTestViewFromNormalized, stimulusContentFromNormalized, } from "./normalized-item";
6
+ export { referenceInteractionKinds, reportItemCapability, type ItemCapabilityOptions } from "./item-capability";
5
7
  export { formatPoint, parseCoords, parsePoint, pointInShape, type Point, type QtiShape } from "./graphic";
6
8
  export { applyCorrectResponseOverrides, collectRpIssues, collectTemplateIssues, executeResponseProcessing, executeTemplateProcessing, mulberry32, resolveTemplate, } from "./rp";
7
9
  export type { CustomOperatorImplementation, InterpolationTableEntryView, InterpolationTableView, MatchTableEntryView, MatchTableView, MaybeRpValue, OutcomeDeclarationView, OutcomeValue, ResponseNormalization, ResponseProcessingContext, ResponseProcessingResult, ResponseProcessingView, RpConditionBranch, RpExpressionView, RpRecordField, RpRuleView, RpScalar, RpValue, TemplateConditionBranch, TemplateDeclarationView, TemplateProcessingContext, TemplateProcessingResult, TemplateProcessingView, TemplateRuleView, } from "./rp";
package/dist/index.js CHANGED
@@ -387,6 +387,23 @@ function scoreResponse(declaration, response, normalize) {
387
387
  correct
388
388
  };
389
389
  }
390
+ // src/item-score.ts
391
+ function numericOutcome(value) {
392
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
393
+ }
394
+ function effectiveItemScore(scores, outcomes) {
395
+ const scoreOutcome = numericOutcome(outcomes["SCORE"]);
396
+ const maxOutcome = numericOutcome(outcomes["MAXSCORE"]);
397
+ const summedMax = scores.reduce((total, score) => total + score.maxScore, 0);
398
+ if (scoreOutcome !== null) {
399
+ return { raw: scoreOutcome, max: maxOutcome ?? summedMax, fromOutcomes: true };
400
+ }
401
+ return {
402
+ raw: scores.reduce((total, score) => total + score.score, 0),
403
+ max: maxOutcome ?? summedMax,
404
+ fromOutcomes: false
405
+ };
406
+ }
390
407
  // src/normalized-item.ts
391
408
  function isRecord(value) {
392
409
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2930,6 +2947,127 @@ function collectTemplateIssues(view, options) {
2930
2947
  walkRules(view.rules);
2931
2948
  return issues;
2932
2949
  }
2950
+ // src/item-capability.ts
2951
+ var feedbackKinds = new Set(["feedbackInline", "feedbackBlock"]);
2952
+ var templateContentKinds = new Set(["templateInline", "templateBlock"]);
2953
+ var intrinsicLeafKinds = new Set(["text", "printedVariable"]);
2954
+ function isFeedbackNode(node) {
2955
+ return feedbackKinds.has(node.kind);
2956
+ }
2957
+ function isTemplateContentNode(node) {
2958
+ return templateContentKinds.has(node.kind);
2959
+ }
2960
+ function isInteractionNode(node) {
2961
+ return node.kind !== "xml" && typeof node.responseIdentifier === "string";
2962
+ }
2963
+ function reportItemCapability(item, options) {
2964
+ const model = options.model ?? v0ContentModel;
2965
+ const customOperatorClasses = options.customOperatorClasses ?? new Set;
2966
+ const issues = [];
2967
+ const seen = new Set;
2968
+ function report(issue) {
2969
+ const dedupeKey = `${issue.type}:${issue.name}:${issue.responseIdentifier ?? ""}`;
2970
+ if (!seen.has(dedupeKey)) {
2971
+ seen.add(dedupeKey);
2972
+ issues.push(issue);
2973
+ }
2974
+ }
2975
+ function walk(node) {
2976
+ if (isFeedbackNode(node) || isTemplateContentNode(node) || node.kind === "rubricBlock") {
2977
+ for (const child of node.content ?? []) {
2978
+ walk(child);
2979
+ }
2980
+ return;
2981
+ }
2982
+ if (isInteractionNode(node)) {
2983
+ if (!options.supportedInteractions.has(node.kind)) {
2984
+ report({ type: "unsupported-interaction", name: node.kind, responseIdentifier: node.responseIdentifier });
2985
+ return;
2986
+ }
2987
+ const schema = options.interactionSchemas?.get(node.kind);
2988
+ if (schema) {
2989
+ const parsed = schema.safeParse(node);
2990
+ if (!parsed.success) {
2991
+ const detail = parsed.error.issues[0]?.message;
2992
+ report({
2993
+ type: "invalid-interaction",
2994
+ name: node.kind,
2995
+ responseIdentifier: node.responseIdentifier,
2996
+ ...detail !== undefined ? { detail } : {}
2997
+ });
2998
+ }
2999
+ }
3000
+ return;
3001
+ }
3002
+ if (node.kind === "xml") {
3003
+ const xmlNode = node;
3004
+ if (xmlNode.name === model.mathRoot) {
3005
+ return;
3006
+ }
3007
+ if (!isAllowedFlowElement(model, xmlNode.name)) {
3008
+ report({ type: "unsupported-element", name: xmlNode.name });
3009
+ }
3010
+ for (const child of xmlNode.children ?? []) {
3011
+ walk(child);
3012
+ }
3013
+ return;
3014
+ }
3015
+ if (intrinsicLeafKinds.has(node.kind)) {
3016
+ return;
3017
+ }
3018
+ report({ type: "unsupported-element", name: node.kind });
3019
+ }
3020
+ for (const node of item.itemBody.content ?? []) {
3021
+ walk(node);
3022
+ }
3023
+ for (const ref of item.assessmentStimulusRefs ?? []) {
3024
+ const stimulus = options.resolveStimulus?.(ref) ?? null;
3025
+ if (stimulus === null) {
3026
+ report({ type: "unsupported-element", name: "assessmentStimulusRef", detail: ref.href });
3027
+ continue;
3028
+ }
3029
+ for (const node of stimulus.content) {
3030
+ walk(node);
3031
+ }
3032
+ }
3033
+ for (const feedback of item.modalFeedbacks ?? []) {
3034
+ for (const child of feedback.content ?? []) {
3035
+ walk(child);
3036
+ }
3037
+ }
3038
+ for (const issue of collectRpIssues(item.responseProcessing, {
3039
+ customOperatorClasses,
3040
+ outcomeDeclarations: item.outcomeDeclarations ?? []
3041
+ })) {
3042
+ report(issue);
3043
+ }
3044
+ for (const issue of collectTemplateIssues(item.templateProcessing, { customOperatorClasses })) {
3045
+ report(issue);
3046
+ }
3047
+ return { deliverable: issues.length === 0, issues };
3048
+ }
3049
+ var referenceInteractionKinds = [
3050
+ "associateInteraction",
3051
+ "choiceInteraction",
3052
+ "drawingInteraction",
3053
+ "endAttemptInteraction",
3054
+ "extendedTextInteraction",
3055
+ "gapMatchInteraction",
3056
+ "graphicAssociateInteraction",
3057
+ "graphicGapMatchInteraction",
3058
+ "graphicOrderInteraction",
3059
+ "hotspotInteraction",
3060
+ "hottextInteraction",
3061
+ "inlineChoiceInteraction",
3062
+ "matchInteraction",
3063
+ "mediaInteraction",
3064
+ "orderInteraction",
3065
+ "positionObjectStage",
3066
+ "selectPointInteraction",
3067
+ "sliderInteraction",
3068
+ "textEntryInteraction",
3069
+ "uploadInteraction"
3070
+ ];
2933
3071
  // src/response-validity.ts
2934
3072
  var countConstraintKinds = ["minChoices", "maxChoices", "minAssociations", "maxAssociations", "minStrings"];
2935
3073
  function collectInteractionConstraints(content) {
@@ -4669,22 +4807,21 @@ function responseIncludes(value, optionIdentifier) {
4669
4807
  function isCorrectOption(declaration, optionIdentifier) {
4670
4808
  return Boolean(declaration?.correctResponse?.values.some((entry) => entry.value === optionIdentifier));
4671
4809
  }
4672
- function isInteractionNode(node) {
4810
+ function isInteractionNode2(node) {
4673
4811
  return node.kind !== "xml" && typeof node.responseIdentifier === "string";
4674
4812
  }
4675
- var feedbackKinds = new Set(["feedbackInline", "feedbackBlock"]);
4676
- function isFeedbackNode(node) {
4677
- return feedbackKinds.has(node.kind);
4813
+ var feedbackKinds2 = new Set(["feedbackInline", "feedbackBlock"]);
4814
+ function isFeedbackNode2(node) {
4815
+ return feedbackKinds2.has(node.kind);
4678
4816
  }
4679
- var templateContentKinds = new Set(["templateInline", "templateBlock"]);
4680
- function isTemplateContentNode(node) {
4681
- return templateContentKinds.has(node.kind);
4817
+ var templateContentKinds2 = new Set(["templateInline", "templateBlock"]);
4818
+ function isTemplateContentNode2(node) {
4819
+ return templateContentKinds2.has(node.kind);
4682
4820
  }
4683
4821
  function templateVisible(value, view) {
4684
4822
  const matched = Array.isArray(value) ? value.includes(view.identifier) : value === view.identifier;
4685
4823
  return matched !== (view.showHide === "hide");
4686
4824
  }
4687
- var intrinsicLeafKinds = new Set(["text", "printedVariable"]);
4688
4825
  function createStaticStore(outcomes) {
4689
4826
  const snapshot = {
4690
4827
  responses: {},
@@ -4782,13 +4919,13 @@ function createQtiRuntime(config) {
4782
4919
  if (override) {
4783
4920
  return createElement(Fragment, { key }, override(node, key));
4784
4921
  }
4785
- if (isInteractionNode(node)) {
4922
+ if (isInteractionNode2(node)) {
4786
4923
  if (descriptorsByKind.has(node.kind) && config.skin[node.kind]) {
4787
4924
  return createElement(InteractionHost, { key, node });
4788
4925
  }
4789
4926
  return renderUnsupported(node, key);
4790
4927
  }
4791
- if (isFeedbackNode(node)) {
4928
+ if (isFeedbackNode2(node)) {
4792
4929
  return createElement(FeedbackHost, {
4793
4930
  key,
4794
4931
  feedback: node,
@@ -4796,7 +4933,7 @@ function createQtiRuntime(config) {
4796
4933
  overrides
4797
4934
  });
4798
4935
  }
4799
- if (isTemplateContentNode(node)) {
4936
+ if (isTemplateContentNode2(node)) {
4800
4937
  return createElement(TemplateContentHost, {
4801
4938
  key,
4802
4939
  view: node,
@@ -5039,91 +5176,15 @@ function createQtiRuntime(config) {
5039
5176
  return catalogIdref !== undefined ? catalogSupports.get(catalogIdref) ?? noSupports : noSupports;
5040
5177
  }
5041
5178
  function canDeliver(item) {
5042
- const issues = [];
5043
- const seen = new Set;
5044
- function report(issue) {
5045
- const dedupeKey = `${issue.type}:${issue.name}:${issue.responseIdentifier ?? ""}`;
5046
- if (!seen.has(dedupeKey)) {
5047
- seen.add(dedupeKey);
5048
- issues.push(issue);
5049
- }
5050
- }
5051
- function walk(node) {
5052
- if (isFeedbackNode(node) || isTemplateContentNode(node) || node.kind === "rubricBlock") {
5053
- for (const child of node.content ?? []) {
5054
- walk(child);
5055
- }
5056
- return;
5057
- }
5058
- if (isInteractionNode(node)) {
5059
- const descriptor = descriptorsByKind.get(node.kind);
5060
- if (!descriptor || !config.skin[node.kind]) {
5061
- report({
5062
- type: "unsupported-interaction",
5063
- name: node.kind,
5064
- responseIdentifier: node.responseIdentifier
5065
- });
5066
- return;
5067
- }
5068
- const parsed = descriptor.schema.safeParse(node);
5069
- if (!parsed.success) {
5070
- const detail = parsed.error.issues[0]?.message;
5071
- report({
5072
- type: "invalid-interaction",
5073
- name: node.kind,
5074
- responseIdentifier: node.responseIdentifier,
5075
- ...detail !== undefined ? { detail } : {}
5076
- });
5077
- }
5078
- return;
5079
- }
5080
- if (node.kind === "xml") {
5081
- const xmlNode = node;
5082
- if (xmlNode.name === model.mathRoot) {
5083
- return;
5084
- }
5085
- if (!isAllowedFlowElement(model, xmlNode.name)) {
5086
- report({ type: "unsupported-element", name: xmlNode.name });
5087
- }
5088
- for (const child of xmlNode.children ?? []) {
5089
- walk(child);
5090
- }
5091
- return;
5092
- }
5093
- if (intrinsicLeafKinds.has(node.kind)) {
5094
- return;
5095
- }
5096
- report({ type: "unsupported-element", name: node.kind });
5097
- }
5098
- for (const node of item.itemBody.content ?? []) {
5099
- walk(node);
5100
- }
5101
- for (const ref of item.assessmentStimulusRefs ?? []) {
5102
- const stimulus = config.resolveStimulus?.(ref) ?? null;
5103
- if (stimulus === null) {
5104
- report({ type: "unsupported-element", name: "assessmentStimulusRef", detail: ref.href });
5105
- continue;
5106
- }
5107
- for (const node of stimulus.content) {
5108
- walk(node);
5109
- }
5110
- }
5111
- for (const feedback of item.modalFeedbacks ?? []) {
5112
- for (const child of feedback.content ?? []) {
5113
- walk(child);
5114
- }
5115
- }
5116
- const customOperatorClasses = new Set(Object.keys(config.customOperators ?? {}));
5117
- for (const issue of collectRpIssues(item.responseProcessing, {
5118
- customOperatorClasses,
5119
- outcomeDeclarations: item.outcomeDeclarations ?? []
5120
- })) {
5121
- report(issue);
5122
- }
5123
- for (const issue of collectTemplateIssues(item.templateProcessing, { customOperatorClasses })) {
5124
- report(issue);
5125
- }
5126
- return { deliverable: issues.length === 0, issues };
5179
+ const supportedInteractions = new Set([...descriptorsByKind.keys()].filter((kind) => Boolean(config.skin[kind])));
5180
+ const interactionSchemas = new Map([...descriptorsByKind].map(([kind, descriptor]) => [kind, descriptor.schema]));
5181
+ return reportItemCapability(item, {
5182
+ supportedInteractions,
5183
+ interactionSchemas,
5184
+ model,
5185
+ customOperatorClasses: new Set(Object.keys(config.customOperators ?? {})),
5186
+ ...config.resolveStimulus !== undefined ? { resolveStimulus: config.resolveStimulus } : {}
5187
+ });
5127
5188
  }
5128
5189
  return { ItemRenderer, ContentRenderer, useAttempt, useCatalogSupports, canDeliver };
5129
5190
  }
@@ -6758,7 +6819,9 @@ export {
6758
6819
  resolveTemplate,
6759
6820
  resolvePnpActivation,
6760
6821
  resolveCatalogSupports,
6822
+ reportItemCapability,
6761
6823
  referenceSkin,
6824
+ referenceInteractionKinds,
6762
6825
  qtiReactPackageName,
6763
6826
  qtiCoreInteractions,
6764
6827
  positionObjectStage,
@@ -6790,6 +6853,7 @@ export {
6790
6853
  executeTemplateProcessing,
6791
6854
  executeResponseProcessing,
6792
6855
  endAttemptInteraction,
6856
+ effectiveItemScore,
6793
6857
  drawingInteraction,
6794
6858
  defineInteraction,
6795
6859
  createTestSessionStore,
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Headless capability gate (ADR-0003): "can a runtime that supports `supportedInteractions`
3
+ * deliver this item, and if not, why" — extracted from the React runtime's `canDeliver`
4
+ * so server-side callers (e.g. an ingest pipeline) can reach the *same* decision without
5
+ * importing React. The React runtime delegates to this, passing the interaction set its
6
+ * descriptors + skins cover; a headless caller passes the set its delivery supports.
7
+ *
8
+ * This module is React-free by construction (content-model + RP collectors only; the view
9
+ * shapes are type-only imports), so it ships through the `@conform-ed/qti-react/headless`
10
+ * entry alongside the normalize → view adapters.
11
+ */
12
+ import type { ZodType } from "zod";
13
+ import type { CapabilityReport } from "./capability";
14
+ import { type ContentModel } from "./content-model";
15
+ import type { AssessmentItemView, AssessmentStimulusRefView, StimulusContentView } from "./runtime";
16
+ export interface ItemCapabilityOptions {
17
+ /** Interaction kinds the target runtime can render (descriptor + skin both present). */
18
+ readonly supportedInteractions: ReadonlySet<string>;
19
+ /** Content model deciding the flow-element allowlist + math root; defaults to v0. */
20
+ readonly model?: ContentModel;
21
+ /** Custom-operator classes the target runtime registers (for RP capability). */
22
+ readonly customOperatorClasses?: ReadonlySet<string>;
23
+ /** Resolver for shared-stimulus refs; unresolved refs are not deliverable. */
24
+ readonly resolveStimulus?: (ref: AssessmentStimulusRefView) => StimulusContentView | null;
25
+ /**
26
+ * Optional per-kind schemas for the stricter `invalid-interaction` check. The React
27
+ * runtime supplies its descriptor schemas; a headless caller that has already validated
28
+ * structure (e.g. against the qti-xml contracts schema) can omit them.
29
+ */
30
+ readonly interactionSchemas?: ReadonlyMap<string, ZodType>;
31
+ }
32
+ /**
33
+ * Report whether `item` can be delivered by a runtime with the given capabilities, and
34
+ * every reason it cannot. Pure and React-free; the React runtime's `canDeliver` is a thin
35
+ * wrapper over this.
36
+ */
37
+ export declare function reportItemCapability(item: AssessmentItemView, options: ItemCapabilityOptions): CapabilityReport;
38
+ /**
39
+ * Interaction kinds the bundled reference skin renders — the default "supported set" for
40
+ * callers that deliver with the reference skin. Kept in parity with the reference skin by
41
+ * a test; pass an explicit set to `reportItemCapability` for a custom delivery surface.
42
+ */
43
+ export declare const referenceInteractionKinds: readonly string[];
@@ -0,0 +1,17 @@
1
+ import type { ScoreResult } from "./types";
2
+ export interface EffectiveItemScore {
3
+ readonly raw: number;
4
+ readonly max: number;
5
+ /** True when SCORE came from the RP outcomes of record rather than per-variable scoring. */
6
+ readonly fromOutcomes: boolean;
7
+ }
8
+ /**
9
+ * The item score of record (QTI): a numeric SCORE outcome from response processing is
10
+ * authoritative — PCI/RP-scored items (e.g. math-entry) have no per-variable
11
+ * correctResponse basis, so their standard scores read 0. Summed per-variable standard
12
+ * scoring is the fallback for items without RP. MAXSCORE follows the same precedence.
13
+ *
14
+ * Pure and framework-light: client and server (authoritative finalize) share it so the
15
+ * grade of record is derived identically on both sides.
16
+ */
17
+ export declare function effectiveItemScore(scores: readonly ScoreResult[], outcomes: Readonly<Record<string, unknown>>): EffectiveItemScore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conform-ed/qti-react",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "files": [
5
5
  "src",
6
6
  "dist"
@@ -12,10 +12,15 @@
12
12
  "development": "./src/index.ts",
13
13
  "types": "./dist/index.d.ts",
14
14
  "import": "./dist/index.js"
15
+ },
16
+ "./headless": {
17
+ "development": "./src/headless.ts",
18
+ "types": "./dist/headless.d.ts",
19
+ "import": "./dist/headless.js"
15
20
  }
16
21
  },
17
22
  "scripts": {
18
- "build": "bun build ./src/index.ts --outdir dist --format esm --target browser --external react --external react-dom --external zod && tsgo -p tsconfig.build.json",
23
+ "build": "bun build ./src/index.ts ./src/headless.ts --outdir dist --format esm --target browser --external react --external react-dom --external zod && tsgo -p tsconfig.build.json",
19
24
  "format": "oxfmt --config ../../.oxfmtrc.jsonc --check .",
20
25
  "lint": "oxlint --config ../../.oxlintrc.jsonc .",
21
26
  "test": "bun test",
@@ -25,11 +30,11 @@
25
30
  "xspattern": "^3.1.0"
26
31
  },
27
32
  "devDependencies": {
28
- "@conform-ed/contracts": "0.0.17",
29
- "@conform-ed/qti-xml": "0.0.17",
33
+ "@conform-ed/contracts": "0.0.19",
34
+ "@conform-ed/qti-xml": "0.0.19",
30
35
  "@types/react": "^19.2.17",
31
36
  "@types/react-dom": "^19",
32
- "happy-dom": "^20.10.2",
37
+ "happy-dom": "^20.10.3",
33
38
  "react": "^19.2.7",
34
39
  "react-dom": "^19"
35
40
  },
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Headless (React-free) surface of @conform-ed/qti-react: the normalize → view adapters,
3
+ * the capability gate, and the **scoring engine** (Response Processing interpreter, the
4
+ * standard per-response scoring templates, the item-score aggregator, and the test-level
5
+ * outcome-processing controller). Importable on a server (e.g. a QTI ingest pipeline or an
6
+ * authoritative grade finalize) without pulling React. Exposed at
7
+ * `@conform-ed/qti-react/headless`; everything here is also re-exported from the package
8
+ * root for React consumers.
9
+ *
10
+ * Keep this entry free of React-coupled imports — every module re-exported here
11
+ * (./normalized-item, ./item-capability, ./response-processing, ./rp, ./item-score,
12
+ * ./store, ./test, ./response-validity) is verified framework-light.
13
+ */
14
+
15
+ export {
16
+ assessmentItemViewFromNormalized,
17
+ assessmentTestViewFromNormalized,
18
+ stimulusContentFromNormalized,
19
+ } from "./normalized-item";
20
+ export { referenceInteractionKinds, reportItemCapability, type ItemCapabilityOptions } from "./item-capability";
21
+
22
+ // The scoring engine, headless. Running these server-side re-derives the grade of record
23
+ // from the learner's raw responses + the (server-held) answer keys — see emergent ADR-0019.
24
+ export { foldString, mapResponse, matchCorrect, mapResponsePoint, scoreResponse } from "./response-processing";
25
+ export { effectiveItemScore, type EffectiveItemScore } from "./item-score";
26
+ export {
27
+ applyCorrectResponseOverrides,
28
+ collectRpIssues,
29
+ collectTemplateIssues,
30
+ executeResponseProcessing,
31
+ executeTemplateProcessing,
32
+ mulberry32,
33
+ resolveTemplate,
34
+ } from "./rp";
35
+ export type {
36
+ CustomOperatorImplementation,
37
+ OutcomeDeclarationView,
38
+ OutcomeValue,
39
+ ResponseNormalization,
40
+ ResponseProcessingContext,
41
+ ResponseProcessingResult,
42
+ ResponseProcessingView,
43
+ TemplateDeclarationView,
44
+ } from "./rp";
45
+ export { createAttemptStore, type AttemptSnapshot, type AttemptStore, type AttemptStoreOptions } from "./store";
46
+ export { createTestController, type TestController, type TestSessionState } from "./test";
47
+
48
+ export type { CapabilityIssue, CapabilityIssueType, CapabilityReport } from "./capability";
49
+ export type {
50
+ AssessmentItemView,
51
+ AssessmentStimulusRefView,
52
+ BodyNode,
53
+ InteractionNode,
54
+ StimulusContentView,
55
+ XmlContentNode,
56
+ } from "./runtime";
57
+ export type { AssessmentTestView } from "./test";
58
+ export type { Cardinality, ResponseDeclarationView, ResponseValue, ScoreResult } from "./types";
package/src/index.ts CHANGED
@@ -14,12 +14,16 @@ export {
14
14
 
15
15
  export { foldString, mapResponse, matchCorrect, mapResponsePoint, scoreResponse } from "./response-processing";
16
16
 
17
+ export { effectiveItemScore, type EffectiveItemScore } from "./item-score";
18
+
17
19
  export {
18
20
  assessmentItemViewFromNormalized,
19
21
  assessmentTestViewFromNormalized,
20
22
  stimulusContentFromNormalized,
21
23
  } from "./normalized-item";
22
24
 
25
+ export { referenceInteractionKinds, reportItemCapability, type ItemCapabilityOptions } from "./item-capability";
26
+
23
27
  export { formatPoint, parseCoords, parsePoint, pointInShape, type Point, type QtiShape } from "./graphic";
24
28
 
25
29
  export {