Skip to content

Close guideline coverage gaps for JavaScript and TypeScript - #1

Merged
piquark6046 merged 4 commits into
mainfrom
claude/codeguidelines-ts-coverage-jhk8kx
Sep 28, 2026
Merged

piquark6046 merged 4 commits into
mainfrom
claude/codeguidelines-ts-coverage-jhk8kx

Conversation

@piquark6046

Copy link
Copy Markdown
Member

Summary

Every numbered clause of the pinned AdguardTeam/CodeGuidelines JavaScript guide already had a catalog row, but the rows were only checked for existence. Running each clause's good and bad examples through the complete preset showed three kinds of problem:

  • Clauses marked enforced whose bad examples passed (e.g. 10.10/10.11 import grouping and order, 17.1, 18.6, 5.2).
  • Settings that rejected the guide's own good examples (e.g. two-space JSX indentation against 18.1).
  • TypeScript files running pinned JavaScript rules that misreport TypeScript syntax: false positives on overloads, declaration merging, and new Array<string>(); missed enum/tuple commas, union spacing, and type-alias semicolons.

The guide repository is not modified.

Policies and catalog

  • Each clause now has a disposition for the default compatibility policy (the sample .eslintrc.js wins) and for the opt-in guideline policy (prose wins). partial marks clauses whose rules enforce only part of the requirement.
  • The guideline policy now resolves every documented prose/sample conflict, not just prefer-default-export. Clause 10.10's grouping supports both readings of the guide via importGroups: 'example' | 'prose'.
  • New guideline-only rules cover checks the guide requires but no upstream rule provides:
    • ag/no-multiline-string-concat, ag/multiline-condition-layout, ag/constant-name
    • ag/prefer-array-from, ag/prefer-template-over-join, ag/no-arguments, ag/docblock-spacing
    • require-docblock line-comment runs
    • prototype changes through calls (Object.assign/defineProperty on a prototype, setPrototypeOf, inherits)
  • Project conventions that the guide does not require move from the base preset to an opt-in profile: 'adguard-projects', with accurate provenance:
    • stricter JSDoc rules, MV2/MV3 import restrictions, .pcss imports, import-newlines, boundaries, logger context
    • @typescript-eslint rules, plus member-delimiter-style

TypeScript

  • In TypeScript files, a generated equivalence table swaps pinned rules for TypeScript-aware implementations of the same rules and options:
    • native no-dupe-class-members, no-array-constructor, default-param-last, no-use-before-define, class-methods-use-this
    • Stylistic comma-dangle (enums/tuples/generics), comma-spacing, key-spacing, semi, space-infix-ops, object-curly-spacing, space-before-blocks, lines-between-class-members, lines-around-comment, brace-style, keyword-spacing, space-before-function-paren
    • a merge-aware ag-ts/no-redeclare
  • no-accessors and unknown-catch cover TypeScript forms (abstract, signature, and auto-accessors; catch bindings of any shape; any unions).
  • ag-oxlint-config --check-tsconfig verifies clauses 26.1/26.2, resolving extends the way TypeScript does.

Fix

  • import-newlines/enforce autofix produced invalid import type { type A } and dropped inline type modifiers. The TypeScript port read the declaration's importKind instead of the specifier's; the reviewed vendor patch now matches upstream.

Breaking changes

  • Rules moved to profile: 'adguard-projects'; type-aware consistent-type-exports now also requires that profile. The repository's own lint config extends the new profile preset.

Test plan

  • pnpm run check (source policy, build, typecheck, self-lint, catalog/snapshot checks, coverage): 45,381 tests, coverage 98.74% statements / 95.54% branches.
  • tests/clauses.test.ts:
    • Every enforced clause has an executed bad example under each policy.
    • Every partial/overridden label is backed by an example that demonstrates the gap.
    • Both 10.10 interpretations are tested.
  • tests/typescript-preset.test.ts: an idiomatic TypeScript corpus passes the full preset under both policies, and each replacement reports TypeScript-only violations.
  • Independent clause-by-clause audit plus read-only lint runs on copies of AdguardBrowserExtension, AdGuardVPNExtension, and Scriptlets.
    • TypeScript replacements removed 21 false positives there.
    • Guideline-policy output was sampled for over-reach, and the justified narrowings were applied.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MCeDV2VhbUtLyAP9XRG1zL


Generated by Claude Code

Every numbered clause of the pinned guide had a catalog row, but several
rows claimed enforcement that the resolved settings did not provide, the
guideline policy reversed only one prose/sample conflict, and TypeScript
files ran pinned JavaScript rules that misreport TypeScript syntax.

Catalog: record a disposition per policy (compatibility and guideline),
add a `partial` enforcement level, scope mappings to the base preset,
the guideline policy, or an opt-in profile, and record the TypeScript
implementation of each replaced rule. Dispositions for 5.2, 10.4, 10.10,
10.11, 16.1, 17.1, 18.1, 18.6, and 7.2 now match actual behavior.

Guideline policy: enforce the prose for clauses 5.2, 6.2/18.13, 10.1,
10.2, 10.6, 10.10 (selectable `importGroups: example | prose`), 10.11,
16.1, 17.1, 17.2, 18.1 (JSX), 18.6, 18.7, 22.1, and 22.7. Add rules
no-multiline-string-concat, multiline-condition-layout, constant-name,
and a lineCommentRuns option for require-docblock.

TypeScript: replace pinned rules that report valid TypeScript or ignore
TypeScript syntax with TypeScript-aware implementations of the same rules
and options (native no-dupe-class-members, no-array-constructor,
default-param-last, no-use-before-define; Stylistic comma-dangle,
comma-spacing, key-spacing, lines-between-class-members,
lines-around-comment, object-curly-spacing, semi, space-before-blocks,
space-infix-ops; merge-aware ag-ts/no-redeclare). no-accessors covers
abstract, signature, and auto-accessors; unknown-catch covers every
catch binding pattern. `--check-tsconfig` verifies clauses 26.1/26.2.

Profile: move AdGuard project conventions that the guide does not
require (stricter JSDoc, MV2/MV3 imports, import-newlines, boundaries,
logger context, @typescript-eslint rules) from the base preset into the
opt-in `adguard-projects` profile with accurate provenance.

Tests: run every enforced clause's good and bad examples through the
complete preset for both policies, require partial and overridden
dispositions to be demonstrated, and require an idiomatic TypeScript
corpus to pass the full TypeScript preset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCeDV2VhbUtLyAP9XRG1zL
The TypeScript port of eslint-plugin-import-newlines 1.4.0 mistranslated
the fixer's type check. Upstream lib/enforce.js reads
`currentNode.imported.parent.importKind`; the parent of the imported
name is the ImportSpecifier, so only an inline `type` modifier is
reprinted. The port read `currentNode.parent.importKind`, the
ImportDeclaration's kind, instead. Every specifier of `import type { ... }`
was printed as `type X` (TS2206: the 'type' modifier cannot be used on a
named import when 'import type' is used), and inline modifiers in
`import { type A, B }` were dropped.

This is not an Oxc AST difference. Oxc and @typescript-eslint/parser
both set importKind 'type' on the declaration for `import type { A }`
and 'value' on its specifiers, and 'type' only on specifiers that carry
an inline modifier. With the upstream rule and @typescript-eslint/parser
the fix output is valid. An adapter in newlines.ts would have had to
fake specifier parents to hide a port bug, so the reviewed patch in
scripts/vendor-patches/import-newlines/src/enforce.ts.json now reads the
imported name's parent, as upstream does. The vendored file is
reproduced from the pinned upstream source and that patch, and
vendor/manifest.json was updated with `pnpm run snapshots:record`.

A new CLI test runs `oxlint --fix` with only ag-newlines/enforce on
type-only, aliased, inline, default-plus-inline, and joined imports and on
`export type` forms. It checks the exact fixed text and requires a second
run to report no diagnostics, which include Oxc's TS1363 and TS2206
parser errors. The members stay unindented, as upstream emits them; the
indent rule owns their indentation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCeDV2VhbUtLyAP9XRG1zL
An independent audit ran every good and bad example of the guide under
both policies in JavaScript and TypeScript, and linted three AdGuard
codebases with the guideline policy. It found clauses marked enforced
whose examples passed, rules that rejected the guide's own good
examples, and TypeScript syntax that pinned rules still ignored.

Dispositions: mark 3.3, 6.3, 7.4, 7.6, 7.10, 7.12, 9.1, 9.2, 14.1,
17.3, 21.2, 21.3, and 22.2 partial where the configured rules check only
part of the clause, 18.13 overridden under compatibility, and explain
6.2, 18.14, 19.2, and 21.4. Rule lists now match what enforces them.

Guideline policy: add ag/prefer-array-from (4.3),
ag/prefer-template-over-join (6.3), ag/no-arguments (7.4), and
ag/docblock-spacing (17.3); report prototype changes through calls
(9.1, 9.2); drop Airbnb's exemptions from no-param-reassign (7.10) and
eqeqeq (14.1); enable no-implicit-coercion (21.2, 21.3), inline
duplicate-import merging (10.4), and TypeScript no-require-imports
(10.1); turn off func-names, which rejects the guide's examples. Keep
built-in imports first in the `example` import grouping and put aliases
after packages; allow braced cases back to back, TODO/FIXME comment
runs, and tool directives next to code; report multiline conditions
only when their operands span lines.

Both policies: no-default-side-effects reports `delete`; require-docblock
keeps `/*!` banners and directive blocks; enum-name accepts V1-style
names; unknown-catch reports unions with `any`. TypeScript files use
Stylistic brace-style, keyword-spacing, and space-before-function-paren
and native class-methods-use-this that exempts overrides. The
adguard-projects profile adds member-delimiter-style.

--check-tsconfig resolves `extends` as TypeScript does (existing files
as written, package tsconfig fields, never `main`) and reports disabled
strict-family options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCeDV2VhbUtLyAP9XRG1zL
Copilot AI lite review requested due to automatic review settings September 28, 2026 06:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Moderate issues remain in prototype-call operand validation and TypeScript declaration-merge handling.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

This PR closes JavaScript and TypeScript guideline coverage gaps with policy/profile layering, TypeScript-aware linting, compiler checks, custom rules, and an import-fixer correction.

Changes:

  • Adds compatibility/guideline policies and the adguard-projects profile.
  • Adds TypeScript rule replacements, declaration handling, and tsconfig validation.
  • Expands tests, fixtures, documentation, and import-fix behavior.
File Description
vendor/​manifest.json Updates vendor hashes.
vendor/​import-newlines/​src/​enforce.ts Corrects TypeScript import handling.
tests/​typescript-syntax.test.ts Tests TypeScript syntax coverage.
tests/​typescript-rules.test.ts Tests TypeScript-aware rules.
tests/​typescript-preset.test.ts Tests the complete TypeScript preset.
tests/​integration.test.ts Tests policy and profile APIs.
tests/​gaps.test.ts Tests scoped rule coverage.
tests/​gap-cases.ts Adds policy and profile cases.
tests/​fixtures/​typescript/​types.ts Adds TypeScript syntax fixtures.
tests/​fixtures/​typescript/​square.ts Adds class fixtures.
tests/​fixtures/​typescript/​overloads.ts Adds overload fixtures.
tests/​fixtures/​typescript/​namespace-merge.ts Adds namespace merge fixtures.
tests/​fixtures/​typescript/​merging.ts Adds declaration merge fixtures.
tests/​fixtures/​typescript/​imports.ts Adds TypeScript import fixtures.
tests/​fixtures/​typescript/​declarations.d.ts Adds ambient declaration fixtures.
tests/​fixtures/​typescript/​component.tsx Adds TSX fixtures.
tests/​fixtures/​typescript/​classes.ts Adds abstract-class fixtures.
tests/​custom.test.ts Tests configurable custom rules.
tests/​custom-cases.ts Adds custom-rule edge cases.
tests/​consumer.test.ts Tests packaged presets and consumers.
tests/​config-cli.test.ts Tests new CLI options.
tests/​compiler.test.ts Tests tsconfig validation.
tests/​clauses.test.ts Tests clause examples under both policies.
tests/​catalog.test.ts Validates scoped catalog mappings.
tests/​behavior.test.ts Tests import fixes and typed linting.
scripts/​write-configs.ts Generates project-profile presets.
scripts/​vendor-patches/​import-newlines/​src/​enforce.ts.json Records the vendor patch.
scripts/​source-policy.ts Registers permitted external loaders.
scripts/​generate.ts Generates policies, profiles, and mappings.
README.md Documents policies and TypeScript support.
packages/​rule-catalog/​src/​index.ts Extends catalog types.
packages/​rule-catalog/​README.md Documents catalog layers.
packages/​oxlint-plugin/​src/​typescript.ts Adds TypeScript-aware redeclaration handling.
packages/​oxlint-plugin/​src/​index.ts Adds custom guideline rules.
packages/​oxlint-plugin/​src/​helpers.ts Adds shared AST and mutation helpers.
packages/​oxlint-plugin/​README.md Documents plugin rules.
packages/​oxlint-plugin/​package.json Exposes the TypeScript plugin.
packages/​oxlint-config/​src/​index.ts Implements policy and profile configuration.
packages/​oxlint-config/​src/​compiler.ts Adds tsconfig checking.
packages/​oxlint-config/​src/​cli.ts Adds policy, profile, and tsconfig options.
packages/​oxlint-config/​README.md Documents configuration options.
packages/​oxlint-config/​package.json Exposes project-profile presets.
docs/​conformance.md Documents TypeScript rule substitutions.
.oxlintrc.json Enables the project profile.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/oxlint-plugin/src/typescript.ts Outdated
… accepts

ag-ts/no-redeclare suppressed reports for every declaration merge that
TypeScript permits, including enum + enum, type alias + value, and
interface + value. The TypeScript version of the rule,
@typescript-eslint/no-redeclare (used by AdGuard projects through
airbnb-typescript), accepts fewer merges with its default
ignoreDeclarationMerge: interfaces, namespaces, one class with
interfaces and namespaces, one function implementation with namespaces,
and one enum with namespaces. It reports the rest, although TypeScript
itself allows enum and type/value merges.

Match that set so the TypeScript replacement enforces the same rule as
its reference implementation. Overload signatures and ambient function
declarations still merge with their implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCeDV2VhbUtLyAP9XRG1zL
@piquark6046
piquark6046 merged commit 5d53175 into main Sep 28, 2026
18 checks passed
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.

3 participants