x-fidelity 3.21.0 → 3.22.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/core/engine/engineRunner.js +76 -8
  3. package/dist/core/engine/engineRunner.test.js +2 -0
  4. package/dist/core/engine/engineSetup.js +55 -4
  5. package/dist/core/engine/errorActionExecutor.d.ts +1 -2
  6. package/dist/core/engine/errorActionExecutor.js +23 -15
  7. package/dist/core/engine/errorActionExecutor.test.js +2 -0
  8. package/dist/facts/globalFileAnalysisFacts.js +1 -3
  9. package/dist/index.js +22 -1
  10. package/dist/notifications/reportGenerator.d.ts +4 -0
  11. package/dist/notifications/reportGenerator.js +62 -3
  12. package/dist/operators/globalPatternCount.js +1 -1
  13. package/dist/operators/globalPatternCount.test.js +2 -2
  14. package/dist/operators/globalPatternRatio.test.js +3 -3
  15. package/dist/types/typeDefs.d.ts +29 -0
  16. package/dist/utils/jsonSchemas.js +6 -0
  17. package/dist/utils/logger.d.ts +2 -0
  18. package/dist/utils/logger.js +15 -0
  19. package/dist/xfidelity +22 -1
  20. package/package.json +1 -1
  21. package/src/core/engine/engineRunner.test.ts +3 -1
  22. package/src/core/engine/engineRunner.ts +84 -2
  23. package/src/core/engine/engineSetup.ts +62 -2
  24. package/src/core/engine/errorActionExecutor.test.ts +3 -1
  25. package/src/core/engine/errorActionExecutor.ts +26 -18
  26. package/src/facts/globalFileAnalysisFacts.ts +1 -3
  27. package/src/index.ts +21 -1
  28. package/src/notifications/reportGenerator.ts +76 -3
  29. package/src/operators/globalPatternCount.test.ts +2 -2
  30. package/src/operators/globalPatternCount.ts +1 -1
  31. package/src/operators/globalPatternRatio.test.ts +3 -3
  32. package/src/types/typeDefs.ts +29 -0
  33. package/src/utils/jsonSchemas.ts +7 -1
  34. package/src/utils/logger.ts +15 -1
  35. package/website/docs/facts.md +119 -4
  36. package/website/docs/operators.md +170 -11
  37. package/xfi-report-2025-04-02.json +23 -11
  38. package/xfi-report-2025-04-02.md +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,39 @@
1
+ # [3.22.0](https://github.com/zotoio/x-fidelity/compare/v3.21.1...v3.22.0) (2025-04-02)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * access operatorThreshold and operatorValue through details property ([e427e94](https://github.com/zotoio/x-fidelity/commit/e427e942aa0072483e02c62fb6e8af967b6a76cc))
7
+ * add missing logger function mocks in test files ([713a1e9](https://github.com/zotoio/x-fidelity/commit/713a1e969142272f4f9e835ede0853c8e92d1620))
8
+ * add ruleName property to BasicTelemetryMetadata interface ([0c66b78](https://github.com/zotoio/x-fidelity/commit/0c66b787986018250f77f727425dfe012400c2e9))
9
+ * add type assertions for conditionType in engineSetup ([734d492](https://github.com/zotoio/x-fidelity/commit/734d492b09e76531c42d712ff0e70a4150761b55))
10
+ * resolve TypeScript type errors and null safety issues ([bfb892d](https://github.com/zotoio/x-fidelity/commit/bfb892d637519f3d4d7b768067e4f478ad74971a))
11
+
12
+
13
+ ### Features
14
+
15
+ * add all condition operators to rule failure details ([023f44f](https://github.com/zotoio/x-fidelity/commit/023f44fffdd82011fc00ea9ae2dabd2ba380e5f7))
16
+ * add all operator value objects to rule results ([c8103c5](https://github.com/zotoio/x-fidelity/commit/c8103c55f60f9da2453305980fe305c57341f961))
17
+ * add backward compatibility for pattern and file output grouping ([db22b70](https://github.com/zotoio/x-fidelity/commit/db22b7084532ddf3edac2b16e7fe30761b15d5d4))
18
+ * add condition details to rule failure output ([168aeec](https://github.com/zotoio/x-fidelity/commit/168aeec2741a22e6706d309b93e361946024a14a))
19
+ * add operator threshold details to rule output and telemetry ([c28974a](https://github.com/zotoio/x-fidelity/commit/c28974a0d1259a943b5afda3ec3f83424c196b16))
20
+ * add operator threshold details to rule output reports ([0ce279d](https://github.com/zotoio/x-fidelity/commit/0ce279d4e480645ba2636beedec5d2fd17f8dadc))
21
+ * add operator value information to report sections ([697a1a3](https://github.com/zotoio/x-fidelity/commit/697a1a36dbb0b6de19b1c5b3be7ca308f757cbbe))
22
+ * add operator value to rule failure details ([ae62f56](https://github.com/zotoio/x-fidelity/commit/ae62f561583209bc8496ff0cd07be597b04909d9))
23
+ * add rule name to log prefix for better traceability ([6a4c4b6](https://github.com/zotoio/x-fidelity/commit/6a4c4b6880c9dfa06bad56a024b3065db771dcdd))
24
+ * enhance rule condition details with descriptions and recommendations ([8eef433](https://github.com/zotoio/x-fidelity/commit/8eef43370c800b5dcb3e9150c858ed7e848abc58))
25
+ * enhance rule condition tracking with detailed condition info ([4e48e7c](https://github.com/zotoio/x-fidelity/commit/4e48e7c63843aef98a6ccbf73cc1252c0e48608c))
26
+ * enhance rule failure reporting with detailed condition information ([915ae09](https://github.com/zotoio/x-fidelity/commit/915ae09a0b3f539d7e48effd3abe26e16d28dee5))
27
+ * enhance XFI_RESULT with detailed rule conditions and recommendations ([7243da5](https://github.com/zotoio/x-fidelity/commit/7243da538f1c37abae2806bc405ec6c251184bb5))
28
+ * include all rule conditions and parameters in output ([ae802bb](https://github.com/zotoio/x-fidelity/commit/ae802bbb41a0613835e4d3e6e477c66abcd8e1ac))
29
+
30
+ ## [3.21.1](https://github.com/zotoio/x-fidelity/compare/v3.21.0...v3.21.1) (2025-04-02)
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * **tests:** logic issue ([1578b81](https://github.com/zotoio/x-fidelity/commit/1578b817ff58912a312e32f5480b2b5f655a1014))
36
+
1
37
  # [3.21.0](https://github.com/zotoio/x-fidelity/compare/v3.20.0...v3.21.0) (2025-04-02)
2
38
 
3
39
 
@@ -15,7 +15,7 @@ const configManager_1 = require("../configManager");
15
15
  const errorActionExecutor_1 = require("./errorActionExecutor");
16
16
  function runEngineOnFiles(params) {
17
17
  return __awaiter(this, void 0, void 0, function* () {
18
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
18
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
19
19
  const { engine, fileData, installedDependencyVersions, minimumDependencyVersions, standardStructure } = params;
20
20
  const msg = `\n==========================\nRUNNING FILE CHECKS..\n==========================`;
21
21
  logger_1.logger.info(msg);
@@ -41,6 +41,8 @@ function runEngineOnFiles(params) {
41
41
  };
42
42
  const fileFailures = [];
43
43
  try {
44
+ // Save the original log prefix
45
+ const originalLogPrefix = (0, logger_1.getLogPrefix)();
44
46
  const { results } = yield engine.run(facts);
45
47
  const seenFailures = new Set();
46
48
  for (const result of results) {
@@ -49,11 +51,66 @@ function runEngineOnFiles(params) {
49
51
  // Create unique key for deduplication
50
52
  const failureKey = `${result.name}:${(_a = result.event) === null || _a === void 0 ? void 0 : _a.type}:${(_c = (_b = result.event) === null || _b === void 0 ? void 0 : _b.params) === null || _c === void 0 ? void 0 : _c.message}`;
51
53
  if (!seenFailures.has(failureKey)) {
54
+ // Set the rule name as log prefix for this failure
55
+ const ruleName = result.name || 'unknown-rule';
56
+ (0, logger_1.setLogPrefix)(`${originalLogPrefix}:${ruleName}`);
57
+ // Extract condition details from the rule
58
+ let conditionDetails = undefined;
59
+ let ruleDescription = null;
60
+ let recommendations = null;
61
+ let allConditions = [];
62
+ let conditionType = 'unknown';
63
+ try {
64
+ // Find the condition that triggered this rule
65
+ const rule = engine.rules.find((r) => r.name === result.name);
66
+ if (rule) {
67
+ // Extract rule description if available
68
+ ruleDescription = rule.description || 'No description available';
69
+ // Extract recommendations if available
70
+ if ((_e = (_d = result.event) === null || _d === void 0 ? void 0 : _d.params) === null || _e === void 0 ? void 0 : _e.recommendations) {
71
+ recommendations = result.event.params.recommendations;
72
+ }
73
+ else if (rule.recommendations) {
74
+ recommendations = rule.recommendations;
75
+ }
76
+ // Extract operator value from the condition
77
+ const conditions = rule.conditions.all || rule.conditions.any || [];
78
+ conditionType = rule.conditions.all ? 'all' : 'any';
79
+ // Capture all conditions with their parameters
80
+ allConditions = conditions.map((condition) => ({
81
+ fact: condition.fact,
82
+ operator: condition.operator,
83
+ value: condition.value,
84
+ params: condition.params,
85
+ path: condition.path,
86
+ priority: condition.priority
87
+ }));
88
+ // Find the first condition with operator and value for backward compatibility
89
+ for (const condition of conditions) {
90
+ if (condition.operator && condition.value !== undefined) {
91
+ conditionDetails = {
92
+ fact: condition.fact,
93
+ operator: condition.operator,
94
+ value: condition.value,
95
+ params: condition.params
96
+ };
97
+ break;
98
+ }
99
+ }
100
+ }
101
+ }
102
+ catch (err) {
103
+ logger_1.logger.debug(`Error extracting operator value: ${err}`);
104
+ }
52
105
  fileFailures.push({
53
106
  ruleFailure: result.name,
54
- level: (_d = result.event) === null || _d === void 0 ? void 0 : _d.type,
55
- details: Object.assign({ message: ((_f = (_e = result.event) === null || _e === void 0 ? void 0 : _e.params) === null || _f === void 0 ? void 0 : _f.message) || 'Rule failure detected' }, (_g = result.event) === null || _g === void 0 ? void 0 : _g.params)
107
+ level: (_f = result.event) === null || _f === void 0 ? void 0 : _f.type,
108
+ details: Object.assign({ message: ((_h = (_g = result.event) === null || _g === void 0 ? void 0 : _g.params) === null || _h === void 0 ? void 0 : _h.message) || 'Rule failure detected', conditionDetails: conditionDetails, allConditions: allConditions, conditionType: conditionType, ruleDescription: ruleDescription, recommendations: recommendations }, (_j = result.event) === null || _j === void 0 ? void 0 : _j.params)
56
109
  });
110
+ // Restore original log prefix
111
+ (0, logger_1.setLogPrefix)(originalLogPrefix);
112
+ // Restore original log prefix before continuing
113
+ (0, logger_1.setLogPrefix)(originalLogPrefix);
57
114
  seenFailures.add(failureKey);
58
115
  }
59
116
  else {
@@ -64,8 +121,11 @@ function runEngineOnFiles(params) {
64
121
  }
65
122
  catch (e) {
66
123
  const error = e;
67
- const failedRuleName = (_h = error === null || error === void 0 ? void 0 : error.rule) === null || _h === void 0 ? void 0 : _h.name;
124
+ const failedRuleName = (_k = error === null || error === void 0 ? void 0 : error.rule) === null || _k === void 0 ? void 0 : _k.name;
68
125
  const rule = failedRuleName ? engine.rules.find((r) => r.name === failedRuleName) : null;
126
+ // Set the rule name as log prefix for this error
127
+ const originalLogPrefix = (0, logger_1.getLogPrefix)();
128
+ (0, logger_1.setLogPrefix)(`${originalLogPrefix}:${failedRuleName || 'unknown-rule'}`);
69
129
  // Determine error source and level
70
130
  let errorSource = 'unknown';
71
131
  let errorLevel = 'error';
@@ -89,7 +149,7 @@ function runEngineOnFiles(params) {
89
149
  }
90
150
  else if (failedRuleName) {
91
151
  errorSource = 'rule';
92
- errorLevel = (rule === null || rule === void 0 ? void 0 : rule.errorBehavior) === 'fatal' || ((_j = rule === null || rule === void 0 ? void 0 : rule.event) === null || _j === void 0 ? void 0 : _j.type) === 'fatality' ? 'fatality' : 'error';
152
+ errorLevel = (rule === null || rule === void 0 ? void 0 : rule.errorBehavior) === 'fatal' || ((_l = rule === null || rule === void 0 ? void 0 : rule.event) === null || _l === void 0 ? void 0 : _l.type) === 'fatality' ? 'fatality' : 'error';
93
153
  }
94
154
  logger_1.logger.error({
95
155
  index: i,
@@ -99,10 +159,10 @@ function runEngineOnFiles(params) {
99
159
  source: errorSource,
100
160
  type: errorLevel,
101
161
  stack: (handledError || error).stack,
102
- details: ((_k = error === null || error === void 0 ? void 0 : error.pluginError) === null || _k === void 0 ? void 0 : _k.details) || error.message
162
+ details: ((_m = error === null || error === void 0 ? void 0 : error.pluginError) === null || _m === void 0 ? void 0 : _m.details) || error.message
103
163
  }, `Execution error occurred at file ${file.filePath} (${i + 1} of ${fileCount})`);
104
164
  // Execute error action if specified
105
- if ((_l = rule === null || rule === void 0 ? void 0 : rule.onError) === null || _l === void 0 ? void 0 : _l.action) {
165
+ if ((_o = rule === null || rule === void 0 ? void 0 : rule.onError) === null || _o === void 0 ? void 0 : _o.action) {
106
166
  try {
107
167
  const actionResult = yield (0, errorActionExecutor_1.executeErrorAction)(rule.onError.action, {
108
168
  error: error,
@@ -133,9 +193,17 @@ function runEngineOnFiles(params) {
133
193
  message: `${errorSource} execution failed: ${(handledError || error).message}`,
134
194
  source: errorSource,
135
195
  stack: (handledError || error).stack,
136
- details: (_m = error === null || error === void 0 ? void 0 : error.pluginError) === null || _m === void 0 ? void 0 : _m.details
196
+ details: (_p = error === null || error === void 0 ? void 0 : error.pluginError) === null || _p === void 0 ? void 0 : _p.details,
197
+ // Include rule information if available
198
+ rule: rule ? {
199
+ name: rule.name,
200
+ conditions: rule.conditions,
201
+ event: rule.event
202
+ } : undefined
137
203
  }
138
204
  });
205
+ // Restore original log prefix before returning
206
+ (0, logger_1.setLogPrefix)(originalLogPrefix);
139
207
  }
140
208
  if (fileFailures.length > 0) {
141
209
  failures.push({ filePath: file.filePath, errors: fileFailures });
@@ -21,6 +21,8 @@ jest.mock('../../utils/logger', () => ({
21
21
  warn: jest.fn(),
22
22
  trace: jest.fn()
23
23
  },
24
+ getLogPrefix: jest.fn().mockReturnValue('test-prefix'),
25
+ setLogPrefix: jest.fn(),
24
26
  }));
25
27
  describe('runEngineOnFiles', () => {
26
28
  let mockEngine;
@@ -94,12 +94,53 @@ function setupEngine(params) {
94
94
  }
95
95
  });
96
96
  }
97
- engine.on('success', (_a) => __awaiter(this, [_a], void 0, function* ({ type, params }) {
97
+ engine.on('success', (_a) => __awaiter(this, [_a], void 0, function* ({ type, params, name, conditions }) {
98
+ const originalLogPrefix = (0, logger_1.getLogPrefix)();
99
+ const ruleName = name || 'unknown-rule';
100
+ (0, logger_1.setLogPrefix)(`${originalLogPrefix}:${ruleName}`);
101
+ // Extract condition details from conditions
102
+ let conditionDetails = undefined;
103
+ let allConditions = [];
104
+ let conditionType = 'unknown';
105
+ try {
106
+ const rule = engine.rules.find((r) => r.name === name);
107
+ if (rule) {
108
+ const conditions = rule.conditions.all || rule.conditions.any || [];
109
+ conditionType = rule.conditions.all ? 'all' : 'any';
110
+ // Capture all conditions with their parameters
111
+ allConditions = conditions.map((condition) => ({
112
+ fact: condition.fact,
113
+ operator: condition.operator,
114
+ value: condition.value,
115
+ params: condition.params,
116
+ path: condition.path,
117
+ priority: condition.priority
118
+ }));
119
+ // Find the first condition with operator and value for backward compatibility
120
+ for (const condition of conditions) {
121
+ if (condition.operator && condition.value !== undefined) {
122
+ conditionDetails = {
123
+ fact: condition.fact,
124
+ operator: condition.operator,
125
+ value: condition.value,
126
+ params: condition.params
127
+ };
128
+ break;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ catch (err) {
134
+ logger_1.logger.debug(`Error extracting operator threshold: ${err}`);
135
+ }
98
136
  if (type === 'warning') {
99
137
  logger_1.logger.warn(`warning detected: ${JSON.stringify(params)}`);
100
138
  yield (0, telemetry_1.sendTelemetry)({
101
139
  eventType: 'warning',
102
- metadata: Object.assign({ archetype, repoPath: '' }, params),
140
+ metadata: Object.assign({ archetype, repoPath: '', ruleName,
141
+ conditionDetails,
142
+ allConditions,
143
+ conditionType }, params),
103
144
  timestamp: new Date().toISOString()
104
145
  }, executionLogPrefix);
105
146
  }
@@ -107,7 +148,10 @@ function setupEngine(params) {
107
148
  logger_1.logger.error(`fatality detected: ${JSON.stringify(params)}`);
108
149
  yield (0, telemetry_1.sendTelemetry)({
109
150
  eventType: 'fatality',
110
- metadata: Object.assign({ archetype, repoPath: '' }, params),
151
+ metadata: Object.assign({ archetype, repoPath: '', ruleName,
152
+ conditionDetails,
153
+ allConditions,
154
+ conditionType }, params),
111
155
  timestamp: new Date().toISOString()
112
156
  }, executionLogPrefix);
113
157
  }
@@ -115,10 +159,17 @@ function setupEngine(params) {
115
159
  logger_1.logger.error(`exemption detected: ${JSON.stringify(params)}`);
116
160
  yield (0, telemetry_1.sendTelemetry)({
117
161
  eventType: 'exempt',
118
- metadata: Object.assign({ archetype, repoPath: '' }, params),
162
+ metadata: Object.assign({ archetype, repoPath: '', ruleName,
163
+ conditionDetails,
164
+ allConditions,
165
+ conditionType }, params),
119
166
  timestamp: new Date().toISOString()
120
167
  }, executionLogPrefix);
121
168
  }
169
+ // Restore original log prefix
170
+ (0, logger_1.setLogPrefix)(originalLogPrefix);
171
+ // Restore original log prefix
172
+ (0, logger_1.setLogPrefix)(originalLogPrefix);
122
173
  }));
123
174
  // Add facts to engine
124
175
  logger_1.logger.info(`=== loading facts..`);
@@ -1,4 +1,4 @@
1
- interface ErrorActionParams {
1
+ export interface ErrorActionParams {
2
2
  error: Error;
3
3
  rule: string;
4
4
  level: string;
@@ -7,4 +7,3 @@ interface ErrorActionParams {
7
7
  file: any;
8
8
  }
9
9
  export declare function executeErrorAction(actionName: string, params: ErrorActionParams): Promise<any>;
10
- export {};
@@ -15,23 +15,31 @@ const pluginRegistry_1 = require("../pluginRegistry");
15
15
  function executeErrorAction(actionName, params) {
16
16
  return __awaiter(this, void 0, void 0, function* () {
17
17
  var _a;
18
- // First check if it's a plugin action
19
- if (actionName.includes(':')) {
20
- const [pluginName, functionName] = actionName.split(':');
21
- const result = pluginRegistry_1.pluginRegistry.executePluginFunction(pluginName, functionName, params);
22
- if (!result.success) {
23
- throw new Error(`Plugin error action failed: ${(_a = result.error) === null || _a === void 0 ? void 0 : _a.message}`);
18
+ const originalLogPrefix = (0, logger_1.getLogPrefix)();
19
+ (0, logger_1.setLogPrefix)(`${originalLogPrefix}:${params.rule || 'unknown-rule'}`);
20
+ try {
21
+ // First check if it's a plugin action
22
+ if (actionName.includes(':')) {
23
+ const [pluginName, functionName] = actionName.split(':');
24
+ const result = pluginRegistry_1.pluginRegistry.executePluginFunction(pluginName, functionName, params);
25
+ if (!result.success) {
26
+ throw new Error(`Plugin error action failed: ${(_a = result.error) === null || _a === void 0 ? void 0 : _a.message}`);
27
+ }
28
+ return result.data;
29
+ }
30
+ // Otherwise check built-in actions
31
+ switch (actionName) {
32
+ case 'sendNotification':
33
+ return yield sendNotification(params);
34
+ case 'logToFile':
35
+ return yield logToFile(params);
36
+ default:
37
+ throw new Error(`Unknown error action: ${actionName}`);
24
38
  }
25
- return result.data;
26
39
  }
27
- // Otherwise check built-in actions
28
- switch (actionName) {
29
- case 'sendNotification':
30
- return yield sendNotification(params);
31
- case 'logToFile':
32
- return yield logToFile(params);
33
- default:
34
- throw new Error(`Unknown error action: ${actionName}`);
40
+ finally {
41
+ // Always restore the original log prefix
42
+ (0, logger_1.setLogPrefix)(originalLogPrefix);
35
43
  }
36
44
  });
37
45
  }
@@ -16,6 +16,8 @@ jest.mock('../../utils/logger', () => ({
16
16
  info: jest.fn(),
17
17
  error: jest.fn(),
18
18
  },
19
+ getLogPrefix: jest.fn().mockReturnValue('test-prefix'),
20
+ setLogPrefix: jest.fn(),
19
21
  }));
20
22
  describe('executeErrorAction', () => {
21
23
  it('should execute sendNotification action', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -125,12 +125,10 @@ exports.globalFileAnalysis = {
125
125
  const patternEntry = result.patternData.find((p) => p.pattern === pattern);
126
126
  return sum + ((patternEntry === null || patternEntry === void 0 ? void 0 : patternEntry.count) || 0);
127
127
  }, 0);
128
- // Create matchCounts and fileMatches for backward compatibility
128
+ // Create matchCounts for convenience
129
129
  result.matchCounts = {};
130
- result.fileMatches = {};
131
130
  result.patternData.forEach((entry) => {
132
131
  result.matchCounts[entry.pattern] = entry.count;
133
- result.fileMatches[entry.pattern] = entry.files;
134
132
  });
135
133
  // Add summary to result
136
134
  result.summary = {
package/dist/index.js CHANGED
@@ -151,7 +151,28 @@ function main() {
151
151
  // if results are found, there were issues found in the codebase
152
152
  if (resultMetadata.XFI_RESULT.totalIssues > 0) {
153
153
  logger_1.logger.warn(`WARNING: lo-fi attributes detected in codebase. ${resultMetadata.XFI_RESULT.warningCount} are warnings, ${resultMetadata.XFI_RESULT.fatalityCount} are fatal.`);
154
- logger_1.logger.warn(resultString);
154
+ // Create a more detailed summary of issues
155
+ const issuesSummary = {
156
+ totalIssues: resultMetadata.XFI_RESULT.totalIssues,
157
+ warningCount: resultMetadata.XFI_RESULT.warningCount,
158
+ fatalityCount: resultMetadata.XFI_RESULT.fatalityCount,
159
+ errorCount: resultMetadata.XFI_RESULT.errorCount,
160
+ exemptCount: resultMetadata.XFI_RESULT.exemptCount,
161
+ topIssues: resultMetadata.XFI_RESULT.issueDetails
162
+ .slice(0, 5)
163
+ .map(detail => ({
164
+ filePath: detail.filePath,
165
+ errors: detail.errors.map(err => {
166
+ var _a;
167
+ return ({
168
+ rule: err.ruleFailure,
169
+ level: err.level,
170
+ message: (_a = err.details) === null || _a === void 0 ? void 0 : _a.message
171
+ });
172
+ })
173
+ }))
174
+ };
175
+ logger_1.logger.warn(JSON.stringify(issuesSummary, null, 2));
155
176
  if (resultMetadata.XFI_RESULT.errorCount > 0) {
156
177
  logger_1.logger.error(outcomeMessage(`THERE WERE ${resultMetadata.XFI_RESULT.errorCount} UNEXPECTED ERRORS!`));
157
178
  logger_1.logger.error(`\n${prettyResult}\n\n`);
@@ -20,6 +20,10 @@ export declare class XFiReportGenerator {
20
20
  private generateDependencyIssuesSection;
21
21
  private generateSensitiveDataSection;
22
22
  private generateGlobalIssuesSection;
23
+ /**
24
+ * Helper method to add operator information to report sections
25
+ */
26
+ private addOperatorValueToReport;
23
27
  generateReport(): string;
24
28
  saveReportToFile(outputPath: string): Promise<void>;
25
29
  }
@@ -236,6 +236,14 @@ Based on the OpenAI analysis, these are the top 5 critical issues to address:
236
236
  **Suggestion**: ${issue.suggestion}
237
237
 
238
238
  `;
239
+ // Add condition details if available
240
+ if (openAiAnalysis.details && openAiAnalysis.details.conditionDetails) {
241
+ const { fact, operator, value, params } = openAiAnalysis.details.conditionDetails;
242
+ aiAnalysis += `**Condition**: Fact \`${fact}\` with operator \`${operator}\`\n`;
243
+ if (params) {
244
+ aiAnalysis += `**Parameters**: \`${JSON.stringify(params)}\`\n\n`;
245
+ }
246
+ }
239
247
  });
240
248
  }
241
249
  }
@@ -250,7 +258,7 @@ Based on the OpenAI analysis, these are the top 5 critical issues to address:
250
258
  filePath: detail.filePath,
251
259
  fileName: this.getFileName(detail.filePath),
252
260
  fileUrl: this.getGithubUrl(detail.filePath),
253
- details: error.details
261
+ details: error.details,
254
262
  })));
255
263
  if (complexityIssues.length === 0) {
256
264
  return '';
@@ -259,7 +267,17 @@ Based on the OpenAI analysis, these are the top 5 critical issues to address:
259
267
 
260
268
  The analysis identified several functions with high complexity that should be refactored:
261
269
 
262
- | File | Function | Cyclomatic Complexity | Cognitive Complexity | Nesting Depth | Parameter Count | Return Count |
270
+ `;
271
+ // Add threshold information if available from the first issue
272
+ if (complexityIssues[0].details && complexityIssues[0].details.operatorThreshold) {
273
+ const { operator, value } = complexityIssues[0].details.operatorThreshold;
274
+ section += `**Threshold**: \`${operator}: ${JSON.stringify(value)}\`\n\n`;
275
+ }
276
+ // Add operator value information if available
277
+ if (complexityIssues[0].details && complexityIssues[0].details.operatorValue) {
278
+ section += `**Required Value**: \`${JSON.stringify(complexityIssues[0].details.operatorValue)}\`\n\n`;
279
+ }
280
+ section += `| File | Function | Cyclomatic Complexity | Cognitive Complexity | Nesting Depth | Parameter Count | Return Count |
263
281
  |------|----------|------------------------|----------------------|--------------|----------------|--------------|
264
282
  `;
265
283
  complexityIssues.forEach(issue => {
@@ -287,7 +305,16 @@ The analysis identified several functions with high complexity that should be re
287
305
 
288
306
  The analysis detected outdated framework dependencies that need updating:
289
307
 
290
- | Dependency | Current Version | Required Version |
308
+ `;
309
+ // Add condition details if available
310
+ if (dependencyIssue.details.conditionDetails) {
311
+ const { fact, operator, params } = dependencyIssue.details.conditionDetails;
312
+ section += `**Condition**: Fact \`${fact}\` with operator \`${operator}\`\n`;
313
+ if (params) {
314
+ section += `**Parameters**: \`${JSON.stringify(params)}\`\n\n`;
315
+ }
316
+ }
317
+ section += `| Dependency | Current Version | Required Version |
291
318
  |------------|-----------------|------------------|
292
319
  `;
293
320
  dependencies.forEach((dep) => {
@@ -341,9 +368,41 @@ Several files contain potentially sensitive data patterns that shouldn't be logg
341
368
  `;
342
369
  globalIssues.forEach(issue => {
343
370
  section += `- **${issue.ruleFailure}** (${issue.level}): ${issue.details && issue.details.message ? issue.details.message : 'No details available'}\n`;
371
+ // Add condition details if available
372
+ if (issue.details && issue.details.conditionDetails) {
373
+ const { fact, operator, params } = issue.details.conditionDetails;
374
+ section += ` - Condition: Fact \`${fact}\` with operator \`${operator}\`\n`;
375
+ if (params) {
376
+ section += ` - Parameters: \`${JSON.stringify(params)}\`\n`;
377
+ }
378
+ }
344
379
  });
345
380
  return section;
346
381
  }
382
+ /**
383
+ * Helper method to add operator information to report sections
384
+ */
385
+ addOperatorValueToReport(issueDetails, error) {
386
+ // Add condition details if available
387
+ if (error.details.conditionDetails) {
388
+ const { fact, operator, params } = error.details.conditionDetails;
389
+ issueDetails += ` - Condition: Fact \`${fact}\` with operator \`${operator}\`\n`;
390
+ if (params) {
391
+ issueDetails += ` - Parameters: \`${JSON.stringify(params)}\`\n`;
392
+ }
393
+ }
394
+ // Add all condition operators if available
395
+ if (error.details && error.details.allConditionOperators && error.details.allConditionOperators.length > 0) {
396
+ issueDetails += ` - All Condition Operators:\n`;
397
+ error.details.allConditionOperators.forEach((condition, index) => {
398
+ issueDetails += ` ${index + 1}. Fact: \`${condition.fact}\` Operator: \`${condition.operator}\` Value: \`${JSON.stringify(condition.value)}\`\n`;
399
+ if (condition.params) {
400
+ issueDetails += ` Parameters: \`${JSON.stringify(condition.params)}\`\n`;
401
+ }
402
+ });
403
+ }
404
+ return issueDetails;
405
+ }
347
406
  generateReport() {
348
407
  const executiveSummary = this.generateExecutiveSummary();
349
408
  const fileStatusChart = this.generateFileStatusChart();
@@ -13,7 +13,7 @@ const globalPatternCount = {
13
13
  }
14
14
  // Parse threshold and comparison type
15
15
  let thresholdValue;
16
- let comparisonType = 'gte'; // Default to greater than or equal
16
+ let comparisonType = 'lte'; // Default to greater than or equal
17
17
  if (typeof threshold === 'object' && threshold !== null) {
18
18
  thresholdValue = threshold.threshold;
19
19
  if (threshold.comparison) {
@@ -24,7 +24,7 @@ describe('globalPatternCount', () => {
24
24
  totalMatches: 10
25
25
  }
26
26
  };
27
- expect(globalPatternCount_1.globalPatternCount.fn(analysisResult, 5)).toBe(true);
27
+ expect(globalPatternCount_1.globalPatternCount.fn(analysisResult, 5)).toBe(false);
28
28
  });
29
29
  it('should return true when count exceeds threshold with explicit gte comparison', () => {
30
30
  const analysisResult = {
@@ -81,7 +81,7 @@ describe('globalPatternCount', () => {
81
81
  expect(globalPatternCount_1.globalPatternCount.fn({
82
82
  patternData: [{ pattern: 'pattern1', count: 0, files: [] }],
83
83
  summary: { totalMatches: 0 }
84
- }, 1)).toBe(false);
84
+ }, 1)).toBe(true);
85
85
  });
86
86
  it('should handle new pattern totals with lte comparison', () => {
87
87
  const analysisResult = {
@@ -81,12 +81,12 @@ describe('globalPatternRatio', () => {
81
81
  });
82
82
  it('should handle edge cases', () => {
83
83
  // No patterns
84
- expect(globalPatternRatio_1.globalPatternRatio.fn({ patternData: [], summary: {} }, { value: 1, comparison: 'gte' })).toBe(false);
84
+ expect(globalPatternRatio_1.globalPatternRatio.fn({ patternData: [], summary: {} }, { threshold: 1, comparison: 'gte' })).toBe(false);
85
85
  // Only one pattern
86
86
  expect(globalPatternRatio_1.globalPatternRatio.fn({
87
87
  patternData: [{ pattern: 'pattern1', count: 5, files: [] }],
88
88
  summary: { totalMatches: 5 }
89
- }, { value: 1, comparison: 'gte' })).toBe(false);
89
+ }, { threshold: 1, comparison: 'gte' })).toBe(false);
90
90
  // Denominator is zero
91
91
  expect(globalPatternRatio_1.globalPatternRatio.fn({
92
92
  patternData: [
@@ -94,7 +94,7 @@ describe('globalPatternRatio', () => {
94
94
  { pattern: 'pattern2', count: 0, files: [] }
95
95
  ],
96
96
  summary: { totalMatches: 5 }
97
- }, { value: 1, comparison: 'gte' })).toBe(false);
97
+ }, { threshold: 1, comparison: 'gte' })).toBe(false);
98
98
  });
99
99
  it('should handle new pattern totals with lte comparison', () => {
100
100
  const analysisResult = {
@@ -21,6 +21,17 @@ export interface RuleFailure {
21
21
  source?: 'operator' | 'fact' | 'plugin' | 'rule' | 'unknown';
22
22
  originalError?: Error;
23
23
  stack?: string;
24
+ operatorThreshold?: {
25
+ operator: string;
26
+ value: any;
27
+ };
28
+ operatorValue?: any;
29
+ conditionDetails?: {
30
+ fact: string;
31
+ operator: string;
32
+ value: any;
33
+ params?: any;
34
+ };
24
35
  [key: string]: any;
25
36
  } | undefined;
26
37
  }
@@ -112,6 +123,8 @@ export interface RuleConfig {
112
123
  action: string;
113
124
  params?: Record<string, any>;
114
125
  };
126
+ description?: string;
127
+ recommendations?: string[];
115
128
  }
116
129
  export type RuleConfigSchema = JSONSchemaType<RuleConfig>;
117
130
  export interface OpenAIAnalysisParams {
@@ -130,6 +143,22 @@ export interface BasicTelemetryMetadata {
130
143
  errorMessage?: string;
131
144
  options?: any;
132
145
  errorStack?: string;
146
+ ruleName?: string;
147
+ conditionDetails?: {
148
+ fact: string;
149
+ operator: string;
150
+ value: any;
151
+ params?: any;
152
+ };
153
+ allConditions?: Array<{
154
+ fact: string;
155
+ operator: string;
156
+ value: any;
157
+ params?: any;
158
+ path?: string;
159
+ priority?: number;
160
+ }>;
161
+ conditionType?: 'all' | 'any' | 'unknown';
133
162
  }
134
163
  export interface ExemptionTelemetryMetadata {
135
164
  repoUrl: string;
@@ -187,6 +187,12 @@ const ruleSchema = {
187
187
  required: ["action"],
188
188
  nullable: true,
189
189
  },
190
+ description: { type: "string", nullable: true },
191
+ recommendations: {
192
+ type: "array",
193
+ items: { type: "string" },
194
+ nullable: true
195
+ }
190
196
  },
191
197
  required: ["name", "conditions", "event"],
192
198
  };
@@ -4,6 +4,8 @@ export declare function generateLogPrefix(): string;
4
4
  export declare function resetLogPrefix(): void;
5
5
  export declare function setLogPrefix(prefix: string): void;
6
6
  export declare function getLogPrefix(): string;
7
+ export declare function appendLogPrefix(suffix: string): void;
8
+ export declare function withLogPrefix<T>(prefix: string, fn: () => T): T;
7
9
  export declare const logger: pino.Logger;
8
10
  export declare function resetLogger(): void;
9
11
  export declare function setLogLevel(level: string): void;