Skip to content

JS-1460 chore: evaluate TypeScript 6.0.1-rc#6626

Open
vdiez wants to merge 11 commits intomasterfrom
codex/ts6-rc-eval
Open

JS-1460 chore: evaluate TypeScript 6.0.1-rc#6626
vdiez wants to merge 11 commits intomasterfrom
codex/ts6-rc-eval

Conversation

@vdiez
Copy link
Contributor

@vdiez vdiez commented Mar 18, 2026

Summary

  • Evaluate SonarJS compatibility with typescript@6.0.1-rc.
  • Keep CI install path working during RC phase (npm ci --legacy-peer-deps) while @typescript-eslint peer ranges still exclude TS6.
  • Stabilize TS6-related CI and test behavior, including ESLint plugin packaging and TS fixtures.
  • Add strictness-compatibility logic during TS program creation to avoid forcing TS6 semantics on projects targeting older TS behavior.

Strictness Policy Evaluation

Policy A: Use TS6 default strictness everywhere (no override)

  • Description: Let TS6 implicit defaults apply in all program creation paths when strict is not set.
  • Outcome: Produced ruling noise/regressions in type-sensitive rules, especially in projects that do not explicitly set strictness and are effectively authored against pre-TS6 behavior.

Policy B: Force non-strict only for synthesized programs (orphan/single-file)

  • Description: Set defaultCompilerOptions.strict = false for synthesized programs (no project tsconfig context).
  • Outcome: Significant FP reduction compared to Policy A; this was a strong first mitigation but did not address tsconfig-backed programs with implicit strictness.

Policy C: Compatibility-aware defaults for tsconfig-backed programs when user TS is <6 and strictness is implicit

  • Description:
    • Detect user TS signal from package.json dependencies.
    • Apply legacy strictness defaults only when version range is definitely <6.
    • Inspect strictness options across tsconfig + extends chain.
    • If strict is explicitly set, do not override.
    • If only sub-options are explicitly set, preserve them and default only missing strictness options.
  • Outcome:
    • Restored CI stability (Linux/Windows build, unit tests, knip green on latest run).
    • Latest ruling differences are improved or neutral on overlapping files versus previous artifact; key observed improvement is S3403 in TypeScript sources (10 -> 3, delta -7), with no regressions on the tracked strictness-sensitive set (S6606, S4325, S1154, S6551, S3757) in overlapping files.

Recommendation for TS6 GA

  • Keep Policy C as the default initially to preserve backward-compatible analysis for projects effectively on TS<6 semantics when strictness is implicit.
  • Always respect explicit user strictness configuration (strict or sub-options), including through extends.
  • After TS6 is GA and ecosystem support is fully aligned, consider an explicit migration path toward TS6-style implicit strictness (opt-in first, then revisit default), gated by ruling quality and FP/FN monitoring.

What I checked

  1. Verified TS6 compile paths in CI and local targeted checks.
  2. Verified strictness behavior with focused tests in packages/jsts/tests/program/options.test.ts.
  3. Verified latest ruling artifact deltas after strictness-policy updates.

This PR remains an evaluation branch to capture TS6 readiness and migration strategy.

@sonar-review-alpha
Copy link

sonar-review-alpha bot commented Mar 18, 2026

Summary

This PR evaluates SonarJS compatibility with TypeScript 6.0.1-rc. The primary change is reimplementing how strictness compiler options are tracked (avoiding a TypeScript internal API that changed in TS6), plus refinements to several rules to work correctly with TS6's type analysis improvements.

What reviewers should know

Start with: Look at packages/jsts/src/program/tsconfig/options.ts first — this contains the main compatibility fix, moving from TypeScript's internal API to maintaining an explicit list of strictness options. The STRICTNESS_COMPILER_OPTIONS constant and related helper functions show what changed.

Key subtleties:

  • Peer dependency workaround: The --legacy-peer-deps additions in .github/workflows/build.yml are necessary because @typescript-eslint@8.57.1 still requires typescript <6.0.0, but we're testing against a pre-release. This flag is expected and intentional.
  • Rule refinements: S1154, S3403, and the new S6551 contain logic improvements tied to TS6, not workarounds for breakage. These reflect better type understanding in TS6.
  • Test fixtures: New TS6-specific fixtures in fixtures/strictness-ts6/ test that the tsconfig handling works correctly across TS5 and TS6.
  • Version regex: The Java test regex change (\([^)]*\)) now matches variable version formats (e.g., 6.0.1-rc) instead of just semver digits.

What to verify: This is an evaluation branch, not a stable release. Check that all tests pass and note any unexpected failures—they'll indicate what still needs compatibility work.


  • Generate Walkthrough
  • Generate Diagram

🗣️ Give feedback

@hashicorp-vault-sonar-prod hashicorp-vault-sonar-prod bot changed the title chore: evaluate TypeScript 6.0.1-rc JS-1460 chore: evaluate TypeScript 6.0.1-rc Mar 18, 2026
@hashicorp-vault-sonar-prod
Copy link

hashicorp-vault-sonar-prod bot commented Mar 18, 2026

JS-1460

@github-actions
Copy link
Contributor

Ruling Report

Code no longer flagged (81 issues)

S1874

TypeScript/scripts/ior.ts:14

    12 | }
    13 | 
>   14 | module Commands {
    15 |     export function dir(obj: IOLog) {
    16 |         obj.filesRead.filter(f => f.result !== undefined).forEach(f => {

TypeScript/scripts/processDiagnosticMessages.ts:155

   153 | }
   154 | 
>  155 | module NameGenerator {
   156 |     export function ensureUniqueness(names: string[], isCaseSensitive: boolean, isFixed?: boolean[]): string[]{
   157 |         if (!isFixed) {

TypeScript/scripts/processDiagnosticMessages.ts:207

   205 | }
   206 | 
>  207 | module Utilities {
   208 |     /// Return a list of all indices where a string occurs.
   209 |     export function collectMatchingIndices(name: string, proposedNames: string[], isCaseSensitive: boolean): number[] {

TypeScript/scripts/word2md.ts:10

     8 | // tool recognizes the specific Word styles used in the TypeScript Language Specification.
     9 | 
>   10 | module Word {
    11 | 
    12 |     export interface Collection<T> {

ace/demo/kitchen-sink/demo.js:459

   457 |         ["div", {}, 
   458 |             ["button", {onclick: function() {
>  459 |                 var info = navigator.platform + "\n" + navigator.userAgent;
   460 |                 if (env.editor.getValue() == info)
   461 |                     return env.editor.undo();

ace/demo/kitchen-sink/docs/typescript.ts:35

    33 | }
    34 | 
>   35 | module Sayings {
    36 |     export class Greeter {
    37 |         greeting: string;

ace/demo/kitchen-sink/docs/typescript.ts:46

    44 |     }
    45 | }
>   46 | module Mankala {
    47 |    export class Features {
    48 |        public turnContinues = false;

ant-design/site/theme/template/Layout/Header/SearchBar.tsx:38

    36 | 
    37 | function isAppleDevice() {
>   38 |   return /(mac|iphone|ipod|ipad)/i.test(navigator.platform);
    39 | }
    40 | 

S4325

TypeScript/src/compiler/binder.ts:445

   443 |                     (node as JSDocTypedefTag).name &&
   444 |                     (node as JSDocTypedefTag).name.kind === SyntaxKind.Identifier &&
>  445 |                     ((node as JSDocTypedefTag).name as Identifier).isInJSDocNamespace;
   446 |                 if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefInJSDocNamespace) {
   447 |                     const exportKind =

TypeScript/src/compiler/binder.ts:1148

  1146 |                 }
  1147 |                 const preCaseLabel = createBranchLabel();
> 1148 |                 addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow, <SwitchStatement>node.parent, clauseStart, i + 1));
  1149 |                 addAntecedent(preCaseLabel, fallthroughFlow);
  1150 |                 currentFlow = finishFlowLabel(preCaseLabel);

...and 71 more

New issues flagged (74 issues)

S3403

Ghost/core/client/app/utils/ed-image-manager.js:38

    36 |         // if the () are missing entirely, which is valid, [2] will be undefined and we'll need to treat this case
    37 |         // a little differently
>   38 |         if (images[index][2] === undefined) {
    39 |             replacement.needsParens = true;
    40 |             replacement.start = content.indexOf(']', images[index].index) + 1;

angular.js/src/ng/compile.js:2231

  2229 | 
  2230 |         if (writeAttr !== false) {
> 2231 |           if (value === null || isUndefined(value)) {
  2232 |             this.$$element.removeAttr(attrName);
  2233 |           } else {

angular.js/src/ng/location.js:582

   580 |         break;
   581 |       default:
>  582 |         if (isUndefined(paramValue) || paramValue === null) {
   583 |           delete this.$$search[search];
   584 |         } else {

angular.js/src/ngAnimate/shared.js:27

    25 | // therefore there is no reason to test anymore for other vendor prefixes:
    26 | // http://caniuse.com/#search=transition
>   27 | if ((window.ontransitionend === undefined) && (window.onwebkittransitionend !== undefined)) {
    28 |   CSS_PREFIX = '-webkit-';
    29 |   TRANSITION_PROP = 'WebkitTransition';

angular.js/src/ngAnimate/shared.js:27

    25 | // therefore there is no reason to test anymore for other vendor prefixes:
    26 | // http://caniuse.com/#search=transition
>   27 | if ((window.ontransitionend === undefined) && (window.onwebkittransitionend !== undefined)) {
    28 |   CSS_PREFIX = '-webkit-';
    29 |   TRANSITION_PROP = 'WebkitTransition';

angular.js/src/ngAnimate/shared.js:36

    34 | }
    35 | 
>   36 | if ((window.onanimationend === undefined) && (window.onwebkitanimationend !== undefined)) {
    37 |   CSS_PREFIX = '-webkit-';
    38 |   ANIMATION_PROP = 'WebkitAnimation';

angular.js/src/ngAnimate/shared.js:36

    34 | }
    35 | 
>   36 | if ((window.onanimationend === undefined) && (window.onwebkitanimationend !== undefined)) {
    37 |   CSS_PREFIX = '-webkit-';
    38 |   ANIMATION_PROP = 'WebkitAnimation';

angular.js/src/ngMock/angular-mocks.js:1986

  1984 |     if (skip >= responses.length) throw new Error('No pending request to flush !');
  1985 | 
> 1986 |     if (angular.isDefined(count) && count !== null) {
  1987 |       while (count--) {
  1988 |         var part = responses.splice(skip, 1);

angular.js/src/ngSanitize/sanitize.js:509

   507 |    */
   508 |   function htmlParserImpl(html, handler) {
>  509 |     if (html === null || html === undefined) {
   510 |       html = '';
   511 |     } else if (typeof html !== 'string') {

angular.js/src/ngSanitize/sanitize.js:509

   507 |    */
   508 |   function htmlParserImpl(html, handler) {
>  509 |     if (html === null || html === undefined) {
   510 |       html = '';
   511 |     } else if (typeof html !== 'string') {

...and 64 more

📋 View full report

Code no longer flagged (81)

S1874

S4325

S6551

S6582

S7728

S3757

S2301

S6544

S3760

New issues flagged (74)

S3403

S7755

S6606

S4325

S6594

S7728

S1874

S3782


Ruling needs updating. A fix PR has been created: #6627

Please review and merge it into your branch.

@vdiez vdiez force-pushed the codex/ts6-rc-eval branch from eecf520 to 75a6a1c Compare March 18, 2026 10:52
@vdiez vdiez changed the base branch from codex/js-1354-css-s2260-special-case to master March 18, 2026 10:53
Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conclusion: Minimal, correctly scoped evaluation PR. The --legacy-peer-deps flag is applied exactly where it needs to be — the cache-population step — and the Windows job inherits the same steps via the YAML anchor alias, so both platforms are covered. All downstream jobs restore the pre-built node_modules from cache and never call npm ci themselves, so no other CI steps need updating.

🗣️ Give feedback

@vdiez
Copy link
Contributor Author

vdiez commented Mar 18, 2026

Follow-up on latest ruling evaluation after pinning synthesized compiler defaults to strict: false.

Scope of this estimate:

  • Compared latest ruling-differences artifact (5987302279, run 23249204802) against the previous baseline (5984169036).
  • Focused on the TS6-sensitive changed-rule set we reviewed.
  • As discussed, S1874 is excluded from FP estimation (deprecation diagnostics are strongly tied to TS/ecmascript lib evolution).

FP estimate (excluding S1874):

  • Strict FP estimate: 3.17% (94 / 2966)
  • FP + 50% of mixed cases: 3.89%
  • Worst-case (all mixed treated as FP): 4.62%

Main residual FP drivers:

  • S3403: assignability-based strict comparison checks can still flag defensive null/undefined idioms.
  • S1154: broad StringLike expression-statement heuristic.
  • S6551: generic/dynamic stringification heuristics.
  • S3757: occasional coarse typing around arithmetic/object flows.

Conclusion:

  • With path-1 (strict: false for synthesized programs), the ruling changes now look mostly acceptable and significantly cleaner than before.
  • I’m comfortable merging this TS6 upgrade once TS6 is GA, provided CI remains green and we keep follow-up cleanup under JS-1469 for intentional strict-by-default adoption and targeted rule tuning (S3403, S1154, S6551, S3757).

Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conclusion: One targeted question before approving — the new isTestLikeFile function may belong in shared helpers rather than being a second, diverging implementation of a concept that already exists.

🗣️ Give feedback

Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! ✅

🗣️ Give feedback

Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! ✅

🗣️ Give feedback

Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! ✅

🗣️ Give feedback

@sonarqube-next
Copy link

Quality Gate failed Quality Gate failed

Failed conditions
3 New issues

See analysis details on SonarQube

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE SonarQube for IDE

Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! ✅

🗣️ Give feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant