diff --git a/package-lock.json b/package-lock.json
index 42bf798..4b9378d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@genese/complexity",
- "version": "1.1.15",
+ "version": "1.1.21",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@genese/complexity",
- "version": "1.1.15",
+ "version": "1.1.21",
"license": "MIT",
"dependencies": {
"@genese/core": "^1.0.0-alpha.1",
@@ -24,6 +24,10 @@
},
"bin": {
"complexity": "dist/src/index.js"
+ },
+ "devDependencies": {
+ "@types/react": "^17.0.39",
+ "react": "^17.0.2"
}
},
"node_modules/@dsherret/to-absolute-glob": {
@@ -116,6 +120,29 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz",
"integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g=="
},
+ "node_modules/@types/prop-types": {
+ "version": "15.7.4",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
+ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==",
+ "dev": true
+ },
+ "node_modules/@types/react": {
+ "version": "17.0.39",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
+ "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
+ "dev": true,
+ "dependencies": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/scheduler": {
+ "version": "0.16.2",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
+ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
+ "dev": true
+ },
"node_modules/ansi-escapes": {
"version": "4.3.1",
"resolved": "http://localhost:4873/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
@@ -291,6 +318,12 @@
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
},
+ "node_modules/csstype": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
+ "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
+ "dev": true
+ },
"node_modules/csv-writer": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz",
@@ -506,6 +539,12 @@
"lodash": "4.17.15"
}
},
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "http://localhost:4873/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -539,6 +578,18 @@
"node": ">=10"
}
},
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -613,6 +664,15 @@
"resolved": "http://localhost:4873/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/onetime": {
"version": "5.1.2",
"resolved": "http://localhost:4873/onetime/-/onetime-5.1.2.tgz",
@@ -650,6 +710,19 @@
"node": ">=8.6"
}
},
+ "node_modules/react": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/regexp-to-ast": {
"version": "0.4.0",
"resolved": "http://localhost:4873/regexp-to-ast/-/regexp-to-ast-0.4.0.tgz",
@@ -939,6 +1012,29 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz",
"integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g=="
},
+ "@types/prop-types": {
+ "version": "15.7.4",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
+ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==",
+ "dev": true
+ },
+ "@types/react": {
+ "version": "17.0.39",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
+ "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
+ "dev": true,
+ "requires": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "@types/scheduler": {
+ "version": "0.16.2",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
+ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
+ "dev": true
+ },
"ansi-escapes": {
"version": "4.3.1",
"resolved": "http://localhost:4873/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
@@ -1075,6 +1171,12 @@
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
},
+ "csstype": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz",
+ "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==",
+ "dev": true
+ },
"csv-writer": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz",
@@ -1235,6 +1337,12 @@
"lodash": "4.17.15"
}
},
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
"jsonfile": {
"version": "6.1.0",
"resolved": "http://localhost:4873/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -1264,6 +1372,15 @@
"chalk": "^4.0.0"
}
},
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -1323,6 +1440,12 @@
"resolved": "http://localhost:4873/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
"onetime": {
"version": "5.1.2",
"resolved": "http://localhost:4873/onetime/-/onetime-5.1.2.tgz",
@@ -1351,6 +1474,16 @@
"resolved": "http://localhost:4873/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
},
+ "react": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
"regexp-to-ast": {
"version": "0.4.0",
"resolved": "http://localhost:4873/regexp-to-ast/-/regexp-to-ast-0.4.0.tgz",
diff --git a/package.json b/package.json
index 8e7dd7b..c0f5b9b 100644
--- a/package.json
+++ b/package.json
@@ -35,5 +35,9 @@
"terminal-link": "^2.1.1",
"ts-morph": "^8.2.0",
"ts-node": "^9.1.1"
+ },
+ "devDependencies": {
+ "@types/react": "^17.0.39",
+ "react": "^17.0.2"
}
}
diff --git a/src/core/enum/syntax-kind.enum.ts b/src/core/enum/syntax-kind.enum.ts
index 8adb52f..950d82e 100644
--- a/src/core/enum/syntax-kind.enum.ts
+++ b/src/core/enum/syntax-kind.enum.ts
@@ -193,6 +193,7 @@ export enum SyntaxKind {
JsxAttributes = 'JsxAttributes',
JsxClosingElement = 'JsxClosingElement',
JsxClosingFragment = 'JsxClosingFragment',
+ JsxComponent = 'JsxComponent',
JsxElement = 'JsxElement',
JsxExpression = 'JsxExpression',
JsxFragment = 'JsxFragment',
diff --git a/src/core/mocks/tsx/tsx.mock.tsx b/src/core/mocks/tsx/tsx.mock.tsx
new file mode 100644
index 0000000..25dec20
--- /dev/null
+++ b/src/core/mocks/tsx/tsx.mock.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+
+const component = () => {
+ console.log('TSX MOCKKKK');
+ return (
+
+ )
+}
diff --git a/src/index-debug.ts b/src/index-debug.ts
index a88df03..731d35d 100644
--- a/src/index-debug.ts
+++ b/src/index-debug.ts
@@ -15,7 +15,7 @@ const ENABLE_CONSOLE_REPORT = ARGS[3] === 'true';
let FRAMEWORK = ARGS[5] ?? undefined;
export async function startDebug(): Promise {
- const pathToAnalyse = `${process.cwd()}/src/core/mocks`;
+ const pathToAnalyse = `${process.cwd()}/src/core/mocks/tsx`;
FRAMEWORK = 'react';
Options.setOptions(process.cwd(), pathToAnalyse, __dirname);
if (!ENABLE_CONSOLE_REPORT) {
diff --git a/src/index.ts b/src/index.ts
index 7528e0d..1185f7e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,7 +19,7 @@ const ENABLE_MARKDOWN_REPORT = ARGS[2] === 'true';
const ENABLE_CONSOLE_REPORT = ARGS[3] === 'true';
const ENABLE_REFACTORING = ARGS[4] === 'true';
let FRAMEWORK = ARGS[5] ?? undefined;
-const DEBUG = false;
+const DEBUG = true;
let pathToAnalyse: string;
if (path.isAbsolute(PATH_TO_ANALYSE)) {
diff --git a/src/json-ast-to-reports/interfaces/evaluate.interface.ts b/src/json-ast-to-reports/interfaces/evaluate.interface.ts
index aaebb48..0640a9f 100644
--- a/src/json-ast-to-reports/interfaces/evaluate.interface.ts
+++ b/src/json-ast-to-reports/interfaces/evaluate.interface.ts
@@ -6,7 +6,7 @@ import { CpxFactors } from '../../core/models/cpx-factor/cpx-factors.model';
export interface Evaluate {
cpxFactors: CpxFactors; // The complexity factors of the object
- cyclomaticCpx: number; // The cyclomatic complexity of the object
+ cyclomaticCpx?: number; // The cyclomatic complexity of the object
evaluate:() => void; // The evaluation method
}
diff --git a/src/json-ast-to-reports/models/ast/ast-file.model.ts b/src/json-ast-to-reports/models/ast/ast-file.model.ts
index ca654ed..5eb3275 100644
--- a/src/json-ast-to-reports/models/ast/ast-file.model.ts
+++ b/src/json-ast-to-reports/models/ast/ast-file.model.ts
@@ -16,10 +16,12 @@ import { DepthCpx } from '../../../core/models/cpx-factor/depth-cpx.model';
import { addObjects } from '../../../core/services/tools.service';
import { AstMethodOrOutsideNode, isAstMethod } from '../../types/ast-method-or-outside-node.type';
import { CpxLevel } from '../../enums/cpx-level.enum';
+import { AstJsxComponent } from './ast-jsx.model';
export class AstFile implements AstFileInterface, Evaluate, Logg {
private _astFolder?: AstFolder = undefined; // The AstFolder which includes this AstFile
+ private _astJsxComponents: AstJsxComponent[];
private _astMethods?: AstMethod[] = []; // The AstMethods included in this AstFile
private _astNode?: AstNode = undefined; // The AstNode corresponding to the file itself
private _astNodes?: AstNode[] = undefined; // Array of all the AstNodes which are children of this.AstNode (including itself)
@@ -181,6 +183,16 @@ export class AstFile implements AstFileInterface, Evaluate, Logg {
}
+ get astJsxComponents(): AstJsxComponent[] {
+ return this._astJsxComponents;
+ }
+
+
+ set astJsxComponents(astJsxComponents: AstJsxComponent[]) {
+ this._astJsxComponents = astJsxComponents;
+ }
+
+
get name(): string {
return this._name;
}
@@ -226,6 +238,7 @@ export class AstFile implements AstFileInterface, Evaluate, Logg {
for (const methodOrOutsideNode of methodsAndOutsideNodes) {
this.evaluateMethodOrOutsideNode(methodOrOutsideNode);
}
+ this.getJsx();
}
@@ -236,6 +249,11 @@ export class AstFile implements AstFileInterface, Evaluate, Logg {
}
+ private getJsx(): any[] {
+ return [];
+ }
+
+
private evaluateMethodOrOutsideNode(methodOrOutsideNode: AstMethodOrOutsideNode): void {
methodOrOutsideNode.evaluate();
this.cpxFactors = this.cpxFactors.add(methodOrOutsideNode.cpxFactors);
diff --git a/src/json-ast-to-reports/models/ast/ast-jsx.model.ts b/src/json-ast-to-reports/models/ast/ast-jsx.model.ts
new file mode 100644
index 0000000..92e0ca5
--- /dev/null
+++ b/src/json-ast-to-reports/models/ast/ast-jsx.model.ts
@@ -0,0 +1,277 @@
+import { AstNode } from './ast-node.model';
+import { Code } from '../code/code.model';
+import { Ast } from '../../services/ast/ast.service';
+import { Evaluate } from '../../interfaces/evaluate.interface';
+import { CpxFactors } from '../../../core/models/cpx-factor/cpx-factors.model';
+import { ComplexityType } from '../../enums/complexity-type.enum';
+import { CodeLine } from '../code/code-line.model';
+import { cpxFactors } from '../../../core/const/cpx-factors';
+import { FactorCategory } from '../../enums/factor-category.enum';
+import { Options } from '../../../core/models/options.model';
+import { CpxLevel } from '../../enums/cpx-level.enum';
+
+/**
+ * Element of the AstNode structure corresponding to a given method
+ */
+export class AstJsxComponent implements Evaluate {
+
+ private _astNode?: AstNode = undefined; // The AST of the method itself
+ private _codeLines?: CodeLine[] = []; // The array of CodeLine of the AstMethod (elements of the array of CodeLine of the corresponding AstFile)
+ private _cognitiveLevel: CpxLevel = CpxLevel.LOW; // The cognitive level of the method
+ private _cpxFactors?: CpxFactors = undefined; // The complexity factors of the AstMethod
+ private _cpxIndex = undefined; // The complexity index of the method
+ private _displayedCode?: Code = undefined; // The code to display in the report
+ private _maxLineLength ?= 0; // The max length of the lines of the code
+ private _name: string = undefined; // The name of the method
+
+
+
+ // ---------------------------------------------------------------------------------
+ // Getters and setters
+ // ---------------------------------------------------------------------------------
+
+
+ get astNode(): AstNode {
+ return this._astNode;
+ }
+
+
+ set astNode(astNode: AstNode) {
+ this._astNode = astNode;
+ }
+
+
+ get codeLines(): CodeLine[] {
+ return this._codeLines;
+ }
+
+
+ set codeLines(codeLines: CodeLine[]) {
+ this._codeLines = codeLines;
+ }
+
+
+ get cognitiveLevel(): CpxLevel {
+ return this._cognitiveLevel;
+ }
+
+
+ set cognitiveLevel(cognitiveStatus: CpxLevel) {
+ this._cognitiveLevel = cognitiveStatus;
+ }
+
+
+ get cpxFactors(): CpxFactors {
+ return this._cpxFactors;
+ }
+
+
+ set cpxFactors(cpxFactors: CpxFactors) {
+ this._cpxFactors = cpxFactors;
+ }
+
+
+ get cpxIndex(): number {
+ return this._cpxIndex ?? this.cpxFactors.total;
+ }
+
+
+ get displayedCode(): Code {
+ return this._displayedCode;
+ }
+
+
+ get end(): number {
+ return this.astNode.end;
+ }
+
+
+ get maxLineLength(): number {
+ if (this._maxLineLength) {
+ return this._maxLineLength;
+ }
+ this._maxLineLength = Math.max(...this.codeLines?.map(l => l.end - l.start));
+ return this._maxLineLength;
+ }
+
+
+ get name(): string {
+ if (this._name) {
+ return this._name;
+ }
+ this._name = this._astNode.name;
+ return this._name;
+ }
+
+
+ set name(name: string) {
+ this._name = name;
+ }
+
+
+ get pos() {
+ return this.astNode?.pos;
+ }
+
+
+ get start() {
+ return this.astNode?.start;
+ }
+
+
+
+ // ---------------------------------------------------------------------------------
+ // Other methods
+ // ---------------------------------------------------------------------------------
+
+
+
+ /**
+ * Creates the displayed code of this AstMethod and evaluates its complexity
+ */
+ evaluate(): void {
+ this.createDisplayedCodeAndCalculateCpxFactors();
+ // LogService.logMethod(this);
+ this.cognitiveLevel = this.getComplexityStatus(ComplexityType.COGNITIVE);
+ }
+
+
+ /**
+ * Gets the complexity status of the method for a given complexity type
+ * @param cpxType
+ */
+ getComplexityStatus(cpxType: ComplexityType): CpxLevel {
+ let status = CpxLevel.MEDIUM;
+ if (cpxType === ComplexityType.COGNITIVE && this.cpxIndex <= Options.cognitiveCpx.warningThreshold) {
+ status = CpxLevel.LOW;
+ } else if (cpxType === ComplexityType.COGNITIVE && Math.round(this.cpxIndex) > Options.cognitiveCpx.errorThreshold) {
+ status = CpxLevel.HIGH;
+ }
+ return status;
+ }
+
+
+ /**
+ * Creates the method's code to display, with comments
+ * @param astNode // The AstNode to analyse (by default: the AstNode associated to this AstMethod)
+ */
+ createDisplayedCodeAndCalculateCpxFactors(astNode: AstNode = this.astNode): void {
+ this.setDisplayedCodeLines();
+ this.setDeclarationCpxFactors();
+ this.setCpxFactorsToDisplayedCode(astNode, false);
+ this._displayedCode.setLinesDepthAndNestingCpx();
+ this.addCommentsToDisplayedCode();
+ this.calculateCpxFactors();
+ this._displayedCode.setTextWithLines();
+ }
+
+
+ /**
+ * Creates the Code object corresponding to the code to display
+ */
+ private setDisplayedCodeLines(): void {
+ this._displayedCode = new Code();
+ for (const line of this.codeLines) {
+ const displayedLine = new CodeLine();
+ displayedLine.issue = line.issue;
+ displayedLine.end = line.end;
+ displayedLine.start = line.start;
+ displayedLine.text = line.text;
+ displayedLine.text = this.getDisplayedLineText(displayedLine);
+ this._displayedCode.lines.push(displayedLine);
+ }
+ }
+
+
+ /**
+ * Returns the text to display for a given line. Removes characters of the first and the last lines which are not inside the AstMethod
+ * @param line // The line to display
+ */
+ private getDisplayedLineText(line: CodeLine): string {
+ let text = line.text;
+ if (line.issue === this.codeLines[0]?.issue) {
+ const firstCharPosition = this.start - line.start;
+ const indentation = text.slice(0, text.length - text.trimLeft().length)
+ text = `\n${indentation}${text.slice(firstCharPosition)}`;
+ }
+ if (line.issue === this.codeLines[this.codeLines.length - 1]?.issue) {
+ const lastCharPosition = this.end - line.start;
+ text = text.slice(0, lastCharPosition);
+ }
+ return text;
+ }
+
+
+ private setDeclarationCpxFactors(): void {
+ this.increaseLineCpxFactors(this.astNode, this._displayedCode.getLine(this.astNode.lineStart));
+ this._displayedCode.getLine(this.astNode.lineStart).astNodes.push(this.astNode);
+ }
+
+
+ /**
+ * Calculates the complexity factors of each CodeLine
+ * @param astNode // The AstNode of the method
+ * @param startedUncommentedLines // Param for recursion (checks if the current line is the first uncommented one)
+ */
+ private setCpxFactorsToDisplayedCode(astNode: AstNode, startedUncommentedLines = false): void {
+ for (const childAst of astNode.children) {
+ let issue = Math.max(childAst.lineStart, this.codeLines[0]?.issue);
+ const codeLine: CodeLine = this._displayedCode.lines.find(l => l.issue === issue);
+ if (Ast.isElseStatement(childAst)) {
+ childAst.cpxFactors.atomic.node = cpxFactors.atomic.node;
+ issue--;
+ }
+ this.increaseLineCpxFactors(childAst, codeLine);
+ this._displayedCode.getLine(issue).astNodes.push(childAst);
+ this.setCpxFactorsToDisplayedCode(childAst, startedUncommentedLines);
+ }
+ }
+
+
+ /**
+ * Adds the Complexity of a AstNode to its CodeLine
+ * @param astNode // The AstNode inside the line of code
+ * @param codeLine // The CodeLine containing the AstNode
+ */
+ private increaseLineCpxFactors(astNode: AstNode, codeLine: CodeLine): void {
+ if (!codeLine.isCommented) {
+ codeLine.cpxFactors = codeLine.cpxFactors.add(astNode?.cpxFactors);
+ }
+ }
+
+
+ /**
+ * Adds information about complexity factors for each line of the displayed code
+ */
+ private addCommentsToDisplayedCode(): void {
+ this._displayedCode.lines
+ .filter(line => line.cpxFactors.total > 0)
+ .forEach(line => {
+ let comment = `+${line.cpxFactors.total.toFixed(1)} Complexity index (+${line.cpxFactors.totalAtomic.toFixed(1)} ${FactorCategory.ATOMIC}`;
+ comment = line.cpxFactors.totalStructural > 0 ? `${comment}, +${line.cpxFactors.totalStructural} ${FactorCategory.STRUCTURAL}` : comment;
+ comment = line.cpxFactors.totalNesting > 0 ? `${comment}, +${line.cpxFactors.totalNesting} nesting` : comment;
+ comment = line.cpxFactors.totalTyping > 0 ? `${comment}, +${line.cpxFactors.totalTyping} typing` : comment;
+ comment = line.cpxFactors.totalAggregation > 0 ? `${comment}, +${line.cpxFactors.totalAggregation} ${FactorCategory.AGGREGATION}` : comment;
+ comment = line.cpxFactors.totalDepth > 0 ? `${comment}, +${line.cpxFactors.totalDepth} depth` : comment;
+ comment = line.cpxFactors.totalRecursion > 0 ? `${comment}, +${line.cpxFactors.totalRecursion} recursivity` : comment;
+ comment = line.cpxFactors.totalUse > 0 ? `${comment}, +${line.cpxFactors.totalUse} ${FactorCategory.USE}` : comment;
+ comment = `${comment})`;
+ this._displayedCode.getLine(line.issue).addComment(comment, this.maxLineLength);
+ });
+ }
+
+
+ /**
+ * Calculates the Complexity Factors of the method
+ */
+ private calculateCpxFactors(): void {
+ const lines: CodeLine[] = this._displayedCode?.lines;
+ if (lines.length === 0) {
+ this.createDisplayedCodeAndCalculateCpxFactors();
+ }
+ this.cpxFactors = new CpxFactors();
+ for (const line of this._displayedCode?.lines) {
+ this.cpxFactors = this.cpxFactors.add(line.cpxFactors);
+ }
+ }
+}
diff --git a/src/json-ast-to-reports/models/ast/ast-node.model.ts b/src/json-ast-to-reports/models/ast/ast-node.model.ts
index ebbf462..c87e1c2 100644
--- a/src/json-ast-to-reports/models/ast/ast-node.model.ts
+++ b/src/json-ast-to-reports/models/ast/ast-node.model.ts
@@ -18,10 +18,12 @@ import { CpxFactorsInterface } from '../../../core/interfaces/cpx-factors.interf
import { FactorCategory } from '../../enums/factor-category.enum';
import { TypingCpx } from '../../../core/models/cpx-factor/typing-cpx.model';
import { Options } from '../../../core/models/options.model';
+import { AstJsxComponent } from './ast-jsx.model';
export class AstNode implements AstNodeInterface, Evaluate, Logg {
private _astFile?: AstFile = undefined; // The AstFile containing the AST node of the AstNode
+ private _astJsxComponent?: AstJsxComponent = undefined; // The method at the root of the current ast (if this ast is inside a method)
private _astMethod?: AstMethod = undefined; // The method at the root of the current ast (if this ast is inside a method)
private _astNodeService?: AstNodeService = new AstNodeService(); // The service managing AstNodes
private _children?: AstNode[] = []; // The children AstNodes of the AstNode
@@ -69,6 +71,16 @@ export class AstNode implements AstNodeInterface, Evaluate, Logg {
}
+ get astJsxComponent(): AstJsxComponent {
+ return this._astJsxComponent;
+ }
+
+
+ set astJsxComponent(astJsxComponent: AstJsxComponent) {
+ this._astJsxComponent = astJsxComponent;
+ }
+
+
get astMethod(): AstMethod {
return this._astMethod;
}
diff --git a/src/json-ast-to-reports/services/ast/ast-file.service.ts b/src/json-ast-to-reports/services/ast/ast-file.service.ts
index 8feccf7..4d68306 100644
--- a/src/json-ast-to-reports/services/ast/ast-file.service.ts
+++ b/src/json-ast-to-reports/services/ast/ast-file.service.ts
@@ -4,6 +4,7 @@ import { StatsService } from '../report/stats.service';
import { Stats } from '../../models/stats.model';
import { ComplexityType } from '../../enums/complexity-type.enum';
import { CpxLevel } from '../../enums/cpx-level.enum';
+import { AstJsxComponent } from '../../models/ast/ast-jsx.model';
/**
* - AstFiles generation from Abstract Syntax AstNode of a file
@@ -74,4 +75,10 @@ export class AstFileService extends StatsService {
this._stats.subject = astFile.name;
}
+
+ getJsxElements(astFile: AstFile): AstJsxComponent[] {
+ console.log('GET JSXXXX')
+ return [];
+ }
+
}
diff --git a/src/json-ast-to-reports/services/ast/ast.service.ts b/src/json-ast-to-reports/services/ast/ast.service.ts
index 7b7ad35..4089bef 100644
--- a/src/json-ast-to-reports/services/ast/ast.service.ts
+++ b/src/json-ast-to-reports/services/ast/ast.service.ts
@@ -145,6 +145,14 @@ export class Ast {
false;
}
+ /**
+ * Checks if an AST node is a function or a method
+ * @param astNode
+ */
+ static isJsxComponent(astNode: AstNode): boolean {
+ return astNode?.type === SyntaxKind.JsxComponent;
+ }
+
/**
* Checks if an AST node is a function or a method
* @param astNode
diff --git a/src/json-ast-to-reports/services/init.service.ts b/src/json-ast-to-reports/services/init.service.ts
index 3b83283..c725fc0 100644
--- a/src/json-ast-to-reports/services/init.service.ts
+++ b/src/json-ast-to-reports/services/init.service.ts
@@ -9,6 +9,7 @@ import { AstNodeService } from './ast/ast-node.service';
import { Ast } from './ast/ast.service';
import { AssignedFunctionsService } from './ast/assigned-functions.service';
import { OutsideCodeService } from './ast/outside-code.service';
+import { AstJsxComponent } from '../models/ast/ast-jsx.model';
/**
* - AstFolders generation from Abstract Syntax Tree of a folder
@@ -88,18 +89,30 @@ export class InitService {
newAstFile.code = CodeService.getCode(astFileFromJsonAst.text);
newAstFile.astNode = this.getFileAstNode(astFileFromJsonAst.astNode, newAstFile);
newAstFile.astNodes = this.astNodeService.flatMapAstNodes(newAstFile.astNode, [newAstFile.astNode]);
- newAstFile.astMethods = newAstFile.astNodes
- .filter(e => {
- return Ast.isFunctionOrMethod(e)
- })
- .map(e => e.astMethod);
+ newAstFile.astMethods = this.getFunctionsOrMethods(newAstFile);
+ newAstFile.astJsxComponents = this.getJsxComponents(newAstFile);
const functionsAssignedToVars: AstMethod[] = AssignedFunctionsService.getArrowFunctions(newAstFile.astNode);
newAstFile.astMethods = newAstFile.astMethods.concat(functionsAssignedToVars);
newAstFile.astOutsideNodes = OutsideCodeService.getOutsideNodes(newAstFile.astNode);
+ console.log('AST JSX COMPONENTSSSS', newAstFile.astJsxComponents);
return newAstFile;
}
+ private getFunctionsOrMethods(astFile: AstFile): AstMethod[] {
+ return astFile.astNodes
+ .filter(Ast.isFunctionOrMethod)
+ .map(e => e.astMethod);
+ }
+
+
+ private getJsxComponents(astFile: AstFile): AstJsxComponent[] {
+ return astFile.astNodes
+ .filter(Ast.isJsxComponent)
+ .map(e => e.astJsxComponent);
+ }
+
+
/**
* Generates the AstNode of a given AstFile with the astNode property in the JsonAst object
* @param astNodeFromJsonAst // The astNode property in the JsonAst object
@@ -152,6 +165,13 @@ export class InitService {
newAstNode.text = astNodeFromJsonAst.text;
newAstNode.type = astNodeFromJsonAst.type;
newAstNode.children = this.generateAstNodes(astNodeFromJsonAst.children, newAstNode);
+ this.setAstMethodProperty(astNodeFromJsonAst, astParentNode, newAstNode);
+ this.setAstJsxComponentProperty(astNodeFromJsonAst, astParentNode, newAstNode);
+ return newAstNode;
+ }
+
+
+ private setAstMethodProperty(astNodeFromJsonAst: any, astParentNode: AstNode, newAstNode: AstNode): void {
if (Ast.isFunctionOrMethod(astNodeFromJsonAst)) {
if (!newAstNode.name && newAstNode.firstSon?.kind === SyntaxKind.Identifier) {
newAstNode.name = newAstNode.children[0].name;
@@ -160,7 +180,16 @@ export class InitService {
} else {
newAstNode.astMethod = astParentNode?.astMethod;
}
- return newAstNode;
+
+ }
+
+
+ private setAstJsxComponentProperty(astNodeFromJsonAst: any, astParentNode: AstNode, newAstNode: AstNode): void {
+ if (Ast.isJsxComponent(astNodeFromJsonAst)) {
+ newAstNode.astJsxComponent = this.generateAstJsxComponent(newAstNode);
+ } else {
+ newAstNode.astJsxComponent = astParentNode?.astJsxComponent;
+ }
}
@@ -177,6 +206,19 @@ export class InitService {
}
+ /**
+ * Generates the AstMethod corresponding to an AstNode with kind corresponding to a FunctionDeclaration or a MethodDeclaration
+ * @param astJsxComponentNode // The AstNode which corresponds to a FunctionDeclaration or a MethodDeclaration
+ */
+ private generateAstJsxComponent(astJsxComponentNode: AstNode): AstJsxComponent {
+ const astJsxComponent = new AstJsxComponent();
+ astJsxComponent.astNode = astJsxComponentNode;
+ astJsxComponent.astNode.text = this.astNodeService.getCode(astJsxComponentNode);
+ astJsxComponent.codeLines = astJsxComponentNode.astFile?.code?.lines?.slice(astJsxComponentNode.linePos - 1, astJsxComponentNode.lineEnd);
+ return astJsxComponent;
+ }
+
+
/**
* Returns the path without slash corresponding to the "path" property of the JsonAst object
* @param jsonAstFolder
diff --git a/src/languages-to-json-ast/ts/services/ast-file-generation.service.ts b/src/languages-to-json-ast/ts/services/ast-file-generation.service.ts
index e179f9c..6abbf4d 100644
--- a/src/languages-to-json-ast/ts/services/ast-file-generation.service.ts
+++ b/src/languages-to-json-ast/ts/services/ast-file-generation.service.ts
@@ -10,7 +10,6 @@ import { Ts } from './ts.service';
import { randomString } from '../../../core/services/tools.service';
import { Options } from '../../../core/models/options.model';
import { ReactService } from '../specific/react/react.service';
-import { isJsx } from '../utils/ast.util';
/**
* - AstFiles generation from their Abstract Syntax Tree (AST)
@@ -69,14 +68,12 @@ export class AstFileGenerationService {
start: node.getStart()
};
astNode = this.addTypeAndCpxFactors(node, astNode);
- if (!isJsx(node)) {
- node.forEachChild((childNode: Node) => {
- if (!astNode.children) {
- astNode.children = [];
- }
- astNode.children.push(this.createAstNodeChildren(childNode));
- });
- }
+ node.forEachChild((childNode: Node) => {
+ if (!astNode.children) {
+ astNode.children = [];
+ }
+ astNode.children.push(this.createAstNodeChildren(childNode));
+ });
return astNode;
}
@@ -105,6 +102,9 @@ export class AstFileGenerationService {
if (Ts.isVarStatement(node)) {
astNode.type = Ts.getVarStatementType(node);
}
+ if (Ts.isJsxComponent(node)) {
+ astNode.type = SyntaxKind.JsxComponent;
+ }
return astNode;
}
diff --git a/src/languages-to-json-ast/ts/services/ts.service.ts b/src/languages-to-json-ast/ts/services/ts.service.ts
index e7c7c45..9941b2e 100644
--- a/src/languages-to-json-ast/ts/services/ts.service.ts
+++ b/src/languages-to-json-ast/ts/services/ts.service.ts
@@ -1,5 +1,13 @@
import { KindAliases } from '../../globals.const';
-import { Expression, Node, ParameterDeclaration, SyntaxKind, VariableDeclaration, VariableStatement } from 'ts-morph';
+import {
+ Expression,
+ JsxElement,
+ Node,
+ ParameterDeclaration,
+ SyntaxKind,
+ VariableDeclaration,
+ VariableStatement
+} from 'ts-morph';
import { isFunctionKind } from '../types/function-kind.type';
import { FunctionNode } from '../types/function-node.type';
@@ -83,6 +91,21 @@ export class Ts {
}
+ static isJsxComponent(node: Node): node is JsxElement {
+ return this.isJsxElement(node) && !this.hasJsxElementAncestor(node);
+ }
+
+
+ static isJsxElement(node: Node): node is JsxElement {
+ return node.getKind() === SyntaxKind.JsxElement;
+ }
+
+
+ static hasJsxElementAncestor(node: Node): boolean {
+ return !!node.getFirstAncestorByKind(SyntaxKind.JsxElement);
+ }
+
+
static getFunctionType(functionNode: FunctionNode): string {
if (!this.hasCompilerNodeType(functionNode)) {
return undefined;
diff --git a/src/languages-to-json-ast/ts/utils/ast.util.ts b/src/languages-to-json-ast/ts/utils/ast.util.ts
deleted file mode 100644
index 1b42ccb..0000000
--- a/src/languages-to-json-ast/ts/utils/ast.util.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { Node } from 'ts-morph';
-
-
-export function isJsx(node: Node): boolean {
- return node?.getKindName()?.slice(0, 3) === 'Jsx';
-}