qnce-engine 1.2.0 → 1.2.2

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.
Files changed (125) hide show
  1. package/README.md +713 -7
  2. package/dist/cli/audit.js +0 -0
  3. package/dist/cli/init.js +0 -0
  4. package/dist/cli/perf.d.ts.map +1 -1
  5. package/dist/cli/perf.js +2 -1
  6. package/dist/cli/perf.js.map +1 -1
  7. package/dist/cli/play.d.ts +4 -0
  8. package/dist/cli/play.d.ts.map +1 -0
  9. package/dist/cli/play.js +259 -0
  10. package/dist/cli/play.js.map +1 -0
  11. package/dist/engine/condition.d.ts +69 -0
  12. package/dist/engine/condition.d.ts.map +1 -0
  13. package/dist/engine/condition.js +195 -0
  14. package/dist/engine/condition.js.map +1 -0
  15. package/dist/engine/core.d.ts +274 -3
  16. package/dist/engine/core.d.ts.map +1 -1
  17. package/dist/engine/core.js +1148 -9
  18. package/dist/engine/core.js.map +1 -1
  19. package/dist/engine/demo-story.d.ts.map +1 -1
  20. package/dist/engine/demo-story.js +99 -13
  21. package/dist/engine/demo-story.js.map +1 -1
  22. package/dist/engine/errors.d.ts +76 -0
  23. package/dist/engine/errors.d.ts.map +1 -0
  24. package/dist/engine/errors.js +178 -0
  25. package/dist/engine/errors.js.map +1 -0
  26. package/dist/engine/types.d.ts +445 -0
  27. package/dist/engine/types.d.ts.map +1 -0
  28. package/dist/engine/types.js +9 -0
  29. package/dist/engine/types.js.map +1 -0
  30. package/dist/engine/validation.d.ts +110 -0
  31. package/dist/engine/validation.d.ts.map +1 -0
  32. package/dist/engine/validation.js +261 -0
  33. package/dist/engine/validation.js.map +1 -0
  34. package/dist/examples/examples/autosave-undo-demo.js +248 -0
  35. package/dist/examples/examples/persistence-demo.js +63 -0
  36. package/dist/examples/src/engine/condition.js +194 -0
  37. package/dist/examples/src/engine/core.js +1382 -0
  38. package/dist/examples/src/engine/demo-story.js +200 -0
  39. package/dist/examples/src/engine/types.js +8 -0
  40. package/dist/examples/src/index.js +35 -0
  41. package/dist/examples/src/integrations/react.js +322 -0
  42. package/dist/examples/src/narrative/branching/engine-simple.js +348 -0
  43. package/dist/examples/src/narrative/branching/index.js +55 -0
  44. package/dist/examples/src/narrative/branching/models.js +5 -0
  45. package/dist/examples/src/performance/ObjectPool.js +296 -0
  46. package/dist/examples/src/performance/PerfReporter.js +280 -0
  47. package/dist/examples/src/performance/ThreadPool.js +347 -0
  48. package/dist/index.d.ts +4 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +12 -1
  51. package/dist/index.js.map +1 -1
  52. package/dist/integrations/react.d.ts +200 -0
  53. package/dist/integrations/react.d.ts.map +1 -0
  54. package/dist/integrations/react.js +365 -0
  55. package/dist/integrations/react.js.map +1 -0
  56. package/dist/narrative/branching/engine-simple.js +3 -3
  57. package/dist/narrative/branching/engine-simple.js.map +1 -1
  58. package/dist/narrative/branching/engine.d.ts +1 -0
  59. package/dist/narrative/branching/engine.d.ts.map +1 -0
  60. package/dist/narrative/branching/engine.js +2 -0
  61. package/dist/narrative/branching/engine.js.map +1 -0
  62. package/dist/narrative/branching/models.d.ts.map +1 -1
  63. package/dist/performance/HotReloadDelta.d.ts +25 -8
  64. package/dist/performance/HotReloadDelta.d.ts.map +1 -1
  65. package/dist/performance/HotReloadDelta.js +10 -15
  66. package/dist/performance/HotReloadDelta.js.map +1 -1
  67. package/dist/ui/__tests__/AutosaveIndicator.test.d.ts +2 -0
  68. package/dist/ui/__tests__/AutosaveIndicator.test.d.ts.map +1 -0
  69. package/dist/ui/__tests__/AutosaveIndicator.test.js +329 -0
  70. package/dist/ui/__tests__/AutosaveIndicator.test.js.map +1 -0
  71. package/dist/ui/__tests__/UndoRedoControls.test.d.ts +2 -0
  72. package/dist/ui/__tests__/UndoRedoControls.test.d.ts.map +1 -0
  73. package/dist/ui/__tests__/UndoRedoControls.test.js +245 -0
  74. package/dist/ui/__tests__/UndoRedoControls.test.js.map +1 -0
  75. package/dist/ui/__tests__/autosave-simple.test.d.ts +2 -0
  76. package/dist/ui/__tests__/autosave-simple.test.d.ts.map +1 -0
  77. package/dist/ui/__tests__/autosave-simple.test.js +29 -0
  78. package/dist/ui/__tests__/autosave-simple.test.js.map +1 -0
  79. package/dist/ui/__tests__/setup.d.ts +2 -0
  80. package/dist/ui/__tests__/setup.d.ts.map +1 -0
  81. package/dist/ui/__tests__/setup.js +40 -0
  82. package/dist/ui/__tests__/setup.js.map +1 -0
  83. package/dist/ui/__tests__/smoke-test.d.ts +2 -0
  84. package/dist/ui/__tests__/smoke-test.d.ts.map +1 -0
  85. package/dist/ui/__tests__/smoke-test.js +18 -0
  86. package/dist/ui/__tests__/smoke-test.js.map +1 -0
  87. package/dist/ui/__tests__/smoke-test.test.d.ts +2 -0
  88. package/dist/ui/__tests__/smoke-test.test.d.ts.map +1 -0
  89. package/dist/ui/__tests__/smoke-test.test.js +18 -0
  90. package/dist/ui/__tests__/smoke-test.test.js.map +1 -0
  91. package/dist/ui/__tests__/useKeyboardShortcuts.test.d.ts +2 -0
  92. package/dist/ui/__tests__/useKeyboardShortcuts.test.d.ts.map +1 -0
  93. package/dist/ui/__tests__/useKeyboardShortcuts.test.js +374 -0
  94. package/dist/ui/__tests__/useKeyboardShortcuts.test.js.map +1 -0
  95. package/dist/ui/components/AutosaveIndicator.d.ts +18 -0
  96. package/dist/ui/components/AutosaveIndicator.d.ts.map +1 -0
  97. package/dist/ui/components/AutosaveIndicator.js +175 -0
  98. package/dist/ui/components/AutosaveIndicator.js.map +1 -0
  99. package/dist/ui/components/UndoRedoControls.d.ts +16 -0
  100. package/dist/ui/components/UndoRedoControls.d.ts.map +1 -0
  101. package/dist/ui/components/UndoRedoControls.js +144 -0
  102. package/dist/ui/components/UndoRedoControls.js.map +1 -0
  103. package/dist/ui/hooks/useKeyboardShortcuts.d.ts +22 -0
  104. package/dist/ui/hooks/useKeyboardShortcuts.d.ts.map +1 -0
  105. package/dist/ui/hooks/useKeyboardShortcuts.js +162 -0
  106. package/dist/ui/hooks/useKeyboardShortcuts.js.map +1 -0
  107. package/dist/ui/index.d.ts +9 -0
  108. package/dist/ui/index.d.ts.map +1 -0
  109. package/dist/ui/index.js +14 -0
  110. package/dist/ui/index.js.map +1 -0
  111. package/dist/ui/types.d.ts +141 -0
  112. package/dist/ui/types.d.ts.map +1 -0
  113. package/dist/ui/types.js +51 -0
  114. package/dist/ui/types.js.map +1 -0
  115. package/examples/autosave-undo-demo.ts +306 -0
  116. package/examples/branching-demo-simple.ts +0 -0
  117. package/examples/branching-demo.ts +0 -0
  118. package/examples/persistence-demo.ts +84 -0
  119. package/examples/tsconfig.json +13 -0
  120. package/examples/ui-components-demo.tsx +320 -0
  121. package/examples/validation-demo-story.json +177 -0
  122. package/examples/validation-demo.js +163 -0
  123. package/package.json +24 -4
  124. package/docs/branching/PDM.md +0 -443
  125. package/docs/branching/RELEASE-v1.2.0.md +0 -169
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ // QNCE Condition Evaluator - Sprint 3.4
3
+ // Parses and evaluates conditional expressions for choice visibility
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.conditionEvaluator = exports.ConditionEvaluator = exports.ConditionEvaluationError = void 0;
6
+ /**
7
+ * Error thrown when condition evaluation fails
8
+ */
9
+ class ConditionEvaluationError extends Error {
10
+ expression;
11
+ cause;
12
+ constructor(message, expression, cause) {
13
+ super(message);
14
+ this.expression = expression;
15
+ this.cause = cause;
16
+ this.name = 'ConditionEvaluationError';
17
+ }
18
+ }
19
+ exports.ConditionEvaluationError = ConditionEvaluationError;
20
+ /**
21
+ * Built-in expression operators
22
+ */
23
+ const OPERATORS = {
24
+ '>=': (a, b) => a >= b,
25
+ '<=': (a, b) => a <= b,
26
+ '>': (a, b) => a > b,
27
+ '<': (a, b) => a < b,
28
+ '==': (a, b) => a == b,
29
+ '===': (a, b) => a === b,
30
+ '!=': (a, b) => a != b,
31
+ '!==': (a, b) => a !== b,
32
+ '&&': (a, b) => a && b,
33
+ '||': (a, b) => a || b,
34
+ };
35
+ /**
36
+ * Condition evaluator service for parsing and executing conditional expressions
37
+ */
38
+ class ConditionEvaluator {
39
+ customEvaluator;
40
+ // Cache compiled functions for better performance
41
+ functionCache = new Map();
42
+ maxCacheSize = 100;
43
+ /**
44
+ * Set a custom evaluator function for handling complex conditions
45
+ */
46
+ setCustomEvaluator(evaluator) {
47
+ this.customEvaluator = evaluator;
48
+ }
49
+ /**
50
+ * Clear the custom evaluator
51
+ */
52
+ clearCustomEvaluator() {
53
+ this.customEvaluator = undefined;
54
+ }
55
+ /**
56
+ * Evaluate a condition expression against the provided context
57
+ */
58
+ evaluate(expression, context) {
59
+ try {
60
+ // If custom evaluator is set, use it first
61
+ if (this.customEvaluator) {
62
+ return this.customEvaluator(expression, context);
63
+ }
64
+ // Use built-in evaluator
65
+ return this.evaluateBuiltIn(expression, context);
66
+ }
67
+ catch (error) {
68
+ throw new ConditionEvaluationError(`Failed to evaluate condition: ${expression}`, expression, error instanceof Error ? error : new Error(String(error)));
69
+ }
70
+ }
71
+ /**
72
+ * Built-in expression evaluator with support for common patterns
73
+ */
74
+ evaluateBuiltIn(expression, context) {
75
+ // Handle empty expressions
76
+ if (!expression || expression.trim() === '') {
77
+ throw new ConditionEvaluationError('Empty or whitespace-only condition expression', expression);
78
+ }
79
+ // Sanitize and prepare expression
80
+ const sanitizedExpression = this.sanitizeExpression(expression);
81
+ // Handle simple cases first
82
+ if (sanitizedExpression === 'true')
83
+ return true;
84
+ if (sanitizedExpression === 'false')
85
+ return false;
86
+ // Create safe evaluation context
87
+ const evalContext = this.createEvaluationContext(context);
88
+ // Check function cache for performance
89
+ let func = this.functionCache.get(sanitizedExpression);
90
+ if (!func) {
91
+ try {
92
+ // Use Function constructor for safe evaluation (better than eval)
93
+ func = new Function('flags', 'state', 'timestamp', 'customData', `
94
+ "use strict";
95
+ return ${sanitizedExpression};
96
+ `);
97
+ // Cache the function for future use
98
+ if (this.functionCache.size >= this.maxCacheSize) {
99
+ // Remove oldest entry when cache is full
100
+ const firstKey = this.functionCache.keys().next().value;
101
+ if (firstKey) {
102
+ this.functionCache.delete(firstKey);
103
+ }
104
+ }
105
+ this.functionCache.set(sanitizedExpression, func);
106
+ }
107
+ catch (error) {
108
+ throw new ConditionEvaluationError(`Invalid expression syntax: ${expression}`, expression, error instanceof Error ? error : new Error(String(error)));
109
+ }
110
+ }
111
+ try {
112
+ return !!func(evalContext.flags, evalContext.state, evalContext.timestamp, evalContext.customData);
113
+ }
114
+ catch (error) {
115
+ throw new ConditionEvaluationError(`Runtime error evaluating: ${expression}`, expression, error instanceof Error ? error : new Error(String(error)));
116
+ }
117
+ }
118
+ /**
119
+ * Sanitize expression to prevent code injection
120
+ */
121
+ sanitizeExpression(expression) {
122
+ // Remove potentially dangerous patterns
123
+ const dangerous = [
124
+ /\beval\b/g,
125
+ /\bFunction\b/g,
126
+ /\bconstructor\b/g,
127
+ /\bprototype\b/g,
128
+ /\b__proto__\b/g,
129
+ /\bimport\b/g,
130
+ /\brequire\b/g,
131
+ /\bprocess\b/g,
132
+ /\bglobal\b/g,
133
+ /\bwindow\b/g,
134
+ /\bdocument\b/g,
135
+ ];
136
+ let sanitized = expression.trim();
137
+ for (const pattern of dangerous) {
138
+ if (pattern.test(sanitized)) {
139
+ throw new ConditionEvaluationError(`Potentially unsafe expression detected: ${expression}`, expression);
140
+ }
141
+ }
142
+ return sanitized;
143
+ }
144
+ /**
145
+ * Create a safe evaluation context from the condition context
146
+ */
147
+ createEvaluationContext(context) {
148
+ return {
149
+ flags: { ...context.state.flags },
150
+ state: {
151
+ currentNodeId: context.state.currentNodeId,
152
+ flags: { ...context.state.flags },
153
+ history: [...context.state.history],
154
+ },
155
+ timestamp: context.timestamp,
156
+ customData: context.customData ? { ...context.customData } : {},
157
+ };
158
+ }
159
+ /**
160
+ * Validate that an expression is syntactically correct without evaluating it
161
+ */
162
+ validateExpression(expression) {
163
+ try {
164
+ this.sanitizeExpression(expression);
165
+ // Try to create the function without executing it
166
+ new Function('flags', 'state', 'timestamp', 'customData', `
167
+ "use strict";
168
+ return ${expression};
169
+ `);
170
+ return { valid: true };
171
+ }
172
+ catch (error) {
173
+ return {
174
+ valid: false,
175
+ error: error instanceof Error ? error.message : String(error)
176
+ };
177
+ }
178
+ }
179
+ /**
180
+ * Get list of flag names referenced in an expression
181
+ */
182
+ getReferencedFlags(expression) {
183
+ const flagPattern = /flags\.([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
184
+ const matches = [];
185
+ let match;
186
+ while ((match = flagPattern.exec(expression)) !== null) {
187
+ matches.push(match[1]);
188
+ }
189
+ return [...new Set(matches)]; // Remove duplicates
190
+ }
191
+ }
192
+ exports.ConditionEvaluator = ConditionEvaluator;
193
+ // Create a global instance for the engine to use
194
+ exports.conditionEvaluator = new ConditionEvaluator();