README.md
July 31, 2026 · View on GitHub
This package contains of type definitions for processing assessment data. Additionally, you find TypeScript interfaces and classes, so these data structures can be used in a coherent way.
Installation
npm i @iqb/responses
.NET 10
The repository also contains the native .NET package Iqb.Responses. It uses
the same camel-case JSON contracts and does not require Node.js at runtime.
dotnet add package Iqb.Responses --version 5.2.2-preview.1
using System.Text.Json;
using Iqb.Responses;
var scheme = CodingScheme.Parse(File.ReadAllText("coding-scheme.json"));
var responses = JsonSerializer.Deserialize<List<Response>>(
File.ReadAllText("responses.json"),
IqbJson.Options) ?? [];
var coded = CodingSchemeFactory.Code(responses, scheme.VariableCodings);
The native SOLVER supports numeric literals, null, booleans, parentheses,
arithmetic and comparison operators, ternary expressions, IQB placeholders,
fragment access, and the documented default/ERROR/INC policies. Its scalar
mathjs subset also includes:
- Constants:
pi/PI,e/E,tau,phi,Infinity, andNaN. - Numeric functions:
abs,sqrt,cbrt,ceil,floor,fix,round,sign,min,max,gcd,pow,mod,square,cube, andnthRoot. - Exponential and logarithmic functions:
exp,log,log10, andlog2. - Trigonometric functions:
sin,cos,tan,asin,acos,atan,atan2, andhypot.
Matrices, units, assignments, user-defined functions and other unrestricted
mathjs syntax are not supported. Unknown syntax, complex values and
non-finite final results produce DERIVE_ERROR. Transcendental functions can
differ from V8 by one final IEEE-754 bit because .NET and JavaScript use
different platform math implementations. Direct, finite SOLVER results that
use exp, logarithmic, trigonometric or hypot functions may differ by at
most one IEEE-754 ULP in differential tests. Status, error and downstream
coding results are still compared exactly. gcd requires at least two finite
integer arguments and is always compared exactly.
Number-to-string conversion and Unicode lowercasing follow JavaScript semantics
in both runtimes. MATCH_REGEX deliberately uses a portable ASCII subset:
character classes, groups, alternation and ordinary quantifiers are supported;
lookaround, backreferences, Unicode property classes, Unicode/hex escapes and
non-ASCII pattern text are rejected during validation and produce a controlled
coding error if validation is bypassed.
Differential parity testing
npm run test:differential compares all checked-in golden vectors and 20,000
reproducible generated cases with the native .NET implementation. A failure is
automatically minimized and written to artifacts/differential/. Replay it with
npm run test:differential:generated -- --case <minimized.request.json>.
Before a stable release, npm run test:differential:stress runs 100,000 cases.
Locale, Unicode, regex-dialect and SOLVER-language boundaries are tracked
separately in test/differential/boundaries/manifest.json. Large-number
formatting, Unicode lowercasing and rejection of non-portable regular
expressions are blocking parity cases.
Documentation
- Quick Reference Guide - Common operations, examples, and troubleshooting
- Coding Process Documentation - Detailed architecture and logic flow with diagrams
- Iqb specifications
- Ausführliche Darstellungen zum Kodieren
Public API (Exports)
The package exports (among others):
- Coding responses
CodingFactory(also exported asCodingEngine/ResponseCoder)CodingSchemeFactory(also exported asCodingSchemeEngine/SchemeCoder)
- Rendering / formatting
ToTextFactory(also exported asCodingTextRenderer/CodingFormatter)CodingSchemeTextFactory(also exported asCodingSchemeTextRenderer)
- Utilities
VariableList
Concepts
Core data model
Response(@iqbspecs/response)- Identified by
id(string) - Holds
value(single value or array) and astatus - May have
code,scoreand (optionally)subform
- Identified by
VariableCodingData(@iqbspecs/coding-scheme)- Defines how one variable is obtained and/or coded
- Important fields you will see often:
idandaliassourceType+deriveSources(for derived variables)codes+processing+fragmenting(for rule-based coding)
id vs alias
In many consuming applications variables are addressed by alias, while internally the coding scheme also has an id.
- When you call
CodingSchemeFactory.code(), responses are temporarily mapped from alias to id, processed, and mapped back. - When building tooling around this package, treat
aliasas the “external name” andidas the “stable internal key”.
Coding pipeline (high level)
CodingSchemeFactory.code() processes a list of responses together with a coding scheme and runs the following steps:
- Group by subform
- Responses with a
subformare coded per subform group.
- Responses with a
- Normalize statuses
- Some statuses are normalized to
VALUE_CHANGEDdepending on variable/source parameters.
- Some statuses are normalized to
- Resolve derived/base conflicts
- Base responses that are shadowed by derived variables can be removed before deriving/coding.
- Plan derivations
- A dependency graph is computed so derived variables are processed in the right order.
- Ensure responses exist
- If a variable is present in the coding scheme but missing from input responses, placeholder responses can be created.
- Derive values (if configured)
- Derived variables are computed from their source responses.
- Code values
- Rule-based coding is applied to responses with
status === VALUE_CHANGED.
- Rule-based coding is applied to responses with
Status and error handling
- Status strings are defined by the
@iqbspecs/response/@iqbspecs/coding-schemespecs and are used throughout this package. - Typical flow for base variables is:
VALUE_CHANGED->CODING_COMPLETE/CODING_INCOMPLETE/NO_CODING
- For derived variables:
- derivation may set
DERIVE_ERROR(and value is cleared)
- derivation may set
- If internal processing throws unexpectedly:
CODING_ERROR/DERIVE_ERRORis set and the optionalonErrorcallback is called.
Debugging & internal extension points
If you are working on the internals:
- Rule evaluation is implemented in
src/rule-engine/*. - Derivations are implemented in
src/derive/*. - Alias mapping lives in
src/mapping/alias-mapper.ts. - Subform grouping lives in
src/subform/*.
Quick start: code all responses of a unit
Use CodingSchemeFactory.code() to apply derivations (if configured in the coding scheme) and then apply coding rules.
import type { Response } from '@iqbspecs/response/response.interface';
import type { VariableCodingData } from '@iqbspecs/coding-scheme';
import { CodingSchemeFactory } from '@iqb/responses';
const responses: Response[] = [
{ id: 'A1', value: 'foo', status: 'VALUE_CHANGED' },
{ id: 'A2', value: 2, status: 'VALUE_CHANGED' }
];
const variableCodings: VariableCodingData[] = /* from a coding-scheme JSON */ [];
const coded = CodingSchemeFactory.code(responses, variableCodings, {
onError: (err) => {
// optional hook: called when derive/coding encounters unexpected errors
console.error(err);
}
});
Notes
- Aliases vs ids:
CodingSchemeFactory.code()maps response ids betweenaliasandidinternally and returns the final responses mapped back. - Subforms: responses may include a
subformproperty; coding is performed per subform group. - Missing responses: for variables that are present in the coding scheme but missing from
responses, placeholder responses may be created (except forsourceType: 'BASE_NO_VALUE').
Code a single response
If you already have a VariableCodingData for a base variable and want to code exactly one Response, use CodingFactory.code().
import type { Response } from '@iqbspecs/response/response.interface';
import type { VariableCodingData } from '@iqbspecs/coding-scheme';
import { CodingFactory } from '@iqb/responses';
const response: Response = { id: 'A1', value: 'foo', status: 'VALUE_CHANGED' };
const coding: VariableCodingData = /* coding for variable A1 */ {} as VariableCodingData;
const codedResponse = CodingFactory.code(response, coding);
Validate a coding scheme against base variables
import type { VariableInfo } from '@iqbspecs/variable-info/variable-info.interface';
import type { VariableCodingData } from '@iqbspecs/coding-scheme';
import { CodingSchemeFactory } from '@iqb/responses';
const baseVariables: VariableInfo[] = /* list of base variables */ [];
const codingScheme: VariableCodingData[] = /* coding scheme variables */ [];
const problems = CodingSchemeFactory.validate(baseVariables, codingScheme);
// each problem is a { type, breaking, variableId, variableLabel, ... }
Derivation dependency tree
To inspect derivation order / dependencies:
import type { VariableCodingData } from '@iqbspecs/coding-scheme';
import { CodingSchemeFactory } from '@iqb/responses';
const variableCodings: VariableCodingData[] = [];
const tree = CodingSchemeFactory.getVariableDependencyTree(variableCodings);
Get required base variables for a set of target variables
This is useful if you want to load only the required base responses needed to derive/code a set of variables.
import type { VariableCodingData } from '@iqbspecs/coding-scheme';
import { CodingSchemeFactory } from '@iqb/responses';
const targetVarAliases = ['V1', 'V2'];
const variableCodings: VariableCodingData[] = [];
const requiredBaseVarAliases = CodingSchemeFactory.getBaseVarsList(targetVarAliases, variableCodings);
Render coding information as text
import type { VariableInfo } from '@iqbspecs/variable-info/variable-info.interface';
import { ToTextFactory } from '@iqb/responses';
const varInfo: VariableInfo = /* ... */ {} as VariableInfo;
const lines = ToTextFactory.varInfoAsText(varInfo);
Status values
Status strings used by this package include (among others) VALUE_CHANGED, CODING_COMPLETE, CODING_INCOMPLETE, CODING_ERROR, DERIVE_ERROR, INVALID, NO_CODING, UNSET, ...
Versionsänderungen npm-package @iqb/responses
5.2.2
- Ein von einem SOLVER-Ausdruck explizit zurückgegebenes
nullwird alsVALUE_CHANGEDweitergegeben und kann überIS_NULLoderRESIDUAL_AUTOkodiert werden. NaN, positive und negative Unendlichkeit sowie andere nichtnumerische SOLVER-Ergebnisse führen weiterhin zuDERIVE_ERROR.
5.2.1
- Ein eindeutiger öffentlicher Alias darf der technischen ID einer anderen Variable entsprechen, sofern deren öffentlicher Bezeichner abweicht. Responses bleiben extern aliasbasiert, während
deriveSourcesweiterhin technische IDs referenzieren. - Doppelte IDs, doppelte Aliasse und echte öffentliche Kollisionen bleiben ungültig.
- Unerwartete
sourceType-Werte führen kontrolliert zuDERIVE_ERROR, statt geerbte Object-Properties als Handler aufzulösen.
5.2
- SOLVER-Ausdrücke können jetzt Fragmente aus Quellvariablen referenzieren, z. B.
${VAR[0]}. - SOLVER-Placeholders unterstützen Policies für leere/fehlende und nicht-numerische Werte, z. B.
${VAR:0},${VAR:INC}oder${VAR:0:INC}. - Die Validierung des Coding-Schemes prüft weitere Regelparameter, Numeric-Ranges, Fragment-Regeln,
valueArrayPosund Typkompatibilität. - Abgeleitete Variablen können gezielt den Alias ihrer Base-Source überschreiben; die Base-Response wird danach korrekt entfernt.
NUMERIC_MATCHwertetnullund leere Strings nicht mehr als numerische0.
5.1
- @iqbspecs/coding-scheme 3.4.0
- Implementiert die neuen CodingProblem Typen:
RULE_REGEX_INVALID,RULE_PARAMETER_INVALID,RULE_NUMERIC_RANGE_INVALID,RULESET_VALUE_ARRAY_POS_INVALID
5.0
- umfangreiches Refactoring/Modularisierung (u. a. Ableitungen, Rule-Engine, Dependency-Planung)
- verbesserte Validierung des Coding-Schemes (z. B. doppelte IDs/Aliase, ungültige Quellen,
RULE_PARAMETER_COUNT_MISMATCH) - robustere Fehlerbehandlung (z. B. ungültige RegEx, ungültige Solver-Expressions)
- Performance-Verbesserungen durch
Map-basierte Lookups - deutlich erweiterte Unit-Tests sowie CI/Dependabot-Workflows
4.0
Übernimmt folgende Spezifikationen:
- @iqbspecs/coding-scheme
- @iqbspecs/response
- @iqbspecs/variable-info
3.7
TAKE_NOT_REACHED_AS_VALUE_CHANGEDneuer Parameter für die Verarbeitung von Quell-Variablen
3.6
NUMERIC_FULL_RANGERegel >= Wert <= hinzugefügt
3.5
- Antworten in Unterformularen werden kodiert
- Setze RuleMethodParameterCount -1 for NUMERIC_MATCH Regel
3.4
BASE_NO_VALUEsource type wird nicht zu den Antworten hinzugefügt- Status
INTENDED_INCOMPLETEund code typeINTENDED_INCOMPLETEhinzugefügt
3.3
3.2
- manuell kodierte abgeleitete und eingespielte Variablen werden nicht versucht abzuleiten
- Missing Regeln werden bei der Ableitung beachtet
- Aliase aus dem CodingScheme werden berücksichtigt
3.1
- neuer Wert für Property
valueArrayPos:LENGTH; Werte Array muss angebene Länge haben - neuer Wert für Property
valueArrayPos:ANY_OPEN; dann wird - im Gegensatz zuANY- erlaubt, dass Werte im Array sind, für die der Regelsatz nicht zutrifft - Funktionalität für
valueArrayPos-ANY_OPENundANYhinzugefügt bzw. korrigiert IGNORE_CASEführt jetzt zumi-Flag bei RegEx- ein Werte-Array mit Länge 0 wird jetzt auch als 'leer' klassifiziert
3.0
- neue Property
version; daher ist das gesamte Coding Scheme nicht mehr ein Array, sondern ein Objekt! - neue Werte für code
type:RESIDUAL,RESIDUAL_AUTO; ersetztELSE-Regel ELSE-Regel entfernt- codingModel ist jetzt beschränkt auf
NONE,RULES_ONLYundMANUAL_ONLY
2.2
- Neuer Wert für
codeModel:RULES_ONLY- Ausblenden der Controls für die manuelle Kodierung - Variable erhält neben der ID einen
alias - Code erhält einen
type, um die Dokumentation zu erleichtern und die UI zu vereinfachen. WerteUNSET,FULL_CREDIT,PARTIAL_CREDIT,NO_CREDIT-labelwurde hierfür immer missbraucht
2.1
- Neue Funktion
getVariableDependencyTree()im Kodierschema, um den Graph der Ableitungen abzubilden
2.0
- Umsetzung der Änderungen Datenstruktur coding-scheme v2.0:
- Neue Ableitungsmethoden
UNIQUE_VALUES,SOLVER - neue Parameter 'sourceParameters' mit den Eigenschaften 'solverExpression' und 'processing' (mögliche Werte
TO_LOWER_CASE,TO_NUMBER,REMOVE_ALL_SPACES,REMOVE_DISPENSABLE_SPACES,TAKE_DISPLAYED_AS_VALUE_CHANGED,SORT,TAKE_EMPTY_AS_VALID) - processing
REMOVE_WHITE_SPACESentfernt; stattdessenIGNORE_ALL_SPACES,IGNORE_DISPENSABLE_SPACES,SORT_ARRAY
- Neue Ableitungsmethoden
- Umbau der Tests auf Jest (für coding-scheme und die Validierung der JSON-Schema)
- Ersetzen
createCodingVariableFromVarInfomitcreateCodingVariableinCodingFactory