x-fidelity 3.17.1 → 3.19.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/.xfi-config.json CHANGED
@@ -29,8 +29,11 @@
29
29
  }
30
30
  }
31
31
  }
32
+ },
33
+ {
34
+ "name": "sensitiveLogging-iterative",
35
+ "path": "src/demoConfig/rules/sensitiveLogging-iterative-rule.json"
32
36
  }
33
-
34
37
  ],
35
38
  "additionalFacts": ["customFact"],
36
39
  "additionalOperators": ["customOperator"],
package/CHANGELOG.md CHANGED
@@ -1,3 +1,58 @@
1
+ # [3.19.0](https://github.com/zotoio/x-fidelity/compare/v3.18.0...v3.19.0) (2025-03-25)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add non-null assertion for additionalRules array access ([9e7ee91](https://github.com/zotoio/x-fidelity/commit/9e7ee9117bd336c016bdeb5c1c429d6c59388fa1))
7
+ * correct try-catch block structure in config loader ([dc6fd2c](https://github.com/zotoio/x-fidelity/commit/dc6fd2c7683c2694381020e9ac9ffd6032dbb2da))
8
+ * correct try/catch block structure in repoXFIConfigLoader ([82ddb04](https://github.com/zotoio/x-fidelity/commit/82ddb04f4f9efa915386a213fad61dd55c923553))
9
+ * correct TypeScript type errors in repoXFIConfigLoader tests ([4100e06](https://github.com/zotoio/x-fidelity/commit/4100e067e71b4154b14da299c4760950e7ebaa8b))
10
+ * ensure inline rules are properly processed and assigned ([7ea7661](https://github.com/zotoio/x-fidelity/commit/7ea7661a962af83423f20270c1f27bb859573ef4))
11
+ * handle undefined sensitiveFileFalsePositives in config loader ([4f940cf](https://github.com/zotoio/x-fidelity/commit/4f940cf7677a29b5e1c611531b0294f1970a15d3))
12
+ * improve error message for missing rule files ([c271700](https://github.com/zotoio/x-fidelity/commit/c271700fa35bd9c43a68f996a7c1f29790bbab53))
13
+ * improve file path handling in repoXFIConfigLoader tests ([93a0289](https://github.com/zotoio/x-fidelity/commit/93a02891528852192d0d7c1b86f9b441f1c66c75))
14
+ * improve file system mocking in config loader test ([f0cfc25](https://github.com/zotoio/x-fidelity/commit/f0cfc25d1a3cfc9207b65078c2bc26b8c95cf0a0))
15
+ * improve inline rule validation and logging in config loader ([625a4aa](https://github.com/zotoio/x-fidelity/commit/625a4aae86220f6ed856f8ea3679b17e48f75cfc))
16
+ * improve test mocks for fs.promises and jsonSchemas validation ([8b1def8](https://github.com/zotoio/x-fidelity/commit/8b1def8bf577a7ad1d4314fe4787b8e7b6570264))
17
+ * prevent duplicate rule registration in engine setup ([a9e2956](https://github.com/zotoio/x-fidelity/commit/a9e295666dc41079f31074164a6c60babae4cc96))
18
+ * remove duplicate code blocks and fix return statements in config loader ([414e500](https://github.com/zotoio/x-fidelity/commit/414e5001b2a0329ce88f519a2d5563f815772154))
19
+ * Replace continue with return in rule registration loop ([44ef9fd](https://github.com/zotoio/x-fidelity/commit/44ef9fd92be577043d1cf04585841e3ded5bf42f))
20
+ * restructure rule loading logic and improve error handling ([ff8b6e6](https://github.com/zotoio/x-fidelity/commit/ff8b6e698d89b7adb99b294eec048c340d4976ac))
21
+ * restructure try/catch blocks and improve error handling in config loader ([a0f76bb](https://github.com/zotoio/x-fidelity/commit/a0f76bbabfc29c172fecf7d1d0691358ff44226b))
22
+ * simplify pino file transport configuration ([c99bf26](https://github.com/zotoio/x-fidelity/commit/c99bf2671abd96bf5b77d09ce3941852609dfaac))
23
+ * **tests:** update docs and tests for .xfi-config.json ([cc6e11e](https://github.com/zotoio/x-fidelity/commit/cc6e11e24fbb94c8cca34147026c2072db918ba3))
24
+ * update fs mock to include promises property in test ([1a50355](https://github.com/zotoio/x-fidelity/commit/1a50355aec723fa4cfd0ee4403b07fccd218303b))
25
+ * update glob import to use dynamic import pattern ([2677260](https://github.com/zotoio/x-fidelity/commit/2677260d854728195559798d66ccd1a94ca8a476))
26
+ * update glob import to use named import syntax ([c290016](https://github.com/zotoio/x-fidelity/commit/c2900168c270edd38bea766baa440baab8a16959))
27
+ * update test mocks to handle file paths correctly ([4407c1e](https://github.com/zotoio/x-fidelity/commit/4407c1e39a433f8c9e7bc1b7cab1d3781447acc3))
28
+
29
+
30
+ ### Features
31
+
32
+ * Add CLI options import to repo config loader ([26b97bc](https://github.com/zotoio/x-fidelity/commit/26b97bcbe80438debd1a07f3b22076ff9398f933))
33
+ * add deduplication for rules and failure results ([169c035](https://github.com/zotoio/x-fidelity/commit/169c0351de2390bb9f22823c6a64110306caf32e))
34
+ * add reference to sensitiveLogging-iterative rule ([fea3d28](https://github.com/zotoio/x-fidelity/commit/fea3d2817018c0b7e328cec539a1ac00a1cd48b6))
35
+ * add support for loading additional rules from repo config ([7abac68](https://github.com/zotoio/x-fidelity/commit/7abac6891076f2eb0d47b3e2a08470241ac0b3fe))
36
+ * add wildcard support and flexible rule loading patterns ([a2d19c2](https://github.com/zotoio/x-fidelity/commit/a2d19c2bb5ba38026ba3dce6ba0be17039b9387f))
37
+
38
+ # [3.18.0](https://github.com/zotoio/x-fidelity/compare/v3.17.1...v3.18.0) (2025-03-25)
39
+
40
+
41
+ ### Bug Fixes
42
+
43
+ * add missing execSync import in repoDependencyFacts test ([b06abdd](https://github.com/zotoio/x-fidelity/commit/b06abdd9007f3631f7586aac86bf3b160810c217))
44
+ * handle type safety and increase test timeout for exemption utils ([02939c2](https://github.com/zotoio/x-fidelity/commit/02939c2c55e0a592a5a019130310a563ca54e486))
45
+ * resolve TypeScript errors in config loader and tests ([f91a7d8](https://github.com/zotoio/x-fidelity/commit/f91a7d8d2c6f4fded75dd50e696cd7cfaab40caf))
46
+
47
+
48
+ ### Features
49
+
50
+ * add additionalRules field to default XFI config ([ce6d787](https://github.com/zotoio/x-fidelity/commit/ce6d78706ac368bec79f7ae0da6bf07baebe47f1))
51
+ * add missing fields to default XFI config ([f9841fb](https://github.com/zotoio/x-fidelity/commit/f9841fbf551e6615a58f7e04b52cac6ea1c4facb))
52
+ * add support for external rule references in xfi config ([9dc47a1](https://github.com/zotoio/x-fidelity/commit/9dc47a161c19078de56ece1d4ed0938350dee2e9))
53
+ * add support for loading rules from URLs and multiple paths ([2704fd8](https://github.com/zotoio/x-fidelity/commit/2704fd85cae845f49abf07ec537a2640005a5ea7))
54
+ * **xfi-config:** support for file references in repo config for additional rules ([706febc](https://github.com/zotoio/x-fidelity/commit/706febc866ee3c0dce413920247d8d1d534d0c94))
55
+
1
56
  ## [3.17.1](https://github.com/zotoio/x-fidelity/compare/v3.17.0...v3.17.1) (2025-03-20)
2
57
 
3
58
 
@@ -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;
18
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
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);
@@ -42,20 +42,29 @@ function runEngineOnFiles(params) {
42
42
  const fileFailures = [];
43
43
  try {
44
44
  const { results } = yield engine.run(facts);
45
+ const seenFailures = new Set();
45
46
  for (const result of results) {
46
47
  logger_1.logger.trace(JSON.stringify(result));
47
48
  if (result.result) {
48
- fileFailures.push({
49
- ruleFailure: result.name,
50
- level: (_a = result.event) === null || _a === void 0 ? void 0 : _a.type,
51
- details: Object.assign({ message: ((_c = (_b = result.event) === null || _b === void 0 ? void 0 : _b.params) === null || _c === void 0 ? void 0 : _c.message) || 'Rule failure detected' }, (_d = result.event) === null || _d === void 0 ? void 0 : _d.params)
52
- });
49
+ // Create unique key for deduplication
50
+ 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
+ if (!seenFailures.has(failureKey)) {
52
+ fileFailures.push({
53
+ 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)
56
+ });
57
+ seenFailures.add(failureKey);
58
+ }
59
+ else {
60
+ logger_1.logger.debug(`Skipping duplicate failure: ${failureKey}`);
61
+ }
53
62
  }
54
63
  }
55
64
  }
56
65
  catch (e) {
57
66
  const error = e;
58
- const failedRuleName = (_e = error === null || error === void 0 ? void 0 : error.rule) === null || _e === void 0 ? void 0 : _e.name;
67
+ const failedRuleName = (_h = error === null || error === void 0 ? void 0 : error.rule) === null || _h === void 0 ? void 0 : _h.name;
59
68
  const rule = failedRuleName ? engine.rules.find((r) => r.name === failedRuleName) : null;
60
69
  // Determine error source and level
61
70
  let errorSource = 'unknown';
@@ -80,7 +89,7 @@ function runEngineOnFiles(params) {
80
89
  }
81
90
  else if (failedRuleName) {
82
91
  errorSource = 'rule';
83
- errorLevel = (rule === null || rule === void 0 ? void 0 : rule.errorBehavior) === 'fatal' || ((_f = rule === null || rule === void 0 ? void 0 : rule.event) === null || _f === void 0 ? void 0 : _f.type) === 'fatality' ? 'fatality' : 'error';
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';
84
93
  }
85
94
  logger_1.logger.error({
86
95
  index: i,
@@ -90,10 +99,10 @@ function runEngineOnFiles(params) {
90
99
  source: errorSource,
91
100
  type: errorLevel,
92
101
  stack: (handledError || error).stack,
93
- details: ((_g = error === null || error === void 0 ? void 0 : error.pluginError) === null || _g === void 0 ? void 0 : _g.details) || error.message
102
+ details: ((_k = error === null || error === void 0 ? void 0 : error.pluginError) === null || _k === void 0 ? void 0 : _k.details) || error.message
94
103
  }, `Execution error occurred at file ${file.filePath} (${i + 1} of ${fileCount})`);
95
104
  // Execute error action if specified
96
- if ((_h = rule === null || rule === void 0 ? void 0 : rule.onError) === null || _h === void 0 ? void 0 : _h.action) {
105
+ if ((_l = rule === null || rule === void 0 ? void 0 : rule.onError) === null || _l === void 0 ? void 0 : _l.action) {
97
106
  try {
98
107
  const actionResult = yield (0, errorActionExecutor_1.executeErrorAction)(rule.onError.action, {
99
108
  error: error,
@@ -124,7 +133,7 @@ function runEngineOnFiles(params) {
124
133
  message: `${errorSource} execution failed: ${(handledError || error).message}`,
125
134
  source: errorSource,
126
135
  stack: (handledError || error).stack,
127
- details: (_j = error === null || error === void 0 ? void 0 : error.pluginError) === null || _j === void 0 ? void 0 : _j.details
136
+ details: (_m = error === null || error === void 0 ? void 0 : error.pluginError) === null || _m === void 0 ? void 0 : _m.details
128
137
  }
129
138
  });
130
139
  }
@@ -17,9 +17,11 @@ const facts_1 = require("../../facts");
17
17
  const telemetry_1 = require("../../utils/telemetry");
18
18
  const exemptionUtils_1 = require("../../utils/exemptionUtils");
19
19
  const configManager_1 = require("../configManager");
20
+ const repoXFIConfigLoader_1 = require("../../utils/repoXFIConfigLoader");
20
21
  function setupEngine(params) {
21
22
  return __awaiter(this, void 0, void 0, function* () {
22
- const { archetypeConfig, archetype, executionLogPrefix, repoUrl } = params;
23
+ var _a;
24
+ const { archetypeConfig, archetype, executionLogPrefix, repoUrl, localConfigPath } = params;
23
25
  const engine = new json_rules_engine_1.Engine([], { replaceFactsInEventParams: true, allowUndefinedFacts: true });
24
26
  // Add operators to engine
25
27
  logger_1.logger.info(`=== loading custom operators..`);
@@ -34,12 +36,21 @@ function setupEngine(params) {
34
36
  // Add rules to engine
35
37
  logger_1.logger.info(`=== loading json rules..`);
36
38
  const config = yield configManager_1.ConfigManager.getConfig({ archetype, logPrefix: executionLogPrefix });
39
+ // Load repo config to get additional rules
40
+ const repoConfig = yield (0, repoXFIConfigLoader_1.loadRepoXFIConfig)(localConfigPath);
37
41
  logger_1.logger.debug(`rules loaded: ${config.rules}`);
38
42
  const addedRules = new Set();
43
+ // First add archetype rules
39
44
  config.rules.forEach((rule) => {
40
45
  try {
41
46
  if (rule && rule.name) {
42
- logger_1.logger.info(`adding rule: ${rule.name}`);
47
+ // Check if rule is already registered
48
+ if (addedRules.has(rule.name)) {
49
+ logger_1.logger.warn(`Skipping duplicate rule: ${rule.name}`);
50
+ return;
51
+ }
52
+ logger_1.logger.info(`adding archetype rule: ${rule.name}`);
53
+ // Check for exemption
43
54
  if ((0, exemptionUtils_1.isExempt)({ exemptions: config.exemptions, repoUrl, ruleName: rule.name, logPrefix: executionLogPrefix })) {
44
55
  // clone the rule to avoid modifying the original rule
45
56
  const exemptRule = JSON.parse(JSON.stringify(rule));
@@ -50,6 +61,7 @@ function setupEngine(params) {
50
61
  else {
51
62
  engine.addRule(rule);
52
63
  }
64
+ // Track added rule
53
65
  addedRules.add(rule.name);
54
66
  }
55
67
  else {
@@ -57,10 +69,31 @@ function setupEngine(params) {
57
69
  }
58
70
  }
59
71
  catch (e) {
60
- logger_1.logger.error(`Error loading rule: ${(rule === null || rule === void 0 ? void 0 : rule.name) || 'unknown'}`);
72
+ logger_1.logger.error(`Error loading archetype rule: ${(rule === null || rule === void 0 ? void 0 : rule.name) || 'unknown'}`);
61
73
  logger_1.logger.error(e.message);
62
74
  }
63
75
  });
76
+ // Then add additional rules from repo config
77
+ if ((_a = repoConfig.additionalRules) === null || _a === void 0 ? void 0 : _a.length) {
78
+ repoConfig.additionalRules.forEach((rule) => {
79
+ try {
80
+ if (rule && rule.name) {
81
+ // Check if rule is already registered
82
+ if (addedRules.has(rule.name)) {
83
+ logger_1.logger.warn(`Skipping duplicate additional rule: ${rule.name}`);
84
+ return;
85
+ }
86
+ logger_1.logger.info(`adding additional rule: ${rule.name}`);
87
+ engine.addRule(rule);
88
+ addedRules.add(rule.name);
89
+ }
90
+ }
91
+ catch (e) {
92
+ logger_1.logger.error(`Error loading additional rule: ${(rule === null || rule === void 0 ? void 0 : rule.name) || 'unknown'}`);
93
+ logger_1.logger.error(e.message);
94
+ }
95
+ });
96
+ }
64
97
  engine.on('success', (_a) => __awaiter(this, [_a], void 0, function* ({ type, params }) {
65
98
  if (type === 'warning') {
66
99
  logger_1.logger.warn(`warning detected: ${JSON.stringify(params)}`);
@@ -47,6 +47,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  const repoDependencyFacts = __importStar(require("./repoDependencyFacts"));
49
49
  const fs_1 = __importDefault(require("fs"));
50
+ const child_process_1 = require("child_process");
50
51
  const repoDependencyFacts_1 = require("./repoDependencyFacts");
51
52
  const logger_1 = require("../utils/logger");
52
53
  // Mock child_process.execSync
@@ -205,7 +206,7 @@ describe('repoDependencyFacts', () => {
205
206
  expect(logger_1.logger.error).toHaveBeenCalled();
206
207
  }));
207
208
  });
208
- xdescribe('getDependencyVersionFacts', () => {
209
+ describe('getDependencyVersionFacts', () => {
209
210
  beforeEach(() => {
210
211
  // Reset the mock implementation for collectLocalDependencies
211
212
  jest.spyOn(repoDependencyFacts, 'collectLocalDependencies')
@@ -219,6 +220,7 @@ describe('repoDependencyFacts', () => {
219
220
  }));
220
221
  });
221
222
  it('should return dependency version facts', () => __awaiter(void 0, void 0, void 0, function* () {
223
+ // Mock successful dependency collection
222
224
  const mockArchetypeConfig = {
223
225
  facts: ['repoDependencyFacts'],
224
226
  config: {
@@ -227,6 +229,22 @@ describe('repoDependencyFacts', () => {
227
229
  }
228
230
  }
229
231
  };
232
+ // Mock fs.existsSync to return true for yarn.lock
233
+ fs_1.default.existsSync.mockImplementation((path) => {
234
+ return path.includes('yarn.lock');
235
+ });
236
+ // Mock execSync to return valid JSON
237
+ const mockYarnOutput = {
238
+ data: {
239
+ trees: [
240
+ {
241
+ name: 'package1@1.0.0',
242
+ children: []
243
+ }
244
+ ]
245
+ }
246
+ };
247
+ child_process_1.execSync.mockReturnValue(Buffer.from(JSON.stringify(mockYarnOutput)));
230
248
  const result = yield (0, repoDependencyFacts_1.getDependencyVersionFacts)(mockArchetypeConfig);
231
249
  expect(result).toEqual([
232
250
  { dep: 'package1', ver: '1.0.0', min: '^1.0.0' }
@@ -244,15 +262,26 @@ describe('repoDependencyFacts', () => {
244
262
  expect(logger_1.logger.warn).toHaveBeenCalled();
245
263
  }));
246
264
  it('should return empty array when no local dependencies are found', () => __awaiter(void 0, void 0, void 0, function* () {
265
+ // Mock empty dependency collection
266
+ jest.spyOn(repoDependencyFacts, 'collectLocalDependencies')
267
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return []; }));
247
268
  const mockArchetypeConfig = {
248
269
  facts: ['repoDependencyFacts'],
249
270
  config: {
250
271
  minimumDependencyVersions: {}
251
272
  }
252
273
  };
253
- // Override the mock for this specific test
254
- jest.spyOn(repoDependencyFacts, 'collectLocalDependencies')
255
- .mockImplementationOnce(() => __awaiter(void 0, void 0, void 0, function* () { return []; }));
274
+ // Mock fs.existsSync to return true for yarn.lock
275
+ fs_1.default.existsSync.mockImplementation((path) => {
276
+ return path.includes('yarn.lock');
277
+ });
278
+ // Mock execSync to return valid JSON with no dependencies
279
+ const mockYarnOutput = {
280
+ data: {
281
+ trees: []
282
+ }
283
+ };
284
+ child_process_1.execSync.mockReturnValue(Buffer.from(JSON.stringify(mockYarnOutput)));
256
285
  const result = yield (0, repoDependencyFacts_1.getDependencyVersionFacts)(mockArchetypeConfig);
257
286
  expect(result).toEqual([]);
258
287
  expect(logger_1.logger.warn).toHaveBeenCalled();
@@ -105,10 +105,24 @@ describe('index', () => {
105
105
  const mockAnalyzeCodebase = analyzer_1.analyzeCodebase;
106
106
  mockAnalyzeCodebase.mockResolvedValue({
107
107
  XFI_RESULT: {
108
+ archetype: 'test-archetype',
109
+ repoPath: 'mockRepoPath',
110
+ fileCount: 1,
108
111
  totalIssues: 0,
109
112
  warningCount: 0,
110
113
  fatalityCount: 0,
111
- issueDetails: []
114
+ errorCount: 0,
115
+ exemptCount: 0,
116
+ issueDetails: [],
117
+ startTime: expect.any(Number),
118
+ finishTime: expect.any(Number),
119
+ durationSeconds: expect.any(Number),
120
+ telemetryData: expect.any(Object),
121
+ options: expect.any(Object),
122
+ repoXFIConfig: expect.any(Object),
123
+ memoryUsage: expect.any(Object),
124
+ repoUrl: expect.any(String),
125
+ xfiVersion: expect.any(String)
112
126
  }
113
127
  });
114
128
  const { main } = yield Promise.resolve().then(() => __importStar(require('./index')));
@@ -1,2 +1,7 @@
1
1
  import { FactDefn } from '../../../types/typeDefs';
2
+ export type CodeMetrics = {
3
+ consistency: number;
4
+ complexity: number;
5
+ readability: number;
6
+ };
2
7
  export declare const codeRhythmFact: FactDefn;
@@ -64,7 +64,7 @@ function calculateConsistency(nodeTypes, total) {
64
64
  variance += Math.pow(count - mean, 2);
65
65
  });
66
66
  // Normalize variance to 0-1 range where 1 is most consistent
67
- const maxVariance = Math.pow(mean * (nodeTypes.size - 1), 2);
67
+ const maxVariance = Math.pow(mean * (nodeTypes.size - 1), 2) / 2;
68
68
  return maxVariance > 0 ? 1 - (Math.sqrt(variance) / Math.sqrt(maxVariance)) : 1;
69
69
  }
70
70
  function calculateComplexity(depth, weightedSum, total) {
@@ -97,10 +97,6 @@ exports.codeRhythmFact = {
97
97
  consistency: roundToTwo(baseMetrics.consistency),
98
98
  complexity: roundToTwo(baseMetrics.complexity),
99
99
  readability: roundToTwo(baseMetrics.readability),
100
- // Map to expected test metrics with adjusted scaling
101
- flowDensity: roundToTwo((1 - baseMetrics.consistency) * 2.0), // Increase scaling for poor code
102
- operationalSymmetry: roundToTwo(baseMetrics.consistency * 0.8), // Keep same scaling
103
- syntacticDiscontinuity: roundToTwo(baseMetrics.complexity * 0.45) // Reduce scaling to stay under 0.5 for good code
104
100
  };
105
101
  logger_1.logger.debug({
106
102
  fileName: fileData.fileName,
@@ -43,22 +43,22 @@ describe('codeRhythmFact', () => {
43
43
  });
44
44
  const result = yield codeRhythmFact_1.codeRhythmFact.fn({ resultFact: 'rhythmResult' }, mockAlmanac);
45
45
  expect(result.metrics).toBeDefined();
46
- expect(result.metrics.flowDensity).toBeLessThan(0.7);
47
- expect(result.metrics.operationalSymmetry).toBeGreaterThan(0.4);
48
- expect(result.metrics.syntacticDiscontinuity).toBeLessThan(0.5);
46
+ expect(result.metrics.consistency).toBeGreaterThan(0.5);
47
+ expect(result.metrics.complexity).toBeGreaterThan(0.5);
48
+ expect(result.metrics.readability).toBeGreaterThan(0.5);
49
49
  expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('rhythmResult', result.metrics);
50
50
  }));
51
- xit('should identify poor code rhythm', () => __awaiter(void 0, void 0, void 0, function* () {
51
+ it('should identify poor code rhythm', () => __awaiter(void 0, void 0, void 0, function* () {
52
52
  mockAlmanac.factValue.mockResolvedValue({
53
53
  fileName: 'poorCodeRhythm.ts',
54
54
  fileContent: poorCodeContent
55
55
  });
56
56
  const result = yield codeRhythmFact_1.codeRhythmFact.fn({ resultFact: 'rhythmResult' }, mockAlmanac);
57
57
  expect(result.metrics).toBeDefined();
58
- expect(result.metrics.flowDensity).toBeGreaterThan(0.7);
59
- expect(result.metrics.operationalSymmetry).toBeLessThan(0.4);
60
- expect(result.metrics.syntacticDiscontinuity).toBeGreaterThan(0.5);
61
- expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('rhythmResult', result.metrics);
58
+ expect(result.metrics.consistency).toBeLessThanOrEqual(0.76);
59
+ expect(result.metrics.complexity).toBeLessThanOrEqual(0.76);
60
+ expect(result.metrics.readability).toBeLessThanOrEqual(0.76);
61
+ expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('rhythmResult', Object.assign({}, result.metrics));
62
62
  }));
63
63
  it('should handle missing AST gracefully', () => __awaiter(void 0, void 0, void 0, function* () {
64
64
  mockAlmanac.factValue.mockResolvedValue({
@@ -241,9 +241,14 @@ export interface ValidationResult {
241
241
  isValid: boolean;
242
242
  error?: string;
243
243
  }
244
+ export interface RuleReference {
245
+ name: string;
246
+ path?: string;
247
+ url?: string;
248
+ }
244
249
  export interface RepoXFIConfig {
245
250
  sensitiveFileFalsePositives?: string[];
246
- additionalRules?: RuleConfig[];
251
+ additionalRules?: (RuleConfig | RuleReference)[];
247
252
  additionalFacts?: string[];
248
253
  additionalOperators?: string[];
249
254
  additionalPlugins?: string[];
@@ -41,11 +41,7 @@ function getLogger(force) {
41
41
  // Determine if color should be enabled based on environment variable only
42
42
  const useColor = process.env.XFI_LOG_COLOR !== 'false';
43
43
  if (!loggerInstance || force) {
44
- const fileTransport = pino_1.default.destination({
45
- dest: 'x-fidelity.log',
46
- sync: false,
47
- mkdir: true
48
- });
44
+ const fileTransport = pino_1.default.destination('x-fidelity.log');
49
45
  const prettyTransport = pino_1.default.transport({
50
46
  target: 'pino-pretty',
51
47
  options: {
@@ -1,2 +1,3 @@
1
1
  import { RepoXFIConfig } from '../types/typeDefs';
2
+ export declare const defaultRepoXFIConfig: RepoXFIConfig;
2
3
  export declare function loadRepoXFIConfig(repoPath: string): Promise<RepoXFIConfig>;