bulltrackers-module 1.0.635 → 1.0.637

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.
@@ -44,7 +44,9 @@ async function fetchDependencies(date, calcs, config, deps, manifestLookup = {})
44
44
  const dStr = date.toISOString().slice(0, 10);
45
45
 
46
46
  // 1. Identify unique dependencies needed
47
- const needed = new Set();
47
+ // CHANGED: Use a Map to track { normalizedName: originalName }
48
+ const needed = new Map();
49
+
48
50
  calcs.forEach(c => {
49
51
  // [FIX] Support both .getDependencies() method and .dependencies array
50
52
  const reqs = (typeof c.getDependencies === 'function')
@@ -52,7 +54,12 @@ async function fetchDependencies(date, calcs, config, deps, manifestLookup = {})
52
54
  : (c.dependencies || []);
53
55
 
54
56
  if (Array.isArray(reqs)) {
55
- reqs.forEach(r => needed.add(normalizeName(r)));
57
+ reqs.forEach(r => {
58
+ // We map the normalized version to the original requested version
59
+ // This ensures we fetch the right file (normalized) but return it
60
+ // with the casing the user code expects (original).
61
+ needed.set(normalizeName(r), r);
62
+ });
56
63
  }
57
64
  });
58
65
 
@@ -61,14 +68,20 @@ async function fetchDependencies(date, calcs, config, deps, manifestLookup = {})
61
68
  logger.log('INFO', `[DependencyFetcher] Fetching ${needed.size} dependencies for ${dStr}`);
62
69
 
63
70
  const results = {};
64
- const promises = Array.from(needed).map(async (name) => {
71
+ // CHANGED: Iterate over the entries to access both normalized and original names
72
+ const promises = Array.from(needed.entries()).map(async ([normName, originalName]) => {
65
73
  try {
66
74
  // Resolve Category from Lookup, default to 'analytics' if unknown
67
- const category = manifestLookup[name] || 'analytics';
68
- const data = await fetchSingleResult(db, config, dStr, name, category);
69
- if (data) results[name] = data;
75
+ // Note: manifestLookup keys are expected to be normalized
76
+ const category = manifestLookup[normName] || 'analytics';
77
+
78
+ // Fetch using the normalized name (system standard)
79
+ const data = await fetchSingleResult(db, config, dStr, normName, category);
80
+
81
+ // CHANGED: Store result using the ORIGINAL name so context.computed['CaseSensitive'] works
82
+ if (data) results[originalName] = data;
70
83
  } catch (e) {
71
- logger.log('WARN', `[DependencyFetcher] Failed to load dependency ${name}: ${e.message}`);
84
+ logger.log('WARN', `[DependencyFetcher] Failed to load dependency ${originalName}: ${e.message}`);
72
85
  }
73
86
  });
74
87
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @fileoverview Comprehensive Computation Validator
3
3
  * Validates computation structure, metadata, and code compliance during build
4
+ * UPDATED: Added Static Dependency Verification to prove context.computed access.
4
5
  */
5
6
 
6
7
  const acorn = require('acorn');
@@ -134,7 +135,8 @@ class ComputationValidator {
134
135
  this.validateDependencies(dependencies, name);
135
136
 
136
137
  // 4. Code Analysis (AST)
137
- this.validateCode(CalcClass, name, metadata);
138
+ // UPDATED: Passing dependencies to enable context.computed verification
139
+ this.validateCode(CalcClass, name, metadata, dependencies);
138
140
 
139
141
  // 5. Schema Validation (if present)
140
142
  if (typeof CalcClass.getSchema === 'function') {
@@ -305,7 +307,7 @@ class ComputationValidator {
305
307
  /**
306
308
  * 4. Code Analysis (AST-based)
307
309
  */
308
- validateCode(CalcClass, name, metadata) {
310
+ validateCode(CalcClass, name, metadata, dependencies) {
309
311
  const processSource = CalcClass.prototype.process.toString();
310
312
 
311
313
  // Parse AST
@@ -336,6 +338,8 @@ class ComputationValidator {
336
338
  this.analyzeContextUsage(ast, name, metadata);
337
339
  this.analyzeLayerUsage(ast, name);
338
340
  this.analyzeResultAssignment(ast, name, metadata);
341
+ // UPDATED: Analyze Dependency Validity
342
+ this.analyzeDependencyUsage(ast, name, dependencies);
339
343
  }
340
344
 
341
345
  analyzeContextUsage(ast, name, metadata) {
@@ -386,6 +390,52 @@ class ComputationValidator {
386
390
  });
387
391
  }
388
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
+
389
439
  analyzeResultAssignment(ast, name, metadata) {
390
440
  let assignsToResults = false;
391
441
  let hasReturn = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.635",
3
+ "version": "1.0.637",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [