@veraxhq/verax 0.2.1 → 0.4.0
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/README.md +10 -6
- package/bin/verax.js +11 -11
- package/package.json +29 -8
- package/src/cli/commands/baseline.js +103 -0
- package/src/cli/commands/default.js +51 -6
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +246 -0
- package/src/cli/commands/gates.js +95 -0
- package/src/cli/commands/inspect.js +4 -2
- package/src/cli/commands/release-check.js +215 -0
- package/src/cli/commands/run.js +45 -6
- package/src/cli/commands/security-check.js +212 -0
- package/src/cli/commands/truth.js +113 -0
- package/src/cli/entry.js +30 -20
- package/src/cli/util/angular-component-extractor.js +179 -0
- package/src/cli/util/angular-navigation-detector.js +141 -0
- package/src/cli/util/angular-network-detector.js +161 -0
- package/src/cli/util/angular-state-detector.js +162 -0
- package/src/cli/util/ast-interactive-detector.js +544 -0
- package/src/cli/util/ast-network-detector.js +603 -0
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +602 -0
- package/src/cli/util/atomic-write.js +12 -1
- package/src/cli/util/bootstrap-guard.js +86 -0
- package/src/cli/util/console-reporter.js +72 -0
- package/src/cli/util/detection-engine.js +105 -41
- package/src/cli/util/determinism-runner.js +124 -0
- package/src/cli/util/determinism-writer.js +129 -0
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +151 -5
- package/src/cli/util/findings-writer.js +3 -0
- package/src/cli/util/framework-detector.js +572 -0
- package/src/cli/util/idgen.js +1 -1
- package/src/cli/util/interaction-planner.js +529 -0
- package/src/cli/util/learn-writer.js +2 -0
- package/src/cli/util/ledger-writer.js +110 -0
- package/src/cli/util/monorepo-resolver.js +162 -0
- package/src/cli/util/observation-engine.js +127 -278
- package/src/cli/util/observe-writer.js +2 -0
- package/src/cli/util/project-discovery.js +284 -0
- package/src/cli/util/project-writer.js +2 -0
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-resolver.js +64 -0
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/source-requirement.js +55 -0
- package/src/cli/util/summary-writer.js +2 -0
- package/src/cli/util/svelte-navigation-detector.js +163 -0
- package/src/cli/util/svelte-network-detector.js +80 -0
- package/src/cli/util/svelte-sfc-extractor.js +146 -0
- package/src/cli/util/svelte-state-detector.js +242 -0
- package/src/cli/util/trust-activation-integration.js +496 -0
- package/src/cli/util/trust-activation-wrapper.js +85 -0
- package/src/cli/util/trust-integration-hooks.js +164 -0
- package/src/cli/util/types.js +153 -0
- package/src/cli/util/url-validation.js +40 -0
- package/src/cli/util/vue-navigation-detector.js +178 -0
- package/src/cli/util/vue-sfc-extractor.js +161 -0
- package/src/cli/util/vue-state-detector.js +215 -0
- package/src/types/fs-augment.d.ts +23 -0
- package/src/types/global.d.ts +137 -0
- package/src/types/internal-types.d.ts +35 -0
- package/src/verax/cli/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +139 -0
- package/src/verax/core/artifacts/verifier.js +990 -0
- package/src/verax/core/baseline/baseline.enforcer.js +137 -0
- package/src/verax/core/baseline/baseline.snapshot.js +233 -0
- package/src/verax/core/capabilities/gates.js +505 -0
- package/src/verax/core/capabilities/registry.js +475 -0
- package/src/verax/core/confidence/confidence-compute.js +144 -0
- package/src/verax/core/confidence/confidence-invariants.js +234 -0
- package/src/verax/core/confidence/confidence-report-writer.js +112 -0
- package/src/verax/core/confidence/confidence-weights.js +44 -0
- package/src/verax/core/confidence/confidence.defaults.js +65 -0
- package/src/verax/core/confidence/confidence.loader.js +80 -0
- package/src/verax/core/confidence/confidence.schema.js +94 -0
- package/src/verax/core/confidence-engine-refactor.js +489 -0
- package/src/verax/core/confidence-engine.js +625 -0
- package/src/verax/core/contracts/index.js +29 -0
- package/src/verax/core/contracts/types.js +186 -0
- package/src/verax/core/contracts/validators.js +456 -0
- package/src/verax/core/decisions/decision.trace.js +278 -0
- package/src/verax/core/determinism/contract-writer.js +89 -0
- package/src/verax/core/determinism/contract.js +139 -0
- package/src/verax/core/determinism/diff.js +405 -0
- package/src/verax/core/determinism/engine.js +222 -0
- package/src/verax/core/determinism/finding-identity.js +149 -0
- package/src/verax/core/determinism/normalize.js +466 -0
- package/src/verax/core/determinism/report-writer.js +93 -0
- package/src/verax/core/determinism/run-fingerprint.js +123 -0
- package/src/verax/core/dynamic-route-intelligence.js +529 -0
- package/src/verax/core/evidence/evidence-capture-service.js +308 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +166 -0
- package/src/verax/core/evidence-builder.js +487 -0
- package/src/verax/core/execution-mode-context.js +77 -0
- package/src/verax/core/execution-mode-detector.js +192 -0
- package/src/verax/core/failures/exit-codes.js +88 -0
- package/src/verax/core/failures/failure-summary.js +76 -0
- package/src/verax/core/failures/failure.factory.js +225 -0
- package/src/verax/core/failures/failure.ledger.js +133 -0
- package/src/verax/core/failures/failure.types.js +196 -0
- package/src/verax/core/failures/index.js +10 -0
- package/src/verax/core/ga/ga-report-writer.js +43 -0
- package/src/verax/core/ga/ga.artifact.js +49 -0
- package/src/verax/core/ga/ga.contract.js +435 -0
- package/src/verax/core/ga/ga.enforcer.js +87 -0
- package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
- package/src/verax/core/guardrails/policy.defaults.js +210 -0
- package/src/verax/core/guardrails/policy.loader.js +84 -0
- package/src/verax/core/guardrails/policy.schema.js +110 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
- package/src/verax/core/guardrails-engine.js +505 -0
- package/src/verax/core/incremental-store.js +1 -0
- package/src/verax/core/integrity/budget.js +138 -0
- package/src/verax/core/integrity/determinism.js +342 -0
- package/src/verax/core/integrity/integrity.js +208 -0
- package/src/verax/core/integrity/poisoning.js +108 -0
- package/src/verax/core/integrity/transaction.js +140 -0
- package/src/verax/core/observe/run-timeline.js +318 -0
- package/src/verax/core/perf/perf.contract.js +186 -0
- package/src/verax/core/perf/perf.display.js +65 -0
- package/src/verax/core/perf/perf.enforcer.js +91 -0
- package/src/verax/core/perf/perf.monitor.js +209 -0
- package/src/verax/core/perf/perf.report.js +200 -0
- package/src/verax/core/pipeline-tracker.js +243 -0
- package/src/verax/core/product-definition.js +127 -0
- package/src/verax/core/release/provenance.builder.js +130 -0
- package/src/verax/core/release/release-report-writer.js +40 -0
- package/src/verax/core/release/release.enforcer.js +164 -0
- package/src/verax/core/release/reproducibility.check.js +222 -0
- package/src/verax/core/release/sbom.builder.js +292 -0
- package/src/verax/core/replay-validator.js +2 -0
- package/src/verax/core/replay.js +4 -0
- package/src/verax/core/report/cross-index.js +195 -0
- package/src/verax/core/report/human-summary.js +362 -0
- package/src/verax/core/route-intelligence.js +420 -0
- package/src/verax/core/run-id.js +6 -3
- package/src/verax/core/run-manifest.js +4 -3
- package/src/verax/core/security/secrets.scan.js +329 -0
- package/src/verax/core/security/security-report.js +50 -0
- package/src/verax/core/security/security.enforcer.js +128 -0
- package/src/verax/core/security/supplychain.defaults.json +38 -0
- package/src/verax/core/security/supplychain.policy.js +334 -0
- package/src/verax/core/security/vuln.scan.js +265 -0
- package/src/verax/core/truth/truth.certificate.js +252 -0
- package/src/verax/core/ui-feedback-intelligence.js +481 -0
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +62 -34
- package/src/verax/detect/confidence-helper.js +34 -0
- package/src/verax/detect/dynamic-route-findings.js +338 -0
- package/src/verax/detect/expectation-chain-detector.js +417 -0
- package/src/verax/detect/expectation-model.js +2 -2
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +131 -35
- package/src/verax/detect/flow-detector.js +2 -2
- package/src/verax/detect/form-silent-failure.js +98 -0
- package/src/verax/detect/index.js +46 -5
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +558 -0
- package/src/verax/detect/navigation-silent-failure.js +82 -0
- package/src/verax/detect/problem-aggregator.js +361 -0
- package/src/verax/detect/route-findings.js +219 -0
- package/src/verax/detect/summary-writer.js +477 -0
- package/src/verax/detect/test-failure-cause-inference.js +314 -0
- package/src/verax/detect/ui-feedback-findings.js +207 -0
- package/src/verax/detect/view-switch-correlator.js +242 -0
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +4 -0
- package/src/verax/intel/ts-program.js +1 -0
- package/src/verax/intel/vue-navigation-extractor.js +3 -0
- package/src/verax/learn/action-contract-extractor.js +3 -0
- package/src/verax/learn/ast-contract-extractor.js +1 -1
- package/src/verax/learn/flow-extractor.js +1 -0
- package/src/verax/learn/project-detector.js +5 -0
- package/src/verax/learn/react-router-extractor.js +2 -0
- package/src/verax/learn/source-instrumenter.js +1 -0
- package/src/verax/learn/state-extractor.js +2 -1
- package/src/verax/learn/static-extractor.js +1 -0
- package/src/verax/observe/coverage-gaps.js +132 -0
- package/src/verax/observe/expectation-handler.js +126 -0
- package/src/verax/observe/incremental-skip.js +46 -0
- package/src/verax/observe/index.js +51 -155
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -513
- package/src/verax/observe/network-firewall.js +86 -0
- package/src/verax/observe/observation-builder.js +169 -0
- package/src/verax/observe/observe-context.js +205 -0
- package/src/verax/observe/observe-helpers.js +192 -0
- package/src/verax/observe/observe-runner.js +230 -0
- package/src/verax/observe/observers/budget-observer.js +185 -0
- package/src/verax/observe/observers/console-observer.js +102 -0
- package/src/verax/observe/observers/coverage-observer.js +107 -0
- package/src/verax/observe/observers/interaction-observer.js +471 -0
- package/src/verax/observe/observers/navigation-observer.js +132 -0
- package/src/verax/observe/observers/network-observer.js +87 -0
- package/src/verax/observe/observers/safety-observer.js +82 -0
- package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
- package/src/verax/observe/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-feedback-detector.js +742 -0
- package/src/verax/scan-summary-writer.js +2 -0
- package/src/verax/shared/artifact-manager.js +25 -5
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/css-spinner-rules.js +204 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/view-switch-rules.js +208 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 20 — Svelte State Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects state mutations (reactive stores, assignments) in Svelte components.
|
|
5
|
+
* Only emits state promises if state is user-visible (used in markup bindings).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { extractSvelteSFC, extractTemplateBindings } from './svelte-sfc-extractor.js';
|
|
9
|
+
import { parse } from '@babel/parser';
|
|
10
|
+
import traverse from '@babel/traverse';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Detect state promises in Svelte SFC
|
|
14
|
+
*
|
|
15
|
+
* @param {string} filePath - Path to .svelte file
|
|
16
|
+
* @param {string} content - Full file content
|
|
17
|
+
* @returns {Array} Array of state expectations
|
|
18
|
+
*/
|
|
19
|
+
export function detectSvelteState(filePath, content) {
|
|
20
|
+
const expectations = [];
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const sfc = extractSvelteSFC(content);
|
|
24
|
+
const { scriptBlocks, markup } = sfc;
|
|
25
|
+
|
|
26
|
+
// Extract template bindings to identify user-visible state
|
|
27
|
+
const templateBindings = markup ? extractTemplateBindings(markup.content) : { bindings: [], reactiveStatements: [] };
|
|
28
|
+
|
|
29
|
+
// Collect all state variables used in template
|
|
30
|
+
const templateStateVars = new Set();
|
|
31
|
+
|
|
32
|
+
// From bindings: bind:value="count"
|
|
33
|
+
templateBindings.bindings.forEach(binding => {
|
|
34
|
+
templateStateVars.add(binding.variable);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// From reactive statements: $: doubled = count * 2
|
|
38
|
+
templateBindings.reactiveStatements.forEach(stmt => {
|
|
39
|
+
// Extract variable names from reactive statements
|
|
40
|
+
const varMatch = stmt.statement.match(/^\s*(\w+)\s*=/);
|
|
41
|
+
if (varMatch) {
|
|
42
|
+
templateStateVars.add(varMatch[1]);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// From markup: {count}, {#if isOpen}, etc.
|
|
47
|
+
if (markup && markup.content) {
|
|
48
|
+
// Extract {variable} patterns
|
|
49
|
+
const varPattern = /\{([a-zA-Z_$][a-zA-Z0-9_$]*)\}/g;
|
|
50
|
+
let varMatch;
|
|
51
|
+
while ((varMatch = varPattern.exec(markup.content)) !== null) {
|
|
52
|
+
templateStateVars.add(varMatch[1]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Extract {#if variable} patterns
|
|
56
|
+
const ifPattern = /\{#if\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\}/g;
|
|
57
|
+
let ifMatch;
|
|
58
|
+
while ((ifMatch = ifPattern.exec(markup.content)) !== null) {
|
|
59
|
+
templateStateVars.add(ifMatch[1]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Process script blocks to find state mutations
|
|
64
|
+
for (const scriptBlock of scriptBlocks) {
|
|
65
|
+
if (!scriptBlock.content) continue;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const ast = parse(scriptBlock.content, {
|
|
69
|
+
sourceType: 'module',
|
|
70
|
+
plugins: ['typescript', 'jsx'],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Track reactive store declarations
|
|
74
|
+
const reactiveStores = new Map();
|
|
75
|
+
|
|
76
|
+
traverse.default(ast, {
|
|
77
|
+
// Detect reactive store declarations: $store, writable(), readable()
|
|
78
|
+
VariableDeclarator(path) {
|
|
79
|
+
const { node } = path;
|
|
80
|
+
if (node.init) {
|
|
81
|
+
// Detect writable() stores
|
|
82
|
+
if (
|
|
83
|
+
node.init.type === 'CallExpression' &&
|
|
84
|
+
node.init.callee.name === 'writable'
|
|
85
|
+
) {
|
|
86
|
+
const storeName = node.id.name;
|
|
87
|
+
reactiveStores.set(storeName, 'writable');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Detect readable() stores
|
|
91
|
+
if (
|
|
92
|
+
node.init.type === 'CallExpression' &&
|
|
93
|
+
node.init.callee.name === 'readable'
|
|
94
|
+
) {
|
|
95
|
+
const storeName = node.id.name;
|
|
96
|
+
reactiveStores.set(storeName, 'readable');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
// Detect store mutations: $store = value, store.set(value), store.update(fn)
|
|
102
|
+
AssignmentExpression(path) {
|
|
103
|
+
const { node } = path;
|
|
104
|
+
|
|
105
|
+
// Detect direct assignments: count = 5
|
|
106
|
+
if (node.left.type === 'Identifier') {
|
|
107
|
+
const varName = node.left.name;
|
|
108
|
+
|
|
109
|
+
// Only emit if variable is used in template
|
|
110
|
+
if (templateStateVars.has(varName)) {
|
|
111
|
+
const location = node.loc;
|
|
112
|
+
const line = scriptBlock.startLine + (location ? location.start.line - 1 : 0);
|
|
113
|
+
|
|
114
|
+
expectations.push({
|
|
115
|
+
type: 'state',
|
|
116
|
+
expectedTarget: varName,
|
|
117
|
+
context: 'assignment',
|
|
118
|
+
sourceRef: {
|
|
119
|
+
file: filePath,
|
|
120
|
+
line,
|
|
121
|
+
snippet: scriptBlock.content.substring(
|
|
122
|
+
node.start - (ast.program.body[0]?.start || 0),
|
|
123
|
+
node.end - (ast.program.body[0]?.start || 0)
|
|
124
|
+
),
|
|
125
|
+
},
|
|
126
|
+
proof: 'PROVEN_EXPECTATION',
|
|
127
|
+
metadata: {
|
|
128
|
+
templateUsage: Array.from(templateStateVars).filter(v => v === varName).length,
|
|
129
|
+
stateType: 'variable',
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Detect store assignments: $store = value
|
|
136
|
+
if (
|
|
137
|
+
node.left.type === 'Identifier' &&
|
|
138
|
+
node.left.name.startsWith('$') &&
|
|
139
|
+
reactiveStores.has(node.left.name.substring(1))
|
|
140
|
+
) {
|
|
141
|
+
const storeName = node.left.name.substring(1);
|
|
142
|
+
const location = node.loc;
|
|
143
|
+
const line = scriptBlock.startLine + (location ? location.start.line - 1 : 0);
|
|
144
|
+
|
|
145
|
+
expectations.push({
|
|
146
|
+
type: 'state',
|
|
147
|
+
expectedTarget: storeName,
|
|
148
|
+
context: 'store-assignment',
|
|
149
|
+
sourceRef: {
|
|
150
|
+
file: filePath,
|
|
151
|
+
line,
|
|
152
|
+
snippet: scriptBlock.content.substring(
|
|
153
|
+
node.start - (ast.program.body[0]?.start || 0),
|
|
154
|
+
node.end - (ast.program.body[0]?.start || 0)
|
|
155
|
+
),
|
|
156
|
+
},
|
|
157
|
+
proof: 'PROVEN_EXPECTATION',
|
|
158
|
+
metadata: {
|
|
159
|
+
stateType: 'store',
|
|
160
|
+
storeType: reactiveStores.get(storeName),
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// Detect store.set() calls
|
|
167
|
+
CallExpression(path) {
|
|
168
|
+
const { node } = path;
|
|
169
|
+
|
|
170
|
+
if (
|
|
171
|
+
node.callee.type === 'MemberExpression' &&
|
|
172
|
+
node.callee.property.name === 'set' &&
|
|
173
|
+
node.callee.object.type === 'Identifier' &&
|
|
174
|
+
reactiveStores.has(node.callee.object.name)
|
|
175
|
+
) {
|
|
176
|
+
const storeName = node.callee.object.name;
|
|
177
|
+
const location = node.loc;
|
|
178
|
+
const line = scriptBlock.startLine + (location ? location.start.line - 1 : 0);
|
|
179
|
+
|
|
180
|
+
expectations.push({
|
|
181
|
+
type: 'state',
|
|
182
|
+
expectedTarget: storeName,
|
|
183
|
+
context: 'store-set',
|
|
184
|
+
sourceRef: {
|
|
185
|
+
file: filePath,
|
|
186
|
+
line,
|
|
187
|
+
snippet: scriptBlock.content.substring(
|
|
188
|
+
node.start - (ast.program.body[0]?.start || 0),
|
|
189
|
+
node.end - (ast.program.body[0]?.start || 0)
|
|
190
|
+
),
|
|
191
|
+
},
|
|
192
|
+
proof: 'PROVEN_EXPECTATION',
|
|
193
|
+
metadata: {
|
|
194
|
+
stateType: 'store',
|
|
195
|
+
storeType: reactiveStores.get(storeName),
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Detect store.update() calls
|
|
201
|
+
if (
|
|
202
|
+
node.callee.type === 'MemberExpression' &&
|
|
203
|
+
node.callee.property.name === 'update' &&
|
|
204
|
+
node.callee.object.type === 'Identifier' &&
|
|
205
|
+
reactiveStores.has(node.callee.object.name)
|
|
206
|
+
) {
|
|
207
|
+
const storeName = node.callee.object.name;
|
|
208
|
+
const location = node.loc;
|
|
209
|
+
const line = scriptBlock.startLine + (location ? location.start.line - 1 : 0);
|
|
210
|
+
|
|
211
|
+
expectations.push({
|
|
212
|
+
type: 'state',
|
|
213
|
+
expectedTarget: storeName,
|
|
214
|
+
context: 'store-update',
|
|
215
|
+
sourceRef: {
|
|
216
|
+
file: filePath,
|
|
217
|
+
line,
|
|
218
|
+
snippet: scriptBlock.content.substring(
|
|
219
|
+
node.start - (ast.program.body[0]?.start || 0),
|
|
220
|
+
node.end - (ast.program.body[0]?.start || 0)
|
|
221
|
+
),
|
|
222
|
+
},
|
|
223
|
+
proof: 'PROVEN_EXPECTATION',
|
|
224
|
+
metadata: {
|
|
225
|
+
stateType: 'store',
|
|
226
|
+
storeType: reactiveStores.get(storeName),
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
} catch (parseError) {
|
|
233
|
+
// Skip if parsing fails
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
} catch (error) {
|
|
237
|
+
// Skip if extraction fails
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return expectations;
|
|
241
|
+
}
|
|
242
|
+
|