Skip to content

Support defining a linter ruleset in a yaml file - #11851

Open
Timothee Guerin (timotheeguerin) wants to merge 5 commits into
microsoft:mainfrom
timotheeguerin:linter-ruleset-file
Open

Support defining a linter ruleset in a yaml file#11851
Timothee Guerin (timotheeguerin) wants to merge 5 commits into
microsoft:mainfrom
timotheeguerin:linter-ruleset-file

Conversation

@timotheeguerin

Copy link
Copy Markdown
Member

Today the only way to share a set of linter rules is to ship them as a ruleset inside a library. That means a repo like azure-rest-api-specs cannot onboard or disable a rule without waiting for a new release of the package that owns it, and it cannot combine rules coming from several sources into one reusable list.

This lets a ruleset live in a plain yaml file, referenced from linter.extends with a file: prefix.

# tspconfig.yaml
linter:
  extends:
    - "file:../../typespec-rulesets/data-plane.yaml"
# typespec-rulesets/data-plane.yaml
extends:
  - "@typespec/best-practices/recommended"
  - "file:./shared/http.yaml"
enable:
  "@typespec/best-practices/new-rule": true
disable:
  "@typespec/best-practices/foo": "This rule is too strict for this repository"

The file has the exact same shape as the linter config, so ruleset files compose freely with each other and with library rulesets. Relative paths always resolve against the file that declares them — a file: in tspconfig.yaml is relative to the config (including when that config was reached through extends:), and a file: inside a ruleset is relative to that ruleset. Circular references report a diagnostic instead of hanging, and schema violations point at the offending line:

shared/bad.yaml:1:1 - error invalid-schema: Schema violation: must NOT have additional properties (/)
  additionalProperty: enabled
> 1 | enabled:
    | ^^^^^^^

This also opens the door to versioned rulesets: add a new file whenever a rule is introduced, and repos opt in by pointing at the newer one.

Fixes #3011

Known follow-up

The language server does not watch ruleset files yet, so editing one does not retrigger a recompile until the config or a source file changes.

Support referencing a standalone yaml ruleset from `linter.extends` with
the `file:` prefix. Relative paths resolve against the file declaring
them, ruleset files can extend other files and library rulesets, and
circular references are reported.

Fixes microsoft#3011
@microsoft-github-policy-service microsoft-github-policy-service Bot added compiler:core Issues for @typespec/compiler meta:website TypeSpec.io updates labels Sep 3, 2026
@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/compiler@11851

commit: 7eddd8c

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/compiler
Show changes

@typespec/compiler - feature ✏️

Add support for defining a linter ruleset in a standalone yaml file and referencing it with the file: prefix in linter.extends. This lets a repository share and version a set of linter rules without depending on a library release.,> ,> yaml,> # tspconfig.yaml,> linter:,> extends:,> - "file:../common-rules.yaml",> ,> ,> yaml,> # common-rules.yaml,> extends:,> - "@typespec/best-practices/recommended",> enable:,> "@typespec/best-practices/new-rule": true,> disable:,> "@typespec/best-practices/foo": "This rule is too strict for this repository",>

@azure-sdk-automation

azure-sdk-automation Bot commented Sep 3, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation is covered by targeted tests and includes docs/changeset; only minor test-description grammar nits remain.

Pull request overview

Adds support in @typespec/compiler for extending linter rulesets from standalone YAML files via linter.extends entries prefixed with file:, enabling repos to share/version rulesets without requiring library releases.

Changes:

  • Introduces file: ruleset resolution/loading (including nested and circular-reference detection) and updates types to allow file-based ruleset refs.
  • Updates config loading so file: references in tspconfig.yaml resolve relative to the declaring config (including when reached via extends).
  • Adds documentation, tests, and a .chronus feature entry for the new capability.
File summaries
File Description
website/src/content/docs/docs/handbook/configuration/configuration.mdx Documents file: ruleset extension and relative path behavior.
packages/compiler/test/core/linter.test.ts Adds unit/integration coverage for loading and composing file-based rulesets.
packages/compiler/test/config/config.test.ts Verifies config-loader resolution of file: ruleset refs relative to config files (including extended configs).
packages/compiler/src/index.ts Exports new ruleset ref types from the public surface.
packages/compiler/src/core/types.ts Adds RuleSetFileRef / RuleSetRef and updates LinterRuleSet.extends typing.
packages/compiler/src/core/program.ts Passes projectRoot to linter ruleset extension for base-dir resolution.
packages/compiler/src/core/messages.ts Adds circular-ruleset-file diagnostic.
packages/compiler/src/core/linter.ts Implements file: handling, nested resolution, and circular file-stack detection.
packages/compiler/src/core/linter-ruleset-file.ts New YAML ruleset file loader + schema validation.
packages/compiler/src/config/types.ts Updates config types to accept RuleSetRef[] in linter.extends.
packages/compiler/src/config/config-loader.ts Makes file: ruleset refs absolute at load-time so they remain resolvable across config extension boundaries.
.chronus/changes/linter-ruleset-file-2026-8-3-11-52-0.md Records the feature change for @typespec/compiler with an example.
Review details

Suppressed comments (2)

packages/compiler/test/core/linter.test.ts:910

  • Test description should use "resolves" (third-person singular) for consistency/grammar.
  it("resolve nested file reference relative to the ruleset file", async () => {

packages/compiler/test/core/linter.test.ts:927

  • Grammar in the test description: use "emits" and "doesn't exist".
  it("emit a diagnostic when the file doesn't exists", async () => {
  • Files reviewed: 12/12 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/compiler/test/core/linter.test.ts Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 3, 2026 17:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Ruleset file diagnostics are currently attributed to <anonymous file> due to parseYaml being invoked with a raw string instead of a source carrying the actual file path.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

packages/compiler/src/core/linter-ruleset-file.ts:55

  • parseYaml(file) is given a raw string, so parseYaml creates a SourceFile with path <anonymous file>, causing YAML/invalid-schema diagnostics from ruleset files to report the wrong filename (contradicting the intended path:line:col reporting). Set the YamlScript's file path to the actual ruleset path before returning diagnostics (or pass a SourceFile with the correct path).
    packages/compiler/src/core/types.ts:2676
  • Missing space before the parenthesis in the doc comment makes it harder to read.
  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 3, 2026 17:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation matches the stated behavior (resolution, composition, cycle handling) and is backed by comprehensive tests plus an appropriate feature changelog entry.

Review details
  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 4, 2026 14:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation is well-covered by tests and includes docs/changeset updates, with only minor diagnostic-targeting polish suggested.

Review details
  • Files reviewed: 12/12 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment on lines +340 to +344
createDiagnostic({
code: "circular-ruleset-file",
format: { path: resolvedPath },
target: NoTarget,
}),
Copilot AI review requested due to automatic review settings September 4, 2026 14:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation matches the stated resolution rules, includes cycle/schema/malformed-YAML handling, and is backed by targeted compiler/config tests plus documentation and a feature changeset.

Review details
  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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

Labels

compiler:core Issues for @typespec/compiler meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to define linter ruleset in a file

2 participants