Sonar Scanner doesn't respect override values via tsconfig extends

Must-share information (formatted with Markdown):

  • which versions are you using (SonarQube, Scanner, Plugin, and any relevant extension): 8.9.8
  • how is SonarQube deployed: zip, Docker, Helm: Docker
  • what are you trying to achieve: Successful scan of a dedicated tsconfig file for Sonar Scanner
  • what have you tried so far to achieve this: See below

Hi there,

I’m currently running into an issue where Sonar Scanner doesn’t seem to evaluate overrides. Our service contains a base tsconfig.json file that has "target": "es2021". This doesn’t seem to be a respected value via Sonar Scanner 4:

ERROR: Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'.Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'.

I also saw that because of this error, it ends up impacting the main projects view downstream in that it shows that the main branch analysis is empty:

Steps I’ve taken

So I ended up porting over to a tsconfig.sonar.json file that extends our base but that didn’t seem to work when I set the target to a valid choice, in this case esnext

{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "target": "esnext",
        "lib": [
            "esnext",
            "dom"
          ],
    },
}

Although I’ve confirmed that the extends works at a tsc level, it seems to choke at the Sonar Scanner level when I set sonar.typescript.tsconfigPath=tsconfig.sonar.json and continues to think that target is es2021 (which is inherited from the base tsconfig.json file.

Please advise as the only workaround I’ve found is to copy-paste the entire tsconfig.json file and just replace target.

Thanks.

Hi,

Your version is past EOL. You should upgrade to either the latest version or the current LTS at your earliest convenience. Your upgrade path is:

8.9.8 → 9.9 → 10.0 (last step optional)

You may find these resources helpful:

If you have questions about upgrading, feel free to open a new thread for that here.

If your error persists after upgrade, please come back to us!

Hey Colin –

OK - Thank you much. We have plans to upgrade to 9.9 soon— and to be clear, this issue will be fixed once we’ve upgraded?

Also - I’m still curious as to why the override doesn’t work when I use extends? That seems like a separate issue. Seems that at the Sonar Scanner level, the extends option doesn’t seem to be supported.

The sonar-scanner does very little except wrap the binaries coming from the SonarQube server that orchestrates the scan.

Whether your exact issue will be fixed, I’m not sure. And, we’ll be happy to troubleshoot it if you can reproduce it on a supported version.

I was able to reproduce a similar issue to this as well. We have a project that’s currently running on 9.9 LTA using sonar scanner 5.0.1.3006. We also have a tsconfig.json file that extends a base tsconfig.json file that has "lib": ["es2023"]. The current scanner we’re using which supports the LTA we’re using doesn’t support es2023 as a valid lib version, so we tried to override it to ["es2022"]. However, the scanner seems to continue to complain that the lib value is invalid.

Base tsconfig.json:

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "_version": "20.1.0",

  "compilerOptions": {
    "lib": ["es2023"],
    "module": "node16",
    "target": "es2022",

    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "moduleResolution": "node16"
  }
}

Our tsconfig.json:

{
  "extends": "@tsconfig/node20/tsconfig.json",
  "compilerOptions": {
    "allowJs": true,
    "lib": ["es2022"],
    "outDir": "dist",
    "sourceMap": true,
    "useUnknownInCatchVariables": false
  },
  "include": ["src/**/*", "test/**/*"]
}

Scanner error:

ERROR: Error: Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'es2022', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2019.intl', 'es2020.bigint', 'es2020.date', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'es2020.number', 'es2021.promise', 'es2021.string', 'es2021.weakref', 'es2021.intl', 'es2022.array', 'es2022.error', 'es2022.intl', 'es2022.object', 'es2022.sharedmemory', 'es2022.string', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'.  <path_to_file>/node_modules/@tsconfig/node20/tsconfig.json:116
ERROR:     at createProgramOptions (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\lib\services\program\program.js:106:15)
ERROR:     at createProgram (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\lib\services\program\program.js:132:28)
ERROR:     at default_1 (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\lib\routing\on-create-program.js:10:57)
ERROR:     at Layer.handle [as handle_request] (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\node_modules\express\lib\router\layer.js:95:5)
ERROR:     at next (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\node_modules\express\lib\router\route.js:144:13)
ERROR:     at Route.dispatch (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\node_modules\express\lib\router\route.js:114:3)
ERROR:     at Layer.handle [as handle_request] (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\node_modules\express\lib\router\layer.js:95:5)
ERROR:     at <path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\node_modules\express\lib\router\index.js:284:15
ERROR:     at Function.process_params (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\node_modules\express\lib\router\index.js:346:12)
ERROR:     at next (<path_to_file>\.scannerwork\.sonartmp\eslint-bridge-bundle\package\node_modules\express\lib\router\index.js:280:10)
ERROR: Failed to create program: Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'es2022', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2019.intl', 'es2020.bigint', 'es2020.date', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'es2020.number', 'es2021.promise', 'es2021.string', 'es2021.weakref', 'es2021.intl', 'es2022.array', 'es2022.error', 'es2022.intl', 'es2022.object', 'es2022.sharedmemory', 'es2022.string', 'esnext.array', 'esnext.symbol','esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'.  <path_to_file>/node_modules/@tsconfig/node20/tsconfig.json:116

The workaround that we found which works is the same as the one Laurence mentioned above, which was to copy the entire base config file and update it as needed.

Hello Anthony and Luarence,

Thank you for providing the detailed repro steps. I believe that the cause of your issues is using lib “es2023”, which is unavailable in the version of typescript within SQ that you are using. For SQ 9.9, the typescript is v4.9.4. To give you more details. We gather the tsconfigs you have in your repository and provide the tsconfigs to typescript to deduce, which config is responsible for which file. If typescript encounters an unknown lib option at any point, it will throw this exception.

Thats exactly what is happening. Hence, for the scanner to work, you need to make sure that the tsconfigs you have provided are compatible with the installed version.

This can be a solution to have a standalone tsconfig that doesn’t contain any invalid options (even options overridden by extending) and pass it in the property sonar.typescript.tsconfigPath specifically. Or to make it easier, you can upgrade to the latest version of SQ 10.7, which ships with typescript 5.6.2. Then you won’t need to make any changes in your tsconfig’s to allow SQ to work.

Kind regards,
Michal

Hi Michal,

Thanks for following up with investigating this issue.

Just to make sure I understand:

for the scanner to work, you need to make sure that the tsconfigs you have provided are compatible with the installed version.

This can be a solution to have a standalone tsconfig that doesn’t contain any invalid options (even options overridden by extending) and pass it in the property sonar.typescript.tsconfigPath specifically.

Is this to say that SonarQube currently doesn’t support extended tsconfig files, only standalone configurations?

We gather the tsconfigs you have in your repository and provide the tsconfigs to typescript to deduce, which config is responsible for which file.

Does this mean that SonarQube happened to find the base config provided by @tsconfig/node20 and used that as the configuration for scanning, rather than the one that is extended from the base config? In other words, if we are extending, does this mean we must explicitly tell SonarQube which tsconfig file to use?

Thanks for your help in understanding the issue.

Anthony

Hello Anthony,

Is this to say that SonarQube currently doesn’t support extended tsconfig files, only standalone configurations?

No, not at all. What I meant is that the version typescript provided by your SQ needs to support the options you are using. The solution I proposed is about providing a single tsconfig so that you will exactly control, which options typescript will process.

No, SQ didn’t happen to find the base config. SQ found your tsconfig.json file, where you reference it. Then, typescript tries to resolve the provided tsconfig, it finds the extends and tries to parse it as well and then it finds the unknown options. tldr: even if you are extending a tsconfig and a certain option is overridden, typescript will validate it and throw an error.

I hope this answers your questions.

Kind regards,
Michal

Thanks, Michal, for explaining. So to make sure I understand. SQ does support extended tsconfig files, but the base tsconfig file must have configurations supported by SQ; otherwise, SQ will find errors with it. If we run into the case where the base default values are not supported by SQ, then we should put everything into a single, unextended tsconfig file that has all the configurations we want that SQ supports. Is that correct?

Anthony

Exactly!

1 Like