@case-framework/survey-core
v0.2.0
Published
Implementation of the survey core to use in typescript/javascript projects.
Readme
@case-framework/survey-core
Headless TypeScript core for defining, editing, running, and exporting surveys in the CASE ecosystem.
Intention
@case-framework/survey-core is the domain/runtime layer behind CASE surveys. It is designed to:
- Provide a framework-agnostic survey model.
- Support custom item types through a plugin registry.
- Evaluate display logic, validations, and template expressions at runtime.
- Produce normalized responses and export-ready data (including CSV).
Scope
This package includes:
- Survey model and serialization (
Survey). - Item contracts and registry utilities (
SurveyItemCore,createItemCore,createFullRegistry). - Runtime engine (
SurveyEngineCore) for render order, conditions, template values, events, and responses. - Expression model + evaluator (
Expression,FunctionExpression,ExpressionEvaluator, etc.). - Response models (
SurveyResponse,SurveyItemResponse,ResponseItem). - Response export tooling (
SurveyResponseExporter, CSV helpers, codebook generation). - Editor state/manipulation APIs via the
@case-framework/survey-core/editorentrypoint.
This package does not include:
- UI rendering components.
- Network or persistence layers.
- App-level state management.
For UI integration, use @case-framework/survey-ui on top of this core package.
Installation
pnpm add @case-framework/survey-coreEntrypoints
@case-framework/survey-core: runtime/model/expressions/exporter APIs.@case-framework/survey-core/editor: editing APIs (SurveyEditor, undo/redo, copy/paste helpers).
Usage
1. Define a custom item type and registry
import {
SurveyItemCore,
ValueRefTypeLookup,
ValueType,
ItemTypeRegistry,
} from '@case-framework/survey-core';
type SingleChoiceConfig = {
id: string;
options: Array<{ id: string; key: string; type: string }>;
};
class SingleChoiceQuestionItemCore extends SurveyItemCore<'singleChoiceQuestion', SingleChoiceConfig> {
readonly type = 'singleChoiceQuestion';
parseConfig(rawConfig: unknown): SingleChoiceConfig {
const cfg = (rawConfig ?? {}) as Partial<SingleChoiceConfig>;
return {
id: cfg.id ?? this.id,
options: cfg.options ?? [],
};
}
isInteractive(): boolean {
return true;
}
getAvailableResponseValueSlots(): ValueRefTypeLookup {
return {
[`${this.id}...get...${this.config.id}`]: ValueType.reference,
[`${this.id}...isDefined...${this.config.id}`]: ValueType.boolean,
};
}
}
const pluginRegistry: ItemTypeRegistry = {
singleChoiceQuestion: SingleChoiceQuestionItemCore,
};2. Load a survey and run it with the engine
import {
Survey,
SurveyEngineCore,
ResponseItem,
ValueType,
ReservedSurveyItemTypes,
} from '@case-framework/survey-core';
const survey = Survey.fromJson(
{
$schema:
'https://github.com/case-framework/case-survey-toolkit/packages/survey-core/schemas/survey-schema.json',
surveyItems: [
{
id: 'root',
key: 'root',
itemType: ReservedSurveyItemTypes.Group,
config: { isRoot: true, items: ['q1'] },
},
{
id: 'q1',
key: 'q1',
itemType: 'singleChoiceQuestion',
config: {
id: 'q1',
options: [
{ id: 'yes', key: 'yes', type: 'option' },
{ id: 'no', key: 'no', type: 'option' },
],
},
},
],
},
pluginRegistry
);
const engine = new SurveyEngineCore(survey, { locale: 'en' });
// Set one item response (slot id == config.id in this example).
engine.setResponse(
'q1',
new ResponseItem([['q1', { type: ValueType.reference, value: 'yes' }]])
);
const pages = engine.getSurveyPages('large');
const responses = engine.getResponses();
const events = engine.getEvents();3. Export responses to CSV
import {
SurveyResponse,
SurveyResponseExporter,
} from '@case-framework/survey-core';
const response = new SurveyResponse('response-1', 'v1');
response.responses = new Map(responses.map((r) => [r.itemId, r]));
response.submittedAt = Math.floor(Date.now() / 1000);
const exporter = new SurveyResponseExporter([
{
versionId: 'v1',
surveyKey: survey.surveyKey ?? 'survey',
survey,
},
]);
const csv = exporter.exportResponsesToCsv([response]);4. Edit surveys with the editor entrypoint
import { SurveyEditor, CommitSource } from '@case-framework/survey-core/editor';
const editor = new SurveyEditor(survey, { pluginRegistry });
const newItem = survey.createItemFromRaw({
id: 'q2',
key: 'q2',
itemType: 'singleChoiceQuestion',
config: { id: 'q2', options: [] },
});
editor.addItem({ parentId: survey.rootItem!.id }, newItem);
editor.commit({ label: 'Add q2', source: CommitSource.USER });