Skip to content

JS-2011 [DO NOT MERGE] Add context-aware JS rules CSV generator#7475

Draft
nathsou wants to merge 3 commits into
masterfrom
codex/context-aware-js-rules-csv
Draft

JS-2011 [DO NOT MERGE] Add context-aware JS rules CSV generator#7475
nathsou wants to merge 3 commits into
masterfrom
codex/context-aware-js-rules-csv

Conversation

@nathsou

@nathsou nathsou commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a TypeScript tool that lists JS rules gated by dependency, ECMA version, or module type metadata
  • check in the generated CSV output next to the script for easy review and reuse

Test plan

  • tmp_csv=$(mktemp) && npx tsx tools/list-context-aware-js-rules.ts > "$tmp_csv" && diff -u "$tmp_csv" tools/list-context-aware-js-rules.csv
  • npx -p prettier prettier --check --no-config --parser typescript --single-quote --trailing-comma all --arrow-parens avoid --print-width 100 --end-of-line lf tools/list-context-aware-js-rules.ts

@hashicorp-vault-sonar-prod hashicorp-vault-sonar-prod Bot changed the title Add context-aware JS rules CSV generator JS-2011 Add context-aware JS rules CSV generator Jul 7, 2026
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Jul 7, 2026

Copy link
Copy Markdown

JS-2011

@nathsou nathsou marked this pull request as draft July 7, 2026 07:39
@nathsou nathsou self-assigned this Jul 7, 2026
@nathsou nathsou changed the title JS-2011 Add context-aware JS rules CSV generator JS-2011 [DO NOT MERGE] Add context-aware JS rules CSV generator Jul 7, 2026
Comment on lines +74 to +77
const requiredDependency =
(await readLocalRequiredDependencyOverride(sonarKey)) ??
metadata.extra?.requiredDependency ??
[];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Edge Case: Empty local requiredDependency array shadows rspec fallback

In listContextAwareJsRules, requiredDependency is computed as (await readLocalRequiredDependencyOverride(sonarKey)) ?? metadata.extra?.requiredDependency ?? []. readLocalRequiredDependencyOverride returns undefined only when the requiredDependency declaration is absent from meta.ts. If a meta.ts contains export const requiredDependency = [] as const; (declaration present but no string literals), the function returns an empty array []. Because [] ?? x yields [] (nullish coalescing only falls back on null/undefined), the rspec metadata.extra.requiredDependency fallback is silently skipped, and such a rule would then be dropped from the CSV if it has no ecma/module requirement. If empty declarations are never expected this is harmless, but the intent is ambiguous. Consider returning undefined when the parsed dependency list is empty so the rspec value can still take effect.

Fall back to rspec metadata when the local declaration parses to an empty list.:

const dependencies: string[] = [];
for (const literal of match.groups.values.matchAll(stringLiteralPattern)) {
  dependencies.push(literal[1] ?? literal[2]);
}
return dependencies.length > 0 ? dependencies : undefined;
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +61 to +63
const requiredDependencyPattern =
/export const requiredDependency = \[(?<values>[\s\S]*?)\](?:\s+as const)?;/;
const stringLiteralPattern = /'([^']+)'|"([^"]+)"/g;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Quality: Regex-based parsing of meta.ts is brittle and fails silently

readLocalRequiredDependencyOverride parses requiredDependency out of TypeScript source with requiredDependencyPattern/stringLiteralPattern regexes rather than importing the module. This works for the current uniform style (export const requiredDependency = ['x'] as const;), but it will silently return undefined/wrong values if the declaration is ever written differently (e.g. split across differently-formatted lines, uses template literals, references imported constants, or has a trailing comment inside the array). Since a miss just omits a dependency rather than erroring, drift between the tool and the actual meta.ts files would go unnoticed. Consider dynamically importing the meta.ts module (via tsx, which is already used to run the tool) and reading the exported requiredDependency value directly, which is exact and robust to formatting.

Was this helpful? React with 👍 / 👎

Comment on lines +65 to +79
export async function listContextAwareJsRules(): Promise<ContextAwareJsRule[]> {
const sonarKeys = await listSonarRuleKeys();
const rules = await Promise.all(
sonarKeys.map(async sonarKey => {
const metadata = await readRspecRuleMetadata(sonarKey);
if (!metadata.compatibleLanguages.includes('js')) {
return undefined;
}

const requiredDependency =
(await readLocalRequiredDependencyOverride(sonarKey)) ??
metadata.extra?.requiredDependency ??
[];
const requiredEcmaVersion = getRequiredEcmaVersion(metadata.tags);
const requiredModuleType = getRequiredModuleType(metadata.tags);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Performance: Unbounded concurrent file reads across all rule directories

listContextAwareJsRules maps every rule key through Promise.all with no concurrency cap. With ~540 rule directories, up to ~540 metadata reads (plus ~540 meta.ts reads for js-compatible rules) are issued simultaneously. On systems with a low open-file-descriptor limit this risks EMFILE: too many open files and makes failures non-deterministic. This is a dev-only tool so impact is low, but batching the reads (e.g. via a small concurrency limiter or processing in chunks) would make the tool more robust.

Was this helpful? React with 👍 / 👎

@datadog-sonarsource

datadog-sonarsource Bot commented Jul 7, 2026

Copy link
Copy Markdown

Pipelines

⚠️ Warnings

🚦 1 Pipeline job failed

Build | Knip   View in Datadog   GitHub Actions

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 9b9da1c | Docs | Give us feedback!

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Ruling Report

Code no longer flagged (2 issues)

S2699

http/test/ConnectionMock.spec.js:256

   254 | 
   255 | 
>  256 |     it('should require code to be a number', function() {
   257 |     });
   258 | 

http/test/ConnectionMock.spec.js:260

   258 | 
   259 | 
>  260 |     it('should require body to be a string', function() {
   261 | 
   262 |     });

@gitar-bot

gitar-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown
CI failed: The build is failing due to a malformed XML test report generated by the new rules script and a tooling error where Knip flags the same new script as an unused file.

Overview

Two distinct failures are blocking the CI pipeline, both directly related to the newly introduced tools/list-context-aware-js-rules.ts script. The SonarQube analysis is failing due to malformed XML output, and the project's static analysis tool (Knip) is flagging the new script as an unused file.

Failures

Malformed Generic Test Execution Report (confidence: high)

  • Type: build
  • Affected jobs: 85563739860
  • Related to change: yes
  • Root cause: The script responsible for generating coverage/js/test-report.xml is producing invalid XML, causing the SonarQube Generic Test Execution sensor to crash during the analysis phase.
  • Suggested fix: Validate the XML structure of the generated report. Ensure it adheres to the SonarQube Generic Test Execution schema, specifically checking for proper tag closure, escaping of special characters, and correct file structure.

Knip Unused File Detection (confidence: high)

  • Type: tooling
  • Affected jobs: 85562395977, 85657762702
  • Related to change: yes
  • Root cause: The new file tools/list-context-aware-js-rules.ts is not referenced by any other part of the project, triggering a failure in the knip static analysis check.
  • Suggested fix: If the script is a standalone utility, add it to the ignore patterns in knip.json or knip.config.ts. If it is intended to be used within the build, ensure it is properly integrated or imported.

Summary

  • Change-related failures: 2 (Malformed XML report and Knip unused file flagging).
  • Infrastructure/flaky failures: 0.
  • Recommended action: Update the script to produce valid XML format and adjust the Knip configuration to ignore the new tool script.
Code Review 👍 Approved with suggestions 0 resolved / 3 findings

Adds a TypeScript tool to generate a CSV of context-aware JS rules. Ensure the implementation handles potential failures by replacing brittle regex parsing with module imports and addressing unbounded concurrency in file reads.

💡 Edge Case: Empty local requiredDependency array shadows rspec fallback

📄 tools/list-context-aware-js-rules.ts:74-77 📄 tools/list-context-aware-js-rules.ts:144-158

In listContextAwareJsRules, requiredDependency is computed as (await readLocalRequiredDependencyOverride(sonarKey)) ?? metadata.extra?.requiredDependency ?? []. readLocalRequiredDependencyOverride returns undefined only when the requiredDependency declaration is absent from meta.ts. If a meta.ts contains export const requiredDependency = [] as const; (declaration present but no string literals), the function returns an empty array []. Because [] ?? x yields [] (nullish coalescing only falls back on null/undefined), the rspec metadata.extra.requiredDependency fallback is silently skipped, and such a rule would then be dropped from the CSV if it has no ecma/module requirement. If empty declarations are never expected this is harmless, but the intent is ambiguous. Consider returning undefined when the parsed dependency list is empty so the rspec value can still take effect.

Fall back to rspec metadata when the local declaration parses to an empty list.
const dependencies: string[] = [];
for (const literal of match.groups.values.matchAll(stringLiteralPattern)) {
  dependencies.push(literal[1] ?? literal[2]);
}
return dependencies.length > 0 ? dependencies : undefined;
💡 Quality: Regex-based parsing of meta.ts is brittle and fails silently

📄 tools/list-context-aware-js-rules.ts:61-63 📄 tools/list-context-aware-js-rules.ts:144-158

readLocalRequiredDependencyOverride parses requiredDependency out of TypeScript source with requiredDependencyPattern/stringLiteralPattern regexes rather than importing the module. This works for the current uniform style (export const requiredDependency = ['x'] as const;), but it will silently return undefined/wrong values if the declaration is ever written differently (e.g. split across differently-formatted lines, uses template literals, references imported constants, or has a trailing comment inside the array). Since a miss just omits a dependency rather than erroring, drift between the tool and the actual meta.ts files would go unnoticed. Consider dynamically importing the meta.ts module (via tsx, which is already used to run the tool) and reading the exported requiredDependency value directly, which is exact and robust to formatting.

💡 Performance: Unbounded concurrent file reads across all rule directories

📄 tools/list-context-aware-js-rules.ts:65-79

listContextAwareJsRules maps every rule key through Promise.all with no concurrency cap. With ~540 rule directories, up to ~540 metadata reads (plus ~540 meta.ts reads for js-compatible rules) are issued simultaneously. On systems with a low open-file-descriptor limit this risks EMFILE: too many open files and makes failures non-deterministic. This is a dev-only tool so impact is low, but batching the reads (e.g. via a small concurrency limiter or processing in chunks) would make the tool more robust.

🤖 Prompt for agents
Code Review: Adds a TypeScript tool to generate a CSV of context-aware JS rules. Ensure the implementation handles potential failures by replacing brittle regex parsing with module imports and addressing unbounded concurrency in file reads.

1. 💡 Edge Case: Empty local requiredDependency array shadows rspec fallback
   Files: tools/list-context-aware-js-rules.ts:74-77, tools/list-context-aware-js-rules.ts:144-158

   In `listContextAwareJsRules`, `requiredDependency` is computed as `(await readLocalRequiredDependencyOverride(sonarKey)) ?? metadata.extra?.requiredDependency ?? []`. `readLocalRequiredDependencyOverride` returns `undefined` only when the `requiredDependency` declaration is absent from `meta.ts`. If a `meta.ts` contains `export const requiredDependency = [] as const;` (declaration present but no string literals), the function returns an empty array `[]`. Because `[] ?? x` yields `[]` (nullish coalescing only falls back on null/undefined), the rspec `metadata.extra.requiredDependency` fallback is silently skipped, and such a rule would then be dropped from the CSV if it has no ecma/module requirement. If empty declarations are never expected this is harmless, but the intent is ambiguous. Consider returning `undefined` when the parsed dependency list is empty so the rspec value can still take effect.

   Fix (Fall back to rspec metadata when the local declaration parses to an empty list.):
   const dependencies: string[] = [];
   for (const literal of match.groups.values.matchAll(stringLiteralPattern)) {
     dependencies.push(literal[1] ?? literal[2]);
   }
   return dependencies.length > 0 ? dependencies : undefined;

2. 💡 Quality: Regex-based parsing of meta.ts is brittle and fails silently
   Files: tools/list-context-aware-js-rules.ts:61-63, tools/list-context-aware-js-rules.ts:144-158

   `readLocalRequiredDependencyOverride` parses `requiredDependency` out of TypeScript source with `requiredDependencyPattern`/`stringLiteralPattern` regexes rather than importing the module. This works for the current uniform style (`export const requiredDependency = ['x'] as const;`), but it will silently return `undefined`/wrong values if the declaration is ever written differently (e.g. split across differently-formatted lines, uses template literals, references imported constants, or has a trailing comment inside the array). Since a miss just omits a dependency rather than erroring, drift between the tool and the actual `meta.ts` files would go unnoticed. Consider dynamically importing the `meta.ts` module (via tsx, which is already used to run the tool) and reading the exported `requiredDependency` value directly, which is exact and robust to formatting.

3. 💡 Performance: Unbounded concurrent file reads across all rule directories
   Files: tools/list-context-aware-js-rules.ts:65-79

   `listContextAwareJsRules` maps every rule key through `Promise.all` with no concurrency cap. With ~540 rule directories, up to ~540 metadata reads (plus ~540 `meta.ts` reads for js-compatible rules) are issued simultaneously. On systems with a low open-file-descriptor limit this risks `EMFILE: too many open files` and makes failures non-deterministic. This is a dev-only tool so impact is low, but batching the reads (e.g. via a small concurrency limiter or processing in chunks) would make the tool more robust.

Tip

Comment Gitar fix CI or enable auto-apply: gitar auto-apply:on

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

sonarqube-next Bot commented Jul 7, 2026

Copy link
Copy Markdown

Quality Gate passed Quality Gate passed

Issues
0 New issues
0 Fixed issues
0 Accepted issues

Measures
0 Security Hotspots
0 Dependency risks
No data about Coverage
No data about Duplication

See analysis details on SonarQube

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