Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
363f3b9
remove unused initial test file
phev8 Jun 2, 2025
4e7c594
remove unused printSurveyItem function from utils.ts
phev8 Jun 2, 2025
2ecd361
add legacy types and update survey item component to support new loca…
phev8 Jun 2, 2025
2a3c6f9
Implement survey compilation and decompilation methods with comprehen…
phev8 Jun 2, 2025
59feb93
Refactor test imports in render-item-components.test.ts to remove unu…
phev8 Jun 2, 2025
5b494a0
Add isSurveyCompiled function to check survey compilation status and …
phev8 Jun 2, 2025
6b6cbdf
Add schemaVersion property to Survey interface for versioning support
phev8 Jun 2, 2025
d492dc3
Update compilation tests to include schemaVersion in survey objects f…
phev8 Jun 2, 2025
3147237
Add legacy conversion utilities for survey format transformations
phev8 Jun 2, 2025
d58cb18
Enhance survey props handling by introducing translations support
phev8 Jun 2, 2025
948c50d
Enhance SurveyEngineCore with localization and dynamic value support
phev8 Jun 2, 2025
401aa47
Refactor build process and update dependencies
phev8 Jun 3, 2025
0e8cf11
Refactor SurveyEngineCore and tests for improved locale handling and …
phev8 Jun 3, 2025
d78cfe7
Add CQM parser and corresponding tests for text formatting
phev8 Jun 3, 2025
5ced9de
Update parseCQM function to handle optional text input
phev8 Jun 3, 2025
bf347be
Refactor content type from 'simple' to 'plain' across various compone…
phev8 Jun 3, 2025
90173fc
Add survey data types and tests for JSON parsing
phev8 Jun 8, 2025
428c1f9
Refactor survey schema handling and enhance JSON parsing tests
phev8 Jun 8, 2025
b266be4
Add SurveyItemKey and ItemComponentKey classes with comprehensive tests
phev8 Jun 8, 2025
237c67c
Add documentation for SurveyItemKey and ItemComponentKey classes
phev8 Jun 8, 2025
88089a3
Enhance data parsing tests and introduce SurveyItemEditor class
phev8 Jun 8, 2025
16b0aa8
Implement DisplayItem and GroupItem components with corresponding edi…
phev8 Jun 8, 2025
e4fc1cb
Add ESLint configuration for TypeScript support and update package de…
phev8 Jun 9, 2025
b8f9e0f
Implement undo-redo functionality for survey editor and add correspon…
phev8 Jun 9, 2025
a4f36fc
Add SurveyEditor class and implement survey item management features
phev8 Jun 9, 2025
03453f9
Refactor survey JSON structure and update parsing tests
phev8 Jun 9, 2025
209261a
Enhance survey item management and component deletion functionality
phev8 Jun 9, 2025
9ec9e1e
rendered items init
phev8 Jun 9, 2025
d0a4ce0
Refactor survey response structure and enhance item response handling
phev8 Jun 10, 2025
f24bbc8
Update tests for SurveyItemKey and ItemComponentKey to reflect change…
phev8 Jun 11, 2025
b9889de
save current state
phev8 Jun 12, 2025
a84f19e
add translations classes and move around files
phev8 Jun 12, 2025
97f3078
remove unavailable type
phev8 Jun 13, 2025
1038a4f
Update ESLint and related dependencies in package.json and yarn.lock
phev8 Jun 13, 2025
e7e74a2
Refactor translation methods for consistency and clarity
phev8 Jun 13, 2025
8b85fc2
Implement survey end item retrieval and flattening utility
phev8 Jun 14, 2025
0b02cb2
move files
phev8 Jun 15, 2025
d269b87
use updated expression types
phev8 Jun 15, 2025
70926a4
getSurveyPages and test
phev8 Jun 16, 2025
5eb3e53
update response types
phev8 Jun 16, 2025
f9c9add
response handling
phev8 Jun 16, 2025
34f2980
simplify validation model
phev8 Jun 16, 2025
accdb0a
Refactor SurveyEngineCore and update tests
phev8 Jun 16, 2025
bc875a7
Refactor item component types and update tests
phev8 Jun 16, 2025
084b932
Update dependencies in package.json and yarn.lock
phev8 Jun 16, 2025
fc9071b
Refactor JSON deserialization for question items
phev8 Jun 17, 2025
68f9f04
Add multiple choice question item parsing
phev8 Jun 17, 2025
86d0f42
optimise import export path and some code structure improvements
phev8 Jun 17, 2025
2015ba1
Add shuffleIndices utility and implement option shuffling for SingleC…
phev8 Jun 17, 2025
89cdeb7
Refactor display component initialization and update footer handling
phev8 Jun 17, 2025
d56b630
Merge pull request #2 from case-framework/scg-mcg-shuffle-options
phev8 Jun 17, 2025
5f2fa19
Enhance ValueReference class with ValueReferenceMethod enum
phev8 Jun 18, 2025
cc43c0b
Refactor expression parsing tests and update variable references
phev8 Jun 18, 2025
77392ec
Add getResponseValueReferences method to Survey class and enhance val…
phev8 Jun 18, 2025
95ed536
Refactor ValueReference validation logic to use Object.values for met…
phev8 Jun 18, 2025
d2cafc5
Merge pull request #3 from case-framework/value-reference-type-lookup
phev8 Jun 18, 2025
ac2368b
Enhance expression handling and editor functionality
phev8 Jun 19, 2025
7e9fc97
Refactor expression handling and enhance type safety
phev8 Jun 19, 2025
65306c5
Add response variable expression handling and editor functionality
phev8 Jun 19, 2025
e9a0560
Refactor ExpressionEditor to use method chaining for editor configura…
phev8 Jun 20, 2025
546ac8a
Add new expression editors and enhance expression handling
phev8 Jun 20, 2025
7f7fae7
Implement ExpressionEvaluator and enhance expression handling
phev8 Jun 20, 2025
1f70371
Refactor dynamic value handling to template values
phev8 Jun 23, 2025
0a76e81
Refactor SurveyEngineCore rendering methods for improved clarity
phev8 Jun 23, 2025
a3fae70
Add display condition management to SurveyItemEditor
phev8 Jun 23, 2025
d3e67b8
Refactor expression handling and improve validation logging
phev8 Jun 23, 2025
a391626
Remove unused methods and commented-out code in SurveyEngineCore for …
phev8 Jun 24, 2025
eb78a81
Enhance expression evaluation capabilities by adding new functions
phev8 Jun 24, 2025
c2e8672
Enhance ExpressionEvaluator to handle undefined expressions and impro…
phev8 Jun 24, 2025
9298ffb
Merge pull request #4 from case-framework/expression-editor-concept
phev8 Jun 24, 2025
71f3eb6
Enhance SurveyEngineCore to support date formatting in template values
phev8 Jun 24, 2025
fdc2b6f
Refactor survey context management and remove deprecated context defi…
phev8 Jun 30, 2025
dd0e17f
Refactor survey context management and remove deprecated context defi…
phev8 Jun 30, 2025
7755b37
Enhance expression handling by introducing context variable support
phev8 Jun 30, 2025
48716f4
Enhance expression evaluation with context variable support
phev8 Jun 30, 2025
2904797
Update SurveyEngineCore to set locale from context during context upd…
phev8 Jul 1, 2025
6ca1a1f
Merge pull request #5 from case-framework/survey-ctx
phev8 Jul 1, 2025
ccb5c03
Implement deletion of item translations and add test for child item r…
phev8 Jul 1, 2025
62d4f1e
Implement item key renaming functionality and add comprehensive tests
phev8 Jul 1, 2025
9a4d3c9
Add component key renaming functionality and extensive tests
phev8 Jul 1, 2025
144519d
Add reference usage tracking and validation in Survey
phev8 Jul 1, 2025
3b1a322
Add tests for item key change functionality in SurveyEditor
phev8 Jul 1, 2025
90d5e90
Implement item movement functionality with comprehensive error handli…
phev8 Jul 2, 2025
f49d9f2
Add getSiblingKeys method and corresponding tests in SurveyItemEditor
phev8 Jul 2, 2025
c005123
Implement changeItemKey method in SurveyItemEditor with comprehensive…
phev8 Jul 2, 2025
418f6c0
Refactor Key class to improve key management and validation
phev8 Jul 2, 2025
b7ec5a6
Refactor response configuration to use 'items' instead of 'options'
phev8 Jul 2, 2025
5d05c6f
Merge pull request #6 from case-framework/reference-handling
phev8 Jul 4, 2025
cec3b00
Enhance SurveyEditor and UndoRedo functionality
phev8 Jul 7, 2025
dc0b94b
Add JSON serialization and deserialization for SurveyEditorUndoRedo
phev8 Jul 7, 2025
b2aa1f9
Add serialization and deserialization for SurveyEditor state
phev8 Jul 7, 2025
8d56ab1
Implement event-driven architecture in SurveyEditor
phev8 Jul 8, 2025
f004755
Add metadata update functionality in SurveyItemEditor
phev8 Jul 15, 2025
bf938a2
Add getRenderedSurveyItem method to SurveyEngineCore
phev8 Jul 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions docs/example-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Survey Editor Event Listener Example

The SurveyEditor now supports a simple event-driven architecture with a single `survey-changed` event.

## Basic Usage

```typescript
import { SurveyEditor } from '../src/survey-editor';

// Create editor instance
const editor = new SurveyEditor(survey);

// Listen for any survey changes (both uncommitted changes and commits)
editor.on('survey-changed', (data) => {
if (data.isCommit) {
console.log('Changes committed:', data.description);
// Save to persistent storage
saveToDatabase(editor.toJson());
} else {
console.log('Survey modified (uncommitted)');
// Auto-save to session storage for recovery
updateSessionData(editor.toJson());
}

console.log('Has uncommitted changes:', data.hasUncommittedChanges);
});
```

## Session Data Auto-Save Example

```typescript
class EditorSession {
private editor: SurveyEditor;
private sessionKey: string;

constructor(editor: SurveyEditor, sessionKey: string) {
this.editor = editor;
this.sessionKey = sessionKey;

// Set up auto-save on any change
this.editor.on('survey-changed', this.handleSurveyChanged.bind(this));
}

private handleSurveyChanged(data: { hasUncommittedChanges: boolean; isCommit: boolean; description?: string }) {
if (data.isCommit) {
// Save committed state to persistent storage
localStorage.setItem(
this.sessionKey,
JSON.stringify(this.editor.toJson())
);

// Clear draft since it's now committed
sessionStorage.removeItem(`${this.sessionKey}_draft`);
} else if (data.hasUncommittedChanges) {
// Save to session storage for recovery
sessionStorage.setItem(
`${this.sessionKey}_draft`,
JSON.stringify(this.editor.toJson())
);
}
}

cleanup() {
this.editor.clearAllListeners();
}
}
```

## Analytics Example

```typescript
class EditorAnalytics {
constructor(editor: SurveyEditor) {
// Track all survey changes
editor.on('survey-changed', (data) => {
if (data.isCommit) {
this.trackEvent('survey_changes_committed', {
description: data.description,
hasUncommittedChanges: data.hasUncommittedChanges
});
} else {
this.trackEvent('survey_modified', {
hasUncommittedChanges: data.hasUncommittedChanges
});
}
});
}

private trackEvent(eventName: string, properties?: any) {
// Send to your analytics service
analytics.track(eventName, properties);
}
}
```

## Available Events

| Event Type | Data | Description |
|------------|------|-------------|
| `survey-changed` | `{ hasUncommittedChanges: boolean; isCommit: boolean; description?: string }` | Fired when survey content changes or is committed |

### Event Data Properties

- `hasUncommittedChanges`: Whether the editor has uncommitted changes
- `isCommit`: `true` if this event was triggered by a commit, `false` if by a modification
- `description`: Only present when `isCommit` is `true`, contains the commit description

## Best Practices

1. **Remove listeners**: Always call `editor.off()` or `editor.clearAllListeners()` when cleaning up
2. **Error handling**: Event listeners are wrapped in try-catch, but handle errors gracefully
3. **Performance**: Be mindful of heavy operations in the `survey-changed` event as it fires on every modification
4. **Memory leaks**: Remove listeners when components unmount to prevent memory leaks
5. **Check event type**: Use the `isCommit` flag to differentiate between modifications and commits
47 changes: 27 additions & 20 deletions docs/survey-structure.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
TODO: update this file with the new structure

# Survey Definition Structure

## Overview

Usually a survey is described as a set of (ordered) questions.
Usually a survey is described as a set of (ordered) questions.

In this engine a survey is a hierarchical structure composed by 2 kind of elements:

Expand Down Expand Up @@ -33,49 +35,50 @@ SurveyGroupItem(intake):

### Path into the survey tree and key rules for SurveyItem

** Survey Engine Rule **
**Survey Engine Rule**

These rules are mandatory to allow the survey engine to work correctly.

Each `SurveyItem` has a key, uniquely identify the item inside the survey.
Each `SurveyItem` has a key, uniquely identify the item inside the survey.
They keys of SurveyItem elements (`SurveySingleItem` and `SurveyGroupItem`) must follow these rules:

- The key is composed by a set of segments separated by a dot (.), root element has only one segment
- The key segments are set of characters WITHOUT dot
- The key segments are set of characters WITHOUT dot
- The key of one SurveyItem must be prefixed by the key of it parents.
- All keys must uniquely identify one item
- All keys must uniquely identify one item

The key with several segments separated by dots represent the path to this item from the root item. In other words, the key of each item must be the path (dot separated) to this item from the root item. Each dot represent the walk through the lower level.
The key with several segments separated by dots represent the path to this item from the root item. In other words, the key of each item must be the path (dot separated) to this item from the root item. Each dot represent the walk through the lower level.

Examples:
- A survey named weekly, with an item Q1:
- The root item is is keyed 'weekly',
- the item is keyed 'weekly.Q1'
- A survey named weekly with a group of question 'G1', this group containing two questions (SingleItem) Q1 and Q2:
- the root item's key is 'weekly'
- the group's key is 'weekly.G1'
- the item inside the groups have keys respectively 'weekly.G1.Q1', 'weekly.G1.Q2'

** General best practices **
- A survey named weekly, with an item Q1:
- The root item is is keyed 'weekly',
- the item is keyed 'weekly.Q1'
- A survey named weekly with a group of question 'G1', this group containing two questions (SingleItem) Q1 and Q2:
- the root item's key is 'weekly'
- the group's key is 'weekly.G1'
- the item inside the groups have keys respectively 'weekly.G1.Q1', 'weekly.G1.Q2'

**General best practices**

- Key segments should be alphanumerical words, including underscores
- As meaningful as possible
- If a word separator is chosen (dash or underscore) it should be the same everywhere

** Best practices for InfluenzaNet **
**Best practices for InfluenzaNet**

Besides the previous naming rules, there are some naming convention, inherited from past platform of Influenzanet

- [should] Items are named with a 'Q' followed by a question identifier (in use Q[nn] and Qcov[nn])
- [must] Last segment of each key must be unique for all the survey. e.g. 'weekly.Q1' must be unique but also 'Q1' in the survey. You must not have another item with a key finishing by 'Q1', even if in another group. This rule because the last segment is used a the key for data export.
- [must] Question keys are arbitrary but the common questions must have the assigned key in the survey standard definition
- [should] Non common question, should have a prefix to clearly identify them as non standard question (like a namespace), for example
- [must] Last segment of each key must be unique for all the survey. e.g. 'weekly.Q1' must be unique but also 'Q1' in the survey. You must not have another item with a key finishing by 'Q1', even if in another group. This rule because the last segment is used a the key for data export.
- [must] Question keys are arbitrary but the common questions must have the assigned key in the survey standard definition
- [should] Non common question, should have a prefix to clearly identify them as non standard question (like a namespace), for example

## Survey Item Components

Components describe the properties of a SurveySingleItem (e.g. a question).
Components describe the properties of a SurveySingleItem (e.g. a question).

Every elements of a question is a component with a specific role. For example the label, the input widget or an option is a component.
Every elements of a question is a component with a specific role. For example the label, the input widget or an option is a component.

Several kind of components are proposed :

Expand All @@ -88,12 +91,14 @@ Components can also be described as a tree, nodes as Group components, and leaf
Each component has a 'role' field, giving the purpose of the component and how the survey engine will handle it.

Common roles:

- 'root' : the group component of a survey item, containing all the components of a Survey item.
- 'responseGroup' : a response group component
- 'helpGroup'
- 'text' : a component describing text to show (for example the label of the question)

Response dedicated roles:

- 'singleChoiceGroup'
- dropDownGroup
- multipleChoiceGroup
Expand All @@ -111,6 +116,7 @@ common Fields :
- `disabled` : rules for disabling component

For group component only

- `order` : order of components (for Group component)

Most of fields are represented as structure called `Expression`. They can be evaluated to a value (boolean, string, value) at runtime allowing to define complex rules to dynamically determine a field value.
Expand All @@ -126,6 +132,7 @@ Keys are mandatory for Response component
**Expression** are tree structures to represent operation to be evaluated at runtime and can produce a value. They provides dynamic property evaluation for the survey logic.

An **Expression** is a simple structure that can be either:

- A typed literal value (numerical, string)
- A call, with a `name` and a field `data` set of parameters with a list of `Expression`

Expand Down
36 changes: 36 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';

export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
},
rules: {
// Rule to detect unused imports and variables
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
// Additional TypeScript-specific rules
'@typescript-eslint/no-explicit-any': 'warn',
},
},
{
files: ['**/*.test.ts', '**/*.spec.ts'],
rules: {
// Allow unused variables in tests (common for setup/teardown)
'@typescript-eslint/no-unused-vars': 'off',
},
}
);
2 changes: 1 addition & 1 deletion jestconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
"json",
"node"
]
}
}
28 changes: 13 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
{
"name": "survey-engine",
"version": "1.3.2",
"version": "2.0.0-dev",
"description": "Implementation of the survey engine to use in typescript/javascript projects.",
"main": "index.js",
"type": "module",
"scripts": {
"test": "jest --config jestconfig.json",
"build": "rollup -c"
"build": "tsdown",
"lint": "eslint src --ext .ts",
"lint:fix": "eslint src --ext .ts --fix"
},
"keywords": [
"survey engine"
Expand All @@ -17,20 +20,15 @@
},
"homepage": "https://github.com/influenzanet/survey-engine.ts#readme",
"devDependencies": {
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.0.6",
"@types/jest": "^29.2.0",
"jest": "^29.2.1",
"rollup": "^2.61.1",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-delete": "^2.0.0",
"rollup-plugin-multi-input": "^1.3.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-typescript2": "^0.31.1",
"ts-jest": "^29.0.3",
"typescript": "^4.5.3"
"@types/jest": "^30.0.0",
"eslint": "^9.29.0",
"jest": "^30.0.2",
"ts-jest": "^29.4.0",
"tsdown": "^0.12.8",
"typescript": "^5.8.3",
"typescript-eslint": "^8.35.0"
},
"dependencies": {
"date-fns": "^2.29.3"
"date-fns": "^4.1.0"
}
}
49 changes: 0 additions & 49 deletions rollup.config.js

This file was deleted.

Loading