VueJs Cyclomatic Complexity

Hello,
I wanted to know if SonarQube also calculates the cyclomatic complexity for .vue files?
Because in the version I use, 9.9, this metric is not present, not even for .ts files.

Hi,

Welcome to the community!

Yes, this should be calculated. Here’s an example from SonarQube itself:

Can you share what you’re expecting to see that you’re not seeing?

 
Thx,
Ann

Hi,
I expect the same calculation of java projects as in the image.


In contrast, for Vue projects, it is not calculated

Even opening the file detail (both .vue and .ts) only the cognitive complexity appears, but always with value 0, even where I am sure it is higher.

Eugenio

Hi Eugenio,

Thanks for the details. What version of SonarQube are you using?

 
Thx,
Ann

Hi Ann,
I use the version 9.9.

Eugenio

Hi,

Thanks for that detail. I’ve flagged this for the language experts.

 
Ann

Hi,
thx.

I would like to add that other metrics such as comments are also incorrectly calculated.

Probably the Vue.js framework is not fully supported.

Eugenio

Hello @Xeyos,

Vue is supported and indeed all those metrics should be properly calculated. We have some Vue projects in our internal tests and they are properly displayed.

Are there any issues shown in .vue files? Can you check the debug logs of the analysis and check if .vue files are listed during analysis? Just want to discard they are not being ignored in your configuration.

Cheers,
Victor

Hi,
then the vue files have no problem, they go through all the various lint checks before they get to SQ. They are parsed with eslint (with setting 0 warnings allowed).

I analyzed the job log of my CI (where I use the official image si sonar-cli) and I have this output:
0Analysis

My sonar.properties configuration is as follows:

sonar.projectKey=****

sonar.projectName=****
sonar.projectVersion=1.5.0
sonar.sourceEncoding=UTF-8

sonar.sources=./src
sonar.tests=./vitest/__tests__
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.typescript.tsconfigPath=tsconfig.json
sonar.coverage.exclusions=src/conf/**/*.json,src/plugins/**,src/router/**

In sonarqube i have .vue files allowed:


So I couldn’t identify the problem.

Eugenio

I found the problem, it is related the tsconfig.json, for some reason the confing structure of the most modern projects excludes the parsing of vue files:
This is my actual config:

{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.vitest.json"
    },
    { "path": "./tsconfig.node.json" }
  ],
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "noEmit": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

The solution seems to add:

"include": [
    "src/**/*.ts",
    "src/**/*.vue",
  ],

only a file that respects this inclusion however seems excluded:
TS

1 Like

Excellent, thanks for letting us know @Xeyos.

I was indeed going to ask you for tsconfig.json contents. Adding explicitly .vue files is needed:

  "include": ["src/**/*", "src/**/*.vue"],

Cheers,
Victor

Hi Victor,
yes I edited my previous response with the same solution.

Thx,
Eugenio

1 Like

Hi @victor.diez
I still can’t get it to parse the .ts files, as shown in the previous screen.
I looked at the logs and all the .ts files are reporting the same error.

Hi @Xeyos,

can you paste the full tsconfig.json contents? And also the contents of any referenced tsconfig? I see those 3 at least

Also, can you please add the full debug logs (add -X parameter to the scanner execution or sonar.verbose=true in sonar.properties)

Cheers,
Victor

Hi, yes.
tsconfig.json:

{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.vitest.json"
    },
    { "path": "./tsconfig.node.json" }
  ],
  "include": [
    "src/**/*",
    "src/**/*.vue",
    "src/**/*.ts",
  ],
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "noEmit": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

tsconfig.app.json:

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": [
    "env.d.ts",
    "src/**/*",
    "src/**/*.vue",
    "src/**/*.json",
    "src/**/*.ts"
  ],
  "exclude": ["**/__tests__/*"],
  "compilerOptions": {
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

tsconfig.node.json:

{
  "extends": "@tsconfig/node18/tsconfig.json",
  "include": [
    "vite.config.*",
    "vitest.config.*",
    "cypress.config.*",
    "playwright.config.*"
  ],
  "compilerOptions": {
    "composite": true,
    "types": ["node"],
    "module": "ESNext",
    "moduleResolution": "Node",
    "allowSyntheticDefaultImports": true
  }
}

tsconfig.vitest.json:

{
  "extends": "./tsconfig.app.json",
  "exclude": [],
  "compilerOptions": {
    "composite": true,
    "lib": [],
    "types": ["node", "jsdom"]
  }
}

SQ.txt (229.1 KB)

Hi @Xeyos,

seems the tsconfig fails to be properly resolved due to missing dependencies. Your referenced tsconfigs extend @tsconfig/node18/tsconfig.json and @vue/tsconfig/tsconfig.dom.json, which are usually available after installing dependencies. Either you do npm ci, or you can use a custom tsconfig.sonar.json to be used just for the analysis. Its contents should be something like this:

{
  "compilerOptions": {
    "strict": true,
    "module": "ESNext",
    "resolveJsonModule": true,
    "jsx": "preserve",
    "jsxImportSource": "vue",
    "verbatimModuleSyntax": true,
    "target": "ESNext",
    "composite": true,
    "useDefineForClassFields": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true,
    "types": ["node", "jsdom"],
    "moduleResolution": "Node",
    "isolatedModules": true,
    "lib": ["ESNext", "DOM"],
    "noEmit": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": [
    "src/**/*",
    "src/**/*.vue",
    "src/**/*.ts",
  ]
}

Such tsconfig will not depend on any external dependency. Place it in the root folder (src/**/* will be evaluated relative to the tsconfig.sonar.json path) and then use it in the sonar.typescript.tsconfigPath property:

sonar.typescript.tsconfigPath=tsconfig.sonar.json

Let me know if that helps.

Victor

The first solution, trying to parse the code with lots of node_modules folder (npm there), I had already tried it, I probably hadn’t investigated thoroughly to see if it worked.
I tried the tsconfig.sonar.json file as indicated but the “verbatimModuleSyntax” option is not recognized, and it failed without parsing any files.
So I rewrote the file correcting the error and incorporating my “tsconfig” configs and I would say it works. It also seems to me a clean solution for my CI, a dedicated parsing stage without the dependencies.

In the analysis I have some small difference in the metrics calculated with eslintcc, but it is probably due to my error locally.

Thank you very much for your help @victor.diez

1 Like

Good to know @Xeyos,

Do not hesitate to reach out if you have any more questions.

Cheers,
Victor

1 Like