x-fidelity 3.12.0 → 3.13.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 (51) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/demoConfig/node-fullstack.json +17 -7
  3. package/dist/demoConfig/rules/functionComplexity-iterative-rule.json +31 -0
  4. package/dist/demoConfig/rules/functionCount-iterative-rule.json +30 -0
  5. package/dist/demoConfig/rules/mutuallyExclusivePackages-global-rule.json +38 -0
  6. package/dist/demoConfig/rules/newSdkFeatureNotAdoped-global-rule.json +1 -1
  7. package/dist/demoConfig/rules/openaiAnalysisTestCriticality-global-rule.json +31 -0
  8. package/dist/facts/globalFileAnalysisFacts.js +1 -1
  9. package/dist/facts/openaiAnalysisFacts.js +2 -2
  10. package/dist/plugins/xfiPluginAst/facts/astFact.d.ts +2 -0
  11. package/dist/plugins/xfiPluginAst/facts/astFact.js +33 -0
  12. package/dist/plugins/xfiPluginAst/facts/functionComplexityFact.d.ts +2 -0
  13. package/dist/plugins/xfiPluginAst/facts/functionComplexityFact.js +136 -0
  14. package/dist/plugins/xfiPluginAst/facts/functionCountFact.d.ts +2 -0
  15. package/dist/plugins/xfiPluginAst/facts/functionCountFact.js +69 -0
  16. package/dist/plugins/xfiPluginAst/index.d.ts +1 -0
  17. package/dist/plugins/xfiPluginAst/index.js +5 -0
  18. package/dist/plugins/xfiPluginAst/operators/astComplexity.d.ts +2 -0
  19. package/dist/plugins/xfiPluginAst/operators/astComplexity.js +33 -0
  20. package/dist/plugins/xfiPluginAst/operators/functionCount.d.ts +2 -0
  21. package/dist/plugins/xfiPluginAst/operators/functionCount.js +28 -0
  22. package/dist/plugins/xfiPluginAst/xfiPluginAst.d.ts +3 -0
  23. package/dist/plugins/xfiPluginAst/xfiPluginAst.js +20 -0
  24. package/dist/utils/astUtils.d.ts +7 -0
  25. package/dist/utils/astUtils.js +78 -0
  26. package/package.json +5 -1
  27. package/src/demoConfig/node-fullstack.json +17 -7
  28. package/src/demoConfig/rules/functionComplexity-iterative-rule.json +31 -0
  29. package/src/demoConfig/rules/functionCount-iterative-rule.json +30 -0
  30. package/src/demoConfig/rules/mutuallyExclusivePackages-global-rule.json +38 -0
  31. package/src/demoConfig/rules/newSdkFeatureNotAdoped-global-rule.json +1 -1
  32. package/src/demoConfig/rules/openaiAnalysisTestCriticality-global-rule.json +31 -0
  33. package/src/exampleTriggerFiles/mixedUIComponents.tsx +11 -0
  34. package/src/facts/globalFileAnalysisFacts.ts +1 -1
  35. package/src/facts/openaiAnalysisFacts.ts +2 -2
  36. package/src/plugins/xfiPluginAst/facts/astFact.ts +24 -0
  37. package/src/plugins/xfiPluginAst/facts/functionComplexityFact.ts +146 -0
  38. package/src/plugins/xfiPluginAst/facts/functionCountFact.ts +63 -0
  39. package/src/plugins/xfiPluginAst/index.ts +1 -0
  40. package/src/plugins/xfiPluginAst/operators/astComplexity.ts +33 -0
  41. package/src/plugins/xfiPluginAst/operators/functionCount.ts +29 -0
  42. package/src/plugins/xfiPluginAst/sampleRules/functionComplexity-iterative-rule.json +31 -0
  43. package/src/plugins/xfiPluginAst/sampleRules/functionCount-iterative-rule.json +30 -0
  44. package/src/plugins/xfiPluginAst/xfiPluginAst.ts +20 -0
  45. package/src/types/tree-sitter-typescript.d.ts +4 -0
  46. package/src/utils/astUtils.ts +47 -0
  47. package/tsconfig.json +9 -3
  48. package/website/docs/getting-started.md +4 -0
  49. package/website/docs/local-configuration.md +22 -0
  50. package/website/docs/notifications.md +136 -0
  51. package/website/sidebars.js +1 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,36 @@
1
+ # [3.13.0](https://github.com/zotoio/x-fidelity/compare/v3.12.1...v3.13.0) (2025-03-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add proper TypeScript types for tree-sitter nodes and imports ([9f9d23f](https://github.com/zotoio/x-fidelity/commit/9f9d23ff8b7a08fae53e3d7512c368d187a71976))
7
+ * correct JavaScript parser language initialization ([9ea4ba0](https://github.com/zotoio/x-fidelity/commit/9ea4ba0077cf69f4fa04f3fa0bff65b6b67974a0))
8
+ * correct TypeScript import declaration for tree-sitter-typescript ([a0c3355](https://github.com/zotoio/x-fidelity/commit/a0c3355bd6774d579ac14c5bf944c89e7a1151db))
9
+ * handle empty array case for maxComplexity calculation ([301e5c3](https://github.com/zotoio/x-fidelity/commit/301e5c3e53e37e0976b81a0f6f1c0c1748c3666c))
10
+ * replace cursor traversal with recursive AST traversal for complexity analysis ([4d54473](https://github.com/zotoio/x-fidelity/commit/4d5447324be6d36cd25b9b752e647ec971ffaf95))
11
+ * resolve maxComplexity variable redeclaration in functionComplexityFact ([0d35ea8](https://github.com/zotoio/x-fidelity/commit/0d35ea82a88bca3b6b5c9d9b8a6456e1ee083af4))
12
+ * Update fact value key from 'ast' to 'astResult' ([e930b53](https://github.com/zotoio/x-fidelity/commit/e930b53d7bbc9414d66906903c0b01a1f2058405))
13
+ * update tree-sitter TypeScript import path and usage ([8bf7ce6](https://github.com/zotoio/x-fidelity/commit/8bf7ce6b34be567216dc331f99b87be67fd5d8f3))
14
+ * update tree-sitter walk API usage to use cursor-based traversal ([f92f2c0](https://github.com/zotoio/x-fidelity/commit/f92f2c0abd14d233d43ec377c4f783bbbae35da5))
15
+
16
+
17
+ ### Features
18
+
19
+ * add AST analysis capabilities with function complexity detection ([9d01df0](https://github.com/zotoio/x-fidelity/commit/9d01df0bc3c49e92b6b870c87313a0936704b7b2))
20
+ * add debug logging to AST plugin operations ([cd7ea16](https://github.com/zotoio/x-fidelity/commit/cd7ea16680d4c8d24fea1d14442ed8c3448b159b))
21
+ * add function count rule with AST analysis ([3311d85](https://github.com/zotoio/x-fidelity/commit/3311d8528ff369cac21bee346dce7c2c109208fe))
22
+ * add minimum complexity threshold filter for function analysis ([a67279c](https://github.com/zotoio/x-fidelity/commit/a67279c134d9dbdd711d9782389d6ee8629d929f))
23
+ * add type declarations for tree-sitter-typescript module ([afd1553](https://github.com/zotoio/x-fidelity/commit/afd1553895f33eca6a016e194d70f504d3fb0e03))
24
+ * create AST plugin with facts and operators ([0be5fa5](https://github.com/zotoio/x-fidelity/commit/0be5fa59d76ad2b5fa261545b0c1254ae1441c6c))
25
+ * **plugin:** ast based facts and rule examples ([b734111](https://github.com/zotoio/x-fidelity/commit/b7341118645627967f0adfbe89664c4ffc5752a2))
26
+
27
+ ## [3.12.1](https://github.com/zotoio/x-fidelity/compare/v3.12.0...v3.12.1) (2025-03-10)
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * **examples:** simple rules to check code evolution ([46547a6](https://github.com/zotoio/x-fidelity/commit/46547a6d5127976178b57010dbc33ad16d0cbdbc))
33
+
1
34
  # [3.12.0](https://github.com/zotoio/x-fidelity/compare/v3.11.0...v3.12.0) (2025-03-10)
2
35
 
3
36
 
@@ -3,37 +3,47 @@
3
3
  "rules": [
4
4
  "sensitiveLogging-iterative",
5
5
  "outdatedFramework-global",
6
- "noDatabases-iterative",
6
+ "noDatabases-iterative",
7
7
  "nonStandardDirectoryStructure-global",
8
8
  "openaiAnalysisTop5-global",
9
9
  "openaiAnalysisA11y-global",
10
+ "openaiAnalysisTestCriticality-global",
10
11
  "invalidSystemIdConfigured-iterative",
11
12
  "missingRequiredFiles-global",
12
13
  "factDoesNotAddResultToAlmanac-iterative",
13
- "newSdkFeatureNotAdoped-global"
14
+ "newSdkFeatureNotAdoped-global",
15
+ "mutuallyExclusivePackages-global",
16
+ "functionComplexity-iterative",
17
+ "functionCount-iterative"
14
18
  ],
15
19
  "operators": [
16
20
  "fileContains",
17
- "outdatedFramework",
21
+ "outdatedFramework",
18
22
  "nonStandardDirectoryStructure",
19
23
  "openaiAnalysisHighSeverity",
20
24
  "invalidRemoteValidation",
21
25
  "missingRequiredFiles",
22
26
  "regexMatch",
23
27
  "globalPatternRatio",
24
- "globalPatternCount"
28
+ "globalPatternCount",
29
+ "astComplexity",
30
+ "functionCount"
25
31
  ],
26
32
  "facts": [
27
33
  "repoFilesystemFacts",
28
34
  "repoDependencyFacts",
29
35
  "openaiAnalysisFacts",
30
- "remoteSubstringValidation",
36
+ "remoteSubstringValidation",
31
37
  "missingRequiredFiles",
32
- "globalFileAnalysisFacts"
38
+ "globalFileAnalysisFacts",
39
+ "ast",
40
+ "functionComplexity",
41
+ "functionCount"
33
42
  ],
34
43
  "plugins": [
35
44
  "xfiPluginRequiredFiles",
36
- "xfiPluginRemoteStringValidator"
45
+ "xfiPluginRemoteStringValidator",
46
+ "xfiPluginAst"
37
47
  ],
38
48
  "config": {
39
49
  "minimumDependencyVersions": {
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "functionComplexity-iterative",
3
+ "conditions": {
4
+ "all": [
5
+ {
6
+ "fact": "fileData",
7
+ "path": "$.fileName",
8
+ "operator": "notEqual",
9
+ "value": "REPO_GLOBAL_CHECK"
10
+ },
11
+ {
12
+ "fact": "functionComplexity",
13
+ "params": {
14
+ "resultFact": "complexityResult",
15
+ "minimumComplexityLogged": 8
16
+ },
17
+ "operator": "astComplexity",
18
+ "value": 10
19
+ }
20
+ ]
21
+ },
22
+ "event": {
23
+ "type": "warning",
24
+ "params": {
25
+ "message": "Functions detected with high cyclomatic complexity (10+). Consider refactoring.",
26
+ "details": {
27
+ "fact": "complexityResult"
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "functionCount-iterative",
3
+ "conditions": {
4
+ "all": [
5
+ {
6
+ "fact": "fileData",
7
+ "path": "$.filePath",
8
+ "operator": "regexMatch",
9
+ "value": "^.*\\/facts\\/(?!.*\\.test).*\\.ts$"
10
+ },
11
+ {
12
+ "fact": "functionCount",
13
+ "params": {
14
+ "resultFact": "functionCountResult"
15
+ },
16
+ "operator": "functionCount",
17
+ "value": 20
18
+ }
19
+ ]
20
+ },
21
+ "event": {
22
+ "type": "warning",
23
+ "params": {
24
+ "message": "File contains too many functions (>20). Consider splitting into multiple files.",
25
+ "details": {
26
+ "fact": "functionCountResult"
27
+ }
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "mutuallyExclusivePackages-global",
3
+ "conditions": {
4
+ "all": [
5
+ {
6
+ "fact": "fileData",
7
+ "path": "$.fileName",
8
+ "operator": "equal",
9
+ "value": "REPO_GLOBAL_CHECK"
10
+ },
11
+ {
12
+ "fact": "globalFileAnalysis",
13
+ "params": {
14
+ "patterns": [
15
+ "import.*from\\s+['\"](@mui/material.*)['\"]",
16
+ "import.*from\\s+['\"](antd)['\"]",
17
+ "require\\(['\"](@mui/material.*)['\"]\\)",
18
+ "require\\(['\"](antd)['\"]\\)"
19
+ ],
20
+ "fileFilter": "\\.(js|jsx|ts|tsx)$",
21
+ "resultFact": "packageUsageAnalysis"
22
+ },
23
+ "operator": "globalPatternCount",
24
+ "value": 0
25
+ }
26
+ ]
27
+ },
28
+ "event": {
29
+ "type": "fatality",
30
+ "params": {
31
+ "message": "Mutually exclusive packages detected. MUI and AntDesign should not be used together.",
32
+ "details": {
33
+ "fact": "packageUsageAnalysis",
34
+ "recommendation": "Choose migrate to MUI."
35
+ }
36
+ }
37
+ }
38
+ }
@@ -12,7 +12,7 @@
12
12
  "fact": "globalFileAnalysis",
13
13
  "params": {
14
14
  "newPatterns": [
15
- "const plugin: XFiPlugin = {"
15
+ "const plugin: XFiPlugin.="
16
16
  ],
17
17
  "legacyPatterns": [
18
18
  "import {.*FactDefn.*} from '\\.\\./types/typeDefs';"
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "openaiAnalysisTestCriticality-global",
3
+ "conditions": {
4
+ "all": [
5
+ {
6
+ "fact": "fileData",
7
+ "path": "$.fileName",
8
+ "operator": "equal",
9
+ "value": "REPO_GLOBAL_CHECK"
10
+ },
11
+ {
12
+ "fact": "openaiAnalysis",
13
+ "params": {
14
+ "prompt": "what are the files and features in the codebase that are most likely to require unit test uplift in order to be able to trust pull-request checks?",
15
+ "resultFact": "openaiAnalysisTestCriticality"
16
+ },
17
+ "operator": "openaiAnalysisHighSeverity",
18
+ "value": 8
19
+ }
20
+ ]
21
+ },
22
+ "event": {
23
+ "type": "warning",
24
+ "params": {
25
+ "message": "OpenAI suggestions for the supplied prompt.",
26
+ "details": {
27
+ "fact": "openaiAnalysisTestCriticality"
28
+ }
29
+ }
30
+ }
31
+ }
@@ -60,7 +60,7 @@ exports.globalFileAnalysis = {
60
60
  fileMatches++;
61
61
  matchDetails.push({
62
62
  lineNumber: i + 1,
63
- match: match[0],
63
+ match: pattern,
64
64
  context: (0, maskSensitiveData_1.maskSensitiveData)(line.trim())
65
65
  });
66
66
  }
@@ -24,7 +24,7 @@ if ((0, openaiUtils_1.isOpenAIEnabled)()) {
24
24
  const openaiAnalysis = function (params, almanac) {
25
25
  return __awaiter(this, void 0, void 0, function* () {
26
26
  let result = { 'result': [] };
27
- const model = process.env.OPENAI_MODEL || 'o3-mini';
27
+ const model = process.env.OPENAI_MODEL || 'gpt-4o';
28
28
  try {
29
29
  if (!openai) {
30
30
  throw new Error('OpenAI client is not initialized');
@@ -40,7 +40,7 @@ const openaiAnalysis = function (params, almanac) {
40
40
  };
41
41
  const payload = {
42
42
  model,
43
- reasoning_effort: 'high',
43
+ //reasoning_effort: 'high',
44
44
  messages: [
45
45
  { role: 'system', content: openaiSystemPrompt },
46
46
  { role: 'user', content: `${params.prompt}
@@ -0,0 +1,2 @@
1
+ import { FactDefn } from '../../../types/typeDefs';
2
+ export declare const astFact: FactDefn;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.astFact = void 0;
13
+ const logger_1 = require("../../../utils/logger");
14
+ const astUtils_1 = require("../../../utils/astUtils");
15
+ exports.astFact = {
16
+ name: 'ast',
17
+ fn: (params, almanac) => __awaiter(void 0, void 0, void 0, function* () {
18
+ try {
19
+ const fileData = yield almanac.factValue('fileData');
20
+ const result = (0, astUtils_1.generateAst)(fileData);
21
+ // Add the AST to the almanac for other facts/operators to use
22
+ if (params === null || params === void 0 ? void 0 : params.resultFact) {
23
+ logger_1.logger.trace({ resultFact: params.resultFact }, 'Adding AST to almanac');
24
+ almanac.addRuntimeFact(params.resultFact, result);
25
+ }
26
+ return result;
27
+ }
28
+ catch (error) {
29
+ logger_1.logger.error(`Error in AST fact: ${error}`);
30
+ return { tree: null };
31
+ }
32
+ })
33
+ };
@@ -0,0 +1,2 @@
1
+ import { FactDefn } from '../../../types/typeDefs';
2
+ export declare const functionComplexityFact: FactDefn;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.functionComplexityFact = void 0;
13
+ const logger_1 = require("../../../utils/logger");
14
+ const astUtils_1 = require("../../../utils/astUtils");
15
+ exports.functionComplexityFact = {
16
+ name: 'functionComplexity',
17
+ fn: (params, almanac) => __awaiter(void 0, void 0, void 0, function* () {
18
+ try {
19
+ const fileData = yield almanac.factValue('fileData');
20
+ const { tree } = (0, astUtils_1.generateAst)(fileData);
21
+ if (!tree) {
22
+ logger_1.logger.debug('No AST available for complexity analysis');
23
+ return { complexity: 0 };
24
+ }
25
+ const complexities = [];
26
+ logger_1.logger.debug('Starting function complexity analysis');
27
+ // Visit each function declaration/expression
28
+ // Traverse the AST to find all function nodes
29
+ const functionNodes = [];
30
+ function visit(node) {
31
+ if (node.type === 'function_declaration' ||
32
+ node.type === 'function_expression' ||
33
+ node.type === 'arrow_function') {
34
+ functionNodes.push(node);
35
+ }
36
+ for (let child of node.children || []) {
37
+ visit(child);
38
+ }
39
+ }
40
+ visit(tree.rootNode);
41
+ // Get minimum complexity threshold from params
42
+ const minimumComplexityLogged = (params === null || params === void 0 ? void 0 : params.minimumComplexityLogged) || 0;
43
+ // Analyze each function node
44
+ for (const node of functionNodes) {
45
+ const name = getFunctionName(node);
46
+ const complexity = analyzeFunctionComplexity(node);
47
+ // Only include functions that exceed the minimum complexity threshold
48
+ if (complexity >= minimumComplexityLogged) {
49
+ logger_1.logger.debug({
50
+ functionName: name,
51
+ nodeType: node.type,
52
+ complexity,
53
+ startLine: node.startPosition.row + 1,
54
+ endLine: node.endPosition.row + 1,
55
+ threshold: minimumComplexityLogged
56
+ }, 'Function exceeds complexity threshold');
57
+ complexities.push({
58
+ name,
59
+ complexity,
60
+ location: {
61
+ start: node.startPosition,
62
+ end: node.endPosition
63
+ }
64
+ });
65
+ }
66
+ else {
67
+ logger_1.logger.debug({
68
+ functionName: name,
69
+ complexity,
70
+ threshold: minimumComplexityLogged
71
+ }, 'Function below complexity threshold - skipping');
72
+ }
73
+ }
74
+ // Calculate max complexity from values
75
+ const complexityValues = complexities.map(c => c.complexity);
76
+ const maxComplexity = complexityValues.length > 0 ? Math.max(...complexityValues) : 0;
77
+ logger_1.logger.debug({
78
+ functionCount: complexities.length,
79
+ maxComplexity,
80
+ complexityBreakdown: complexities.map(c => ({
81
+ name: c.name,
82
+ complexity: c.complexity
83
+ }))
84
+ }, 'Completed complexity analysis');
85
+ const result = {
86
+ complexities,
87
+ maxComplexity
88
+ };
89
+ if (params === null || params === void 0 ? void 0 : params.resultFact) {
90
+ logger_1.logger.debug({ resultFact: params.resultFact }, 'Adding complexity results to almanac');
91
+ almanac.addRuntimeFact(params.resultFact, result);
92
+ }
93
+ return result;
94
+ }
95
+ catch (error) {
96
+ logger_1.logger.error(`Error analyzing function complexity: ${error}`);
97
+ return { complexities: [], maxComplexity: 0 };
98
+ }
99
+ })
100
+ };
101
+ function analyzeFunctionComplexity(node) {
102
+ let complexity = 1; // Base complexity
103
+ // Walk the AST and count:
104
+ // - Conditional statements (if, else, switch cases)
105
+ // - Loops (for, while, do-while)
106
+ // - Logical operators (&&, ||)
107
+ // - Try/catch blocks
108
+ function visit(node) {
109
+ switch (node.type) {
110
+ case 'if_statement':
111
+ case 'switch_case':
112
+ case 'for_statement':
113
+ case 'while_statement':
114
+ case 'do_statement':
115
+ case 'try_statement':
116
+ complexity++;
117
+ break;
118
+ case '&&':
119
+ case '||':
120
+ complexity += 0.5;
121
+ break;
122
+ }
123
+ for (let child of node.children || []) {
124
+ visit(child);
125
+ }
126
+ }
127
+ visit(node);
128
+ return complexity;
129
+ }
130
+ function getFunctionName(node) {
131
+ if (node.type === 'function_declaration') {
132
+ const nameNode = node.descendantsOfType('identifier')[0];
133
+ return nameNode ? nameNode.text : 'anonymous';
134
+ }
135
+ return 'anonymous';
136
+ }
@@ -0,0 +1,2 @@
1
+ import { FactDefn } from '../../../types/typeDefs';
2
+ export declare const functionCountFact: FactDefn;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.functionCountFact = void 0;
13
+ const logger_1 = require("../../../utils/logger");
14
+ const astUtils_1 = require("../../../utils/astUtils");
15
+ exports.functionCountFact = {
16
+ name: 'functionCount',
17
+ fn: (params, almanac) => __awaiter(void 0, void 0, void 0, function* () {
18
+ try {
19
+ const fileData = yield almanac.factValue('fileData');
20
+ const { tree } = (0, astUtils_1.generateAst)(fileData);
21
+ if (!tree) {
22
+ logger_1.logger.debug('No AST available for function count analysis');
23
+ return { count: 0 };
24
+ }
25
+ // Find all function nodes
26
+ const functionNodes = [];
27
+ function visit(node) {
28
+ if (node.type === 'function_declaration' ||
29
+ node.type === 'function_expression' ||
30
+ node.type === 'arrow_function') {
31
+ functionNodes.push(node);
32
+ }
33
+ for (let child of node.children || []) {
34
+ visit(child);
35
+ }
36
+ }
37
+ visit(tree.rootNode);
38
+ const result = {
39
+ count: functionNodes.length,
40
+ functions: functionNodes.map(node => {
41
+ var _a;
42
+ return ({
43
+ name: node.type === 'function_declaration' ?
44
+ (((_a = node.descendantsOfType('identifier')[0]) === null || _a === void 0 ? void 0 : _a.text) || 'anonymous') :
45
+ 'anonymous',
46
+ location: {
47
+ start: node.startPosition,
48
+ end: node.endPosition
49
+ }
50
+ });
51
+ })
52
+ };
53
+ logger_1.logger.debug({
54
+ filePath: fileData.filePath,
55
+ functionCount: result.count,
56
+ functions: result.functions
57
+ }, 'Completed function count analysis');
58
+ // Add result to almanac if resultFact param provided
59
+ if (params === null || params === void 0 ? void 0 : params.resultFact) {
60
+ almanac.addRuntimeFact(params.resultFact, result);
61
+ }
62
+ return result;
63
+ }
64
+ catch (error) {
65
+ logger_1.logger.error(`Error in function count analysis: ${error}`);
66
+ return { count: 0, functions: [] };
67
+ }
68
+ })
69
+ };
@@ -0,0 +1 @@
1
+ export { plugin } from './xfiPluginAst';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.plugin = void 0;
4
+ var xfiPluginAst_1 = require("./xfiPluginAst");
5
+ Object.defineProperty(exports, "plugin", { enumerable: true, get: function () { return xfiPluginAst_1.plugin; } });
@@ -0,0 +1,2 @@
1
+ import { OperatorDefn } from '../../../types/typeDefs';
2
+ export declare const astComplexity: OperatorDefn;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.astComplexity = void 0;
4
+ const logger_1 = require("../../../utils/logger");
5
+ exports.astComplexity = {
6
+ name: 'astComplexity',
7
+ fn: (factValue, threshold) => {
8
+ var _a;
9
+ try {
10
+ logger_1.logger.debug({ threshold }, 'Checking AST complexity against threshold');
11
+ if (!factValue || !factValue.maxComplexity) {
12
+ logger_1.logger.debug('No complexity data available');
13
+ return false;
14
+ }
15
+ const result = factValue.maxComplexity >= threshold;
16
+ logger_1.logger.trace({
17
+ maxComplexity: factValue.maxComplexity,
18
+ threshold,
19
+ exceedsThreshold: result,
20
+ complexityDetails: (_a = factValue.complexities) === null || _a === void 0 ? void 0 : _a.map((c) => ({
21
+ name: c.name,
22
+ complexity: c.complexity,
23
+ exceedsThreshold: c.complexity >= threshold
24
+ }))
25
+ }, 'Completed complexity threshold check');
26
+ return result;
27
+ }
28
+ catch (error) {
29
+ logger_1.logger.error(`Error in astComplexity operator: ${error}`);
30
+ return false;
31
+ }
32
+ }
33
+ };
@@ -0,0 +1,2 @@
1
+ import { OperatorDefn } from '../../../types/typeDefs';
2
+ export declare const functionCount: OperatorDefn;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.functionCount = void 0;
4
+ const logger_1 = require("../../../utils/logger");
5
+ exports.functionCount = {
6
+ name: 'functionCount',
7
+ fn: (factValue, threshold) => {
8
+ try {
9
+ logger_1.logger.debug({ threshold }, 'Checking function count against threshold');
10
+ if (!factValue || typeof factValue.count !== 'number') {
11
+ logger_1.logger.debug('No valid function count data available');
12
+ return false;
13
+ }
14
+ const result = factValue.count > threshold;
15
+ logger_1.logger.debug({
16
+ count: factValue.count,
17
+ threshold,
18
+ exceedsThreshold: result,
19
+ functions: factValue.functions
20
+ }, 'Completed function count threshold check');
21
+ return result;
22
+ }
23
+ catch (error) {
24
+ logger_1.logger.error(`Error in functionCount operator: ${error}`);
25
+ return false;
26
+ }
27
+ }
28
+ };
@@ -0,0 +1,3 @@
1
+ import { XFiPlugin } from '../../types/typeDefs';
2
+ declare const plugin: XFiPlugin;
3
+ export { plugin };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.plugin = void 0;
4
+ const astFact_1 = require("./facts/astFact");
5
+ const functionComplexityFact_1 = require("./facts/functionComplexityFact");
6
+ const functionCountFact_1 = require("./facts/functionCountFact");
7
+ const astComplexity_1 = require("./operators/astComplexity");
8
+ const functionCount_1 = require("./operators/functionCount");
9
+ const plugin = {
10
+ name: 'xfiPluginAst',
11
+ version: '1.0.0',
12
+ facts: [astFact_1.astFact, functionComplexityFact_1.functionComplexityFact, functionCountFact_1.functionCountFact],
13
+ operators: [astComplexity_1.astComplexity, functionCount_1.functionCount],
14
+ onError: (error) => ({
15
+ message: `AST analysis error: ${error.message}`,
16
+ level: 'warning',
17
+ details: error.stack
18
+ })
19
+ };
20
+ exports.plugin = plugin;
@@ -0,0 +1,7 @@
1
+ import Parser from 'tree-sitter';
2
+ import { FileData } from '../types/typeDefs';
3
+ export declare function generateAst(fileData: FileData): {
4
+ tree: null;
5
+ } | {
6
+ tree: Parser.Tree;
7
+ };