bulltrackers-module 1.0.732 → 1.0.734

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 (106) hide show
  1. package/functions/computation-system-v2/README.md +152 -0
  2. package/functions/computation-system-v2/computations/PopularInvestorProfileMetrics.js +720 -0
  3. package/functions/computation-system-v2/computations/PopularInvestorRiskAssessment.js +176 -0
  4. package/functions/computation-system-v2/computations/PopularInvestorRiskMetrics.js +294 -0
  5. package/functions/computation-system-v2/computations/TestComputation.js +46 -0
  6. package/functions/computation-system-v2/computations/UserPortfolioSummary.js +172 -0
  7. package/functions/computation-system-v2/config/bulltrackers.config.js +317 -0
  8. package/functions/computation-system-v2/framework/core/Computation.js +73 -0
  9. package/functions/computation-system-v2/framework/core/Manifest.js +223 -0
  10. package/functions/computation-system-v2/framework/core/RuleInjector.js +53 -0
  11. package/functions/computation-system-v2/framework/core/Rules.js +231 -0
  12. package/functions/computation-system-v2/framework/core/RunAnalyzer.js +163 -0
  13. package/functions/computation-system-v2/framework/cost/CostTracker.js +154 -0
  14. package/functions/computation-system-v2/framework/data/DataFetcher.js +399 -0
  15. package/functions/computation-system-v2/framework/data/QueryBuilder.js +232 -0
  16. package/functions/computation-system-v2/framework/data/SchemaRegistry.js +287 -0
  17. package/functions/computation-system-v2/framework/execution/Orchestrator.js +498 -0
  18. package/functions/computation-system-v2/framework/execution/TaskRunner.js +35 -0
  19. package/functions/computation-system-v2/framework/execution/middleware/CostTrackerMiddleware.js +32 -0
  20. package/functions/computation-system-v2/framework/execution/middleware/LineageMiddleware.js +32 -0
  21. package/functions/computation-system-v2/framework/execution/middleware/Middleware.js +14 -0
  22. package/functions/computation-system-v2/framework/execution/middleware/ProfilerMiddleware.js +47 -0
  23. package/functions/computation-system-v2/framework/index.js +45 -0
  24. package/functions/computation-system-v2/framework/lineage/LineageTracker.js +147 -0
  25. package/functions/computation-system-v2/framework/monitoring/Profiler.js +80 -0
  26. package/functions/computation-system-v2/framework/resilience/Checkpointer.js +66 -0
  27. package/functions/computation-system-v2/framework/scheduling/ScheduleValidator.js +327 -0
  28. package/functions/computation-system-v2/framework/storage/StateRepository.js +286 -0
  29. package/functions/computation-system-v2/framework/storage/StorageManager.js +469 -0
  30. package/functions/computation-system-v2/framework/storage/index.js +9 -0
  31. package/functions/computation-system-v2/framework/testing/ComputationTester.js +86 -0
  32. package/functions/computation-system-v2/framework/utils/Graph.js +205 -0
  33. package/functions/computation-system-v2/handlers/dispatcher.js +109 -0
  34. package/functions/computation-system-v2/handlers/index.js +23 -0
  35. package/functions/computation-system-v2/handlers/onDemand.js +289 -0
  36. package/functions/computation-system-v2/handlers/scheduler.js +327 -0
  37. package/functions/computation-system-v2/index.js +163 -0
  38. package/functions/computation-system-v2/rules/index.js +49 -0
  39. package/functions/computation-system-v2/rules/instruments.js +465 -0
  40. package/functions/computation-system-v2/rules/metrics.js +304 -0
  41. package/functions/computation-system-v2/rules/portfolio.js +534 -0
  42. package/functions/computation-system-v2/rules/rankings.js +655 -0
  43. package/functions/computation-system-v2/rules/social.js +562 -0
  44. package/functions/computation-system-v2/rules/trades.js +545 -0
  45. package/functions/computation-system-v2/scripts/migrate-sectors.js +73 -0
  46. package/functions/computation-system-v2/test/test-dispatcher.js +317 -0
  47. package/functions/computation-system-v2/test/test-framework.js +500 -0
  48. package/functions/computation-system-v2/test/test-real-execution.js +166 -0
  49. package/functions/computation-system-v2/test/test-real-integration.js +194 -0
  50. package/functions/computation-system-v2/test/test-refactor-e2e.js +131 -0
  51. package/functions/computation-system-v2/test/test-results.json +31 -0
  52. package/functions/computation-system-v2/test/test-risk-metrics-computation.js +329 -0
  53. package/functions/computation-system-v2/test/test-scheduler.js +204 -0
  54. package/functions/computation-system-v2/test/test-storage.js +449 -0
  55. package/functions/orchestrator/index.js +24 -30
  56. package/index.js +8 -29
  57. package/package.json +3 -2
  58. package/functions/computation-system/WorkflowOrchestrator.js +0 -213
  59. package/functions/computation-system/config/monitoring_config.js +0 -31
  60. package/functions/computation-system/config/validation_overrides.js +0 -10
  61. package/functions/computation-system/context/ContextFactory.js +0 -143
  62. package/functions/computation-system/context/ManifestBuilder.js +0 -379
  63. package/functions/computation-system/data/AvailabilityChecker.js +0 -236
  64. package/functions/computation-system/data/CachedDataLoader.js +0 -325
  65. package/functions/computation-system/data/DependencyFetcher.js +0 -455
  66. package/functions/computation-system/executors/MetaExecutor.js +0 -279
  67. package/functions/computation-system/executors/PriceBatchExecutor.js +0 -108
  68. package/functions/computation-system/executors/StandardExecutor.js +0 -465
  69. package/functions/computation-system/helpers/computation_dispatcher.js +0 -750
  70. package/functions/computation-system/helpers/computation_worker.js +0 -375
  71. package/functions/computation-system/helpers/monitor.js +0 -64
  72. package/functions/computation-system/helpers/on_demand_helpers.js +0 -154
  73. package/functions/computation-system/layers/extractors.js +0 -1097
  74. package/functions/computation-system/layers/index.js +0 -40
  75. package/functions/computation-system/layers/mathematics.js +0 -522
  76. package/functions/computation-system/layers/profiling.js +0 -537
  77. package/functions/computation-system/layers/validators.js +0 -170
  78. package/functions/computation-system/legacy/AvailabilityCheckerOld.js +0 -388
  79. package/functions/computation-system/legacy/CachedDataLoaderOld.js +0 -357
  80. package/functions/computation-system/legacy/DependencyFetcherOld.js +0 -478
  81. package/functions/computation-system/legacy/MetaExecutorold.js +0 -364
  82. package/functions/computation-system/legacy/StandardExecutorold.js +0 -476
  83. package/functions/computation-system/legacy/computation_dispatcherold.js +0 -944
  84. package/functions/computation-system/logger/logger.js +0 -297
  85. package/functions/computation-system/persistence/ContractValidator.js +0 -81
  86. package/functions/computation-system/persistence/FirestoreUtils.js +0 -56
  87. package/functions/computation-system/persistence/ResultCommitter.js +0 -283
  88. package/functions/computation-system/persistence/ResultsValidator.js +0 -130
  89. package/functions/computation-system/persistence/RunRecorder.js +0 -142
  90. package/functions/computation-system/persistence/StatusRepository.js +0 -52
  91. package/functions/computation-system/reporter_epoch.js +0 -6
  92. package/functions/computation-system/scripts/UpdateContracts.js +0 -128
  93. package/functions/computation-system/services/SnapshotService.js +0 -148
  94. package/functions/computation-system/simulation/Fabricator.js +0 -285
  95. package/functions/computation-system/simulation/SeededRandom.js +0 -41
  96. package/functions/computation-system/simulation/SimRunner.js +0 -51
  97. package/functions/computation-system/system_epoch.js +0 -2
  98. package/functions/computation-system/tools/BuildReporter.js +0 -531
  99. package/functions/computation-system/tools/ContractDiscoverer.js +0 -144
  100. package/functions/computation-system/tools/DeploymentValidator.js +0 -536
  101. package/functions/computation-system/tools/FinalSweepReporter.js +0 -322
  102. package/functions/computation-system/topology/HashManager.js +0 -55
  103. package/functions/computation-system/topology/ManifestLoader.js +0 -47
  104. package/functions/computation-system/utils/data_loader.js +0 -675
  105. package/functions/computation-system/utils/schema_capture.js +0 -121
  106. package/functions/computation-system/utils/utils.js +0 -188
@@ -1,536 +0,0 @@
1
- /**
2
- * @fileoverview Comprehensive Computation Validator
3
- * Validates computation structure, metadata, and code compliance during build
4
- * UPDATED: Added Static Dependency Verification to prove context.computed access.
5
- */
6
-
7
- const acorn = require('acorn');
8
- const walk = require('acorn-walk');
9
-
10
- // Import allowed layer exports for validation
11
- const mathLayer = require('../layers/mathematics');
12
- const extractorsLayer = require('../layers/extractors');
13
- const profilingLayer = require('../layers/profiling');
14
- const validatorsLayer = require('../layers/validators');
15
-
16
- /**
17
- * VALIDATION RULESET CONFIGURATION
18
- */
19
- const VALIDATION_RULES = {
20
- // Allowed metadata fields
21
- ALLOWED_METADATA_FIELDS: new Set([
22
- 'name', 'type', 'category', 'isPage', 'isHistorical', 'isTest',
23
- 'rootDataDependencies', 'rootDataSeries', 'dependencySeries',
24
- 'mandatoryRoots', 'canHaveMissingRoots', 'canHaveMissingSeries',
25
- 'userType', 'schedule', 'ttlDays', 'isAlertComputation',
26
- 'requiresEarliestDataDate'
27
- ]),
28
-
29
- // Valid computation types
30
- VALID_TYPES: new Set(['standard', 'meta']),
31
-
32
- // Valid user types
33
- VALID_USER_TYPES: new Set([
34
- 'all', 'normal', 'speculator', 'popular_investor', 'signed_in_user',
35
- 'NORMAL', 'SPECULATOR', 'POPULAR_INVESTOR', 'SIGNED_IN_USER'
36
- ]),
37
-
38
- // Valid root data dependencies
39
- VALID_ROOT_DATA_DEPS: new Set([
40
- 'portfolio', 'history', 'social', 'insights', 'price',
41
- 'rankings', 'verification', 'ratings', 'pageViews',
42
- 'watchlist', 'alerts', 'piMasterList'
43
- ]),
44
-
45
- // Valid schedule types
46
- VALID_SCHEDULE_TYPES: new Set(['DAILY', 'WEEKLY', 'MONTHLY']),
47
-
48
- // Context structure for 'standard' type
49
- STANDARD_CONTEXT_STRUCTURE: new Set([
50
- 'user', 'date', 'insights', 'social', 'mappings', 'math',
51
- 'computed', 'previousComputed', 'meta', 'config', 'deps',
52
- 'globalData', 'system'
53
- ]),
54
-
55
- // Context structure for 'meta' type
56
- META_CONTEXT_STRUCTURE: new Set([
57
- 'date', 'insights', 'social', 'prices', 'mappings', 'math',
58
- 'computed', 'previousComputed', 'meta', 'config', 'deps',
59
- 'globalData'
60
- ]),
61
-
62
- // Allowed layer functions (built dynamically)
63
- ALLOWED_LAYER_FUNCTIONS: new Map(),
64
-
65
- // Forbidden patterns
66
- FORBIDDEN_PATTERNS: [
67
- { pattern: /localStorage/g, message: 'localStorage is not supported in Cloud Functions' },
68
- { pattern: /sessionStorage/g, message: 'sessionStorage is not supported in Cloud Functions' },
69
- { pattern: /window\./g, message: 'window object is not available in Node.js environment' },
70
- { pattern: /document\./g, message: 'document object is not available in Node.js environment' },
71
- { pattern: /require\(/g, message: 'Dynamic require() is forbidden. Use dependency injection.' },
72
- { pattern: /eval\(/g, message: 'eval() is forbidden for security reasons' },
73
- { pattern: /Function\(/g, message: 'Function constructor is forbidden for security reasons' }
74
- ],
75
-
76
- // Warning patterns (non-blocking)
77
- WARNING_PATTERNS: [
78
- { pattern: /console\.log/g, message: 'Use context.deps.logger instead of console.log' },
79
- { pattern: /Math\.random/g, message: 'Math.random() is non-deterministic. Consider using SeededRandom for reproducibility.' },
80
- { pattern: /new Date\(\)/g, message: 'new Date() without arguments may cause timezone issues. Use context.date.today.' }
81
- ]
82
- };
83
-
84
- // Build allowed layer functions map
85
- function buildLayerFunctionsMap() {
86
- const map = new Map();
87
-
88
- const layers = {
89
- math: mathLayer,
90
- extractors: extractorsLayer,
91
- profiling: profilingLayer,
92
- validators: validatorsLayer
93
- };
94
-
95
- for (const [layerName, layerExports] of Object.entries(layers)) {
96
- for (const exportName of Object.keys(layerExports)) {
97
- const fullPath = `${layerName}.${exportName}`;
98
- map.set(fullPath, { layer: layerName, export: exportName });
99
-
100
- // Also allow direct access (e.g., MathPrimitives)
101
- map.set(exportName, { layer: layerName, export: exportName });
102
- }
103
- }
104
-
105
- return map;
106
- }
107
-
108
- VALIDATION_RULES.ALLOWED_LAYER_FUNCTIONS = buildLayerFunctionsMap();
109
-
110
- /**
111
- * MAIN VALIDATOR CLASS
112
- */
113
- class ComputationValidator {
114
- constructor() {
115
- this.errors = [];
116
- this.warnings = [];
117
- }
118
-
119
- /**
120
- * Validates a single calculation class
121
- */
122
- validate(CalcClass) {
123
- const name = CalcClass.name || 'Unknown';
124
-
125
- try {
126
- // 1. Structural Validation
127
- this.validateStructure(CalcClass, name);
128
-
129
- // 2. Metadata Validation
130
- const metadata = CalcClass.getMetadata();
131
- this.validateMetadata(metadata, name);
132
-
133
- // 3. Dependencies Validation
134
- const dependencies = CalcClass.getDependencies();
135
- this.validateDependencies(dependencies, name);
136
-
137
- // 4. Code Analysis (AST)
138
- // UPDATED: Passing dependencies to enable context.computed verification
139
- this.validateCode(CalcClass, name, metadata, dependencies);
140
-
141
- // 5. Schema Validation (if present)
142
- if (typeof CalcClass.getSchema === 'function') {
143
- this.validateSchema(CalcClass.getSchema(), name);
144
- }
145
-
146
- } catch (e) {
147
- this.errors.push(`[${name}] Validation crashed: ${e.message}`);
148
- }
149
- }
150
-
151
- /**
152
- * 1. Structural Validation
153
- */
154
- validateStructure(CalcClass, name) {
155
- const proto = CalcClass.prototype;
156
-
157
- // Required static methods
158
- if (typeof CalcClass.getMetadata !== 'function') {
159
- this.errors.push(`[${name}] Missing static getMetadata() method`);
160
- }
161
-
162
- if (typeof CalcClass.getDependencies !== 'function') {
163
- this.errors.push(`[${name}] Missing static getDependencies() method`);
164
- }
165
-
166
- // Required instance methods
167
- if (typeof proto.process !== 'function') {
168
- this.errors.push(`[${name}] Missing process() instance method`);
169
- }
170
-
171
- if (typeof proto.getResult !== 'function') {
172
- this.errors.push(`[${name}] Missing getResult() instance method`);
173
- }
174
- }
175
-
176
- /**
177
- * 2. Metadata Validation
178
- */
179
- validateMetadata(metadata, name) {
180
- if (!metadata || typeof metadata !== 'object') {
181
- this.errors.push(`[${name}] getMetadata() must return an object`);
182
- return;
183
- }
184
-
185
- // Check for unknown fields
186
- for (const field of Object.keys(metadata)) {
187
- if (!VALIDATION_RULES.ALLOWED_METADATA_FIELDS.has(field)) {
188
- this.warnings.push(`[${name}] Unknown metadata field: "${field}"`);
189
- }
190
- }
191
-
192
- // Validate type
193
- if (!metadata.type) {
194
- this.errors.push(`[${name}] Missing required metadata field: "type"`);
195
- } else if (!VALIDATION_RULES.VALID_TYPES.has(metadata.type)) {
196
- this.errors.push(`[${name}] Invalid type "${metadata.type}". Must be "standard" or "meta"`);
197
- }
198
-
199
- // Validate category
200
- if (!metadata.category) {
201
- this.warnings.push(`[${name}] Missing metadata field: "category"`);
202
- }
203
-
204
- // Validate userType (for standard computations)
205
- if (metadata.type === 'standard') {
206
- if (!metadata.userType) {
207
- this.warnings.push(`[${name}] Standard computation missing userType. Defaulting to "all"`);
208
- } else if (!VALIDATION_RULES.VALID_USER_TYPES.has(metadata.userType)) {
209
- this.errors.push(`[${name}] Invalid userType "${metadata.userType}"`);
210
- }
211
- }
212
-
213
- // Validate rootDataDependencies
214
- if (metadata.rootDataDependencies) {
215
- if (!Array.isArray(metadata.rootDataDependencies)) {
216
- this.errors.push(`[${name}] rootDataDependencies must be an array`);
217
- } else {
218
- for (const dep of metadata.rootDataDependencies) {
219
- if (!VALIDATION_RULES.VALID_ROOT_DATA_DEPS.has(dep)) {
220
- this.errors.push(`[${name}] Invalid root data dependency: "${dep}"`);
221
- }
222
- }
223
- }
224
- }
225
-
226
- // Validate schedule
227
- if (metadata.schedule) {
228
- if (!metadata.schedule.type || !VALIDATION_RULES.VALID_SCHEDULE_TYPES.has(metadata.schedule.type)) {
229
- this.errors.push(`[${name}] Invalid schedule type. Must be DAILY, WEEKLY, or MONTHLY`);
230
- }
231
-
232
- if (metadata.schedule.type === 'WEEKLY' && !metadata.schedule.days) {
233
- this.errors.push(`[${name}] Weekly schedule missing "days" array`);
234
- }
235
-
236
- if (metadata.schedule.type === 'MONTHLY' && !metadata.schedule.days) {
237
- this.errors.push(`[${name}] Monthly schedule missing "days" array`);
238
- }
239
- }
240
-
241
- // Validate TTL
242
- if (metadata.ttlDays !== undefined) {
243
- if (typeof metadata.ttlDays !== 'number' || metadata.ttlDays < 0) {
244
- this.errors.push(`[${name}] ttlDays must be a positive number`);
245
- }
246
- }
247
-
248
- // Validate boolean flags
249
- const booleanFields = ['isPage', 'isHistorical', 'isTest', 'canHaveMissingRoots', 'canHaveMissingSeries', 'isAlertComputation'];
250
- for (const field of booleanFields) {
251
- if (metadata[field] !== undefined && typeof metadata[field] !== 'boolean') {
252
- this.errors.push(`[${name}] ${field} must be a boolean`);
253
- }
254
- }
255
-
256
- // Validate series configurations
257
- if (metadata.rootDataSeries) {
258
- this.validateSeriesConfig(metadata.rootDataSeries, name, 'rootDataSeries');
259
- }
260
-
261
- if (metadata.dependencySeries) {
262
- this.validateSeriesConfig(metadata.dependencySeries, name, 'dependencySeries');
263
- }
264
- }
265
-
266
- validateSeriesConfig(seriesConfig, name, fieldName) {
267
- if (typeof seriesConfig !== 'object') {
268
- this.errors.push(`[${name}] ${fieldName} must be an object`);
269
- return;
270
- }
271
-
272
- for (const [key, config] of Object.entries(seriesConfig)) {
273
- if (typeof config === 'number') {
274
- if (config < 1 || config > 365) {
275
- this.warnings.push(`[${name}] ${fieldName}.${key} lookback of ${config} days seems unusual`);
276
- }
277
- } else if (typeof config === 'object') {
278
- if (!config.lookback || typeof config.lookback !== 'number') {
279
- this.errors.push(`[${name}] ${fieldName}.${key} missing valid lookback property`);
280
- }
281
- } else {
282
- this.errors.push(`[${name}] ${fieldName}.${key} must be a number or object with lookback`);
283
- }
284
- }
285
- }
286
-
287
- /**
288
- * 3. Dependencies Validation
289
- */
290
- validateDependencies(dependencies, name) {
291
- if (!Array.isArray(dependencies)) {
292
- this.errors.push(`[${name}] getDependencies() must return an array`);
293
- return;
294
- }
295
-
296
- // Check for self-dependency
297
- if (dependencies.includes(name)) {
298
- this.errors.push(`[${name}] Computation cannot depend on itself`);
299
- }
300
-
301
- // Warn about empty dependencies for complex calculations
302
- if (dependencies.length === 0) {
303
- this.warnings.push(`[${name}] No dependencies declared. Is this intentional?`);
304
- }
305
- }
306
-
307
- /**
308
- * 4. Code Analysis (AST-based)
309
- */
310
- validateCode(CalcClass, name, metadata, dependencies) {
311
- const processSource = CalcClass.prototype.process.toString();
312
-
313
- // Parse AST
314
- let ast;
315
- try {
316
- const wrappedSource = `class __Guard { ${processSource} }`;
317
- ast = acorn.parse(wrappedSource, { ecmaVersion: 2022, sourceType: 'script' });
318
- } catch (parseError) {
319
- this.errors.push(`[${name}] Failed to parse process() code: ${parseError.message}`);
320
- return;
321
- }
322
-
323
- // Check forbidden patterns
324
- for (const { pattern, message } of VALIDATION_RULES.FORBIDDEN_PATTERNS) {
325
- if (pattern.test(processSource)) {
326
- this.errors.push(`[${name}] ${message}`);
327
- }
328
- }
329
-
330
- // Check warning patterns
331
- for (const { pattern, message } of VALIDATION_RULES.WARNING_PATTERNS) {
332
- if (pattern.test(processSource)) {
333
- this.warnings.push(`[${name}] ${message}`);
334
- }
335
- }
336
-
337
- // AST Analysis
338
- this.analyzeContextUsage(ast, name, metadata);
339
- this.analyzeLayerUsage(ast, name);
340
- this.analyzeResultAssignment(ast, name, metadata);
341
- // UPDATED: Analyze Dependency Validity
342
- this.analyzeDependencyUsage(ast, name, dependencies);
343
- }
344
-
345
- analyzeContextUsage(ast, name, metadata) {
346
- const allowedContext = metadata.type === 'standard'
347
- ? VALIDATION_RULES.STANDARD_CONTEXT_STRUCTURE
348
- : VALIDATION_RULES.META_CONTEXT_STRUCTURE;
349
-
350
- const usedContextProps = new Set();
351
-
352
- walk.simple(ast, {
353
- MemberExpression(node) {
354
- // Check for context.PROPERTY patterns
355
- if (node.object.type === 'Identifier' && node.object.name === 'context') {
356
- if (node.property.type === 'Identifier') {
357
- usedContextProps.add(node.property.name);
358
- }
359
- }
360
- }
361
- });
362
-
363
- // Validate used context properties
364
- for (const prop of usedContextProps) {
365
- if (!allowedContext.has(prop)) {
366
- this.warnings.push(`[${name}] Unknown context property: context.${prop}`);
367
- }
368
- }
369
- }
370
-
371
- analyzeLayerUsage(ast, name) {
372
- walk.simple(ast, {
373
- MemberExpression(node) {
374
- // Check for context.math.FUNCTION patterns
375
- if (node.object.type === 'MemberExpression' &&
376
- node.object.object.type === 'Identifier' &&
377
- node.object.object.name === 'context' &&
378
- node.object.property.name === 'math') {
379
-
380
- if (node.property.type === 'Identifier') {
381
- const funcName = node.property.name;
382
-
383
- // Check if it's a known layer export
384
- if (!VALIDATION_RULES.ALLOWED_LAYER_FUNCTIONS.has(funcName)) {
385
- this.warnings.push(`[${name}] Unknown math layer function: ${funcName}`);
386
- }
387
- }
388
- }
389
- }
390
- });
391
- }
392
-
393
- /**
394
- * [NEW] Analyzes usage of context.computed to ensure variables exist
395
- */
396
- analyzeDependencyUsage(ast, name, dependencies) {
397
- const declaredSet = new Set(dependencies);
398
- const self = this;
399
-
400
- walk.simple(ast, {
401
- MemberExpression(node) {
402
- // Look for: context.computed['Key'] OR context.computed.Key
403
- if (node.object.type === 'MemberExpression' &&
404
- node.object.object.type === 'Identifier' &&
405
- node.object.object.name === 'context' &&
406
- node.object.property.name === 'computed') {
407
-
408
- let accessedKey = null;
409
-
410
- // Case 1: Dot notation (context.computed.SomeDep)
411
- if (!node.computed && node.property.type === 'Identifier') {
412
- accessedKey = node.property.name;
413
- }
414
- // Case 2: Bracket notation with string literal (context.computed['SomeDep'])
415
- else if (node.computed && node.property.type === 'Literal') {
416
- accessedKey = node.property.value;
417
- }
418
-
419
- if (accessedKey) {
420
- if (!declaredSet.has(accessedKey)) {
421
- // Check for casing mismatches to give helpful errors
422
- const caseInsensitiveMatch = dependencies.find(d => d.toLowerCase() === accessedKey.toLowerCase());
423
-
424
- if (caseInsensitiveMatch) {
425
- self.errors.push(`[${name}] Dependency Casing Mismatch: Accessed '${accessedKey}' but declared '${caseInsensitiveMatch}'. Keys are case-sensitive.`);
426
- } else {
427
- self.errors.push(`[${name}] Accessing undeclared dependency: '${accessedKey}'. Add it to getDependencies() or fix the typo.`);
428
- }
429
- }
430
- } else if (node.computed) {
431
- // Dynamic access (e.g. context.computed[someVar])
432
- self.warnings.push(`[${name}] Dynamic access to context.computed detected. Cannot statically verify dependency existence.`);
433
- }
434
- }
435
- }
436
- });
437
- }
438
-
439
- analyzeResultAssignment(ast, name, metadata) {
440
- let assignsToResults = false;
441
- let hasReturn = false;
442
-
443
- walk.simple(ast, {
444
- ReturnStatement(node) {
445
- if (node.argument !== null) hasReturn = true;
446
- },
447
- AssignmentExpression(node) {
448
- let target = node.left;
449
- while (target && target.type === 'MemberExpression') {
450
- if (target.object.type === 'ThisExpression' &&
451
- target.property.name === 'results') {
452
- assignsToResults = true;
453
- break;
454
- }
455
- target = target.object;
456
- }
457
- }
458
- });
459
-
460
- // Contract enforcement
461
- if (metadata.type === 'meta' && !hasReturn) {
462
- this.errors.push(`[${name}] Meta computation missing ReturnStatement in process()`);
463
- }
464
-
465
- if (!assignsToResults && metadata.type === 'standard') {
466
- this.warnings.push(`[${name}] Standard computation never assigns to this.results`);
467
- }
468
- }
469
-
470
- /**
471
- * 5. Schema Validation
472
- */
473
- validateSchema(schema, name) {
474
- if (!schema || typeof schema !== 'object') {
475
- this.warnings.push(`[${name}] getSchema() should return a valid JSON Schema object`);
476
- return;
477
- }
478
-
479
- // Basic schema structure check
480
- if (!schema.type) {
481
- this.warnings.push(`[${name}] Schema missing "type" field`);
482
- }
483
-
484
- // Check for common schema patterns
485
- if (schema.type === 'object') {
486
- if (!schema.properties && !schema.patternProperties) {
487
- this.warnings.push(`[${name}] Object schema has no properties or patternProperties`);
488
- }
489
- }
490
- }
491
-
492
- /**
493
- * Get validation results
494
- */
495
- getResults() {
496
- return {
497
- hasErrors: this.errors.length > 0,
498
- errors: this.errors,
499
- warnings: this.warnings
500
- };
501
- }
502
-
503
- /**
504
- * Generate formatted report
505
- */
506
- generateReport() {
507
- const divider = '='.repeat(80);
508
- const lines = [];
509
-
510
- if (this.errors.length > 0) {
511
- lines.push(`\n${divider}`);
512
- lines.push(`VALIDATION ERRORS (${this.errors.length}):`);
513
- this.errors.forEach((err, i) => {
514
- lines.push(` ${i + 1}. ${err}`);
515
- });
516
- }
517
-
518
- if (this.warnings.length > 0) {
519
- lines.push(`\n${divider}`);
520
- lines.push(`VALIDATION WARNINGS (${this.warnings.length}):`);
521
- this.warnings.forEach((warn, i) => {
522
- lines.push(` ${i + 1}. ${warn}`);
523
- });
524
- }
525
-
526
- if (this.errors.length === 0 && this.warnings.length === 0) {
527
- lines.push(`\n${divider}`);
528
- lines.push('✓ ALL VALIDATIONS PASSED');
529
- }
530
-
531
- lines.push(`${divider}\n`);
532
- return lines.join('\n');
533
- }
534
- }
535
-
536
- module.exports = { ComputationValidator, VALIDATION_RULES };