Skip to main content

create-linter-rule

Create a new TypeSpec linter rule, lint diagnostic, or design guideline checker with a TDD approach, including implementation, tests, documentation, ruleset registration, and changeset. Use this skill when asked to create, add, implement, or write a new linter rule, lint warning, validation rule, or design guideline enforcement for TypeSpec Azure libraries.

Datos de origen

Repositorio
Azure/typespec-azure
Última actividad en el origen
4 de agosto de 2026 a las 23:52
Idioma detectado de SKILL.md
inglés
Estrellas
27
Forks
92

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
create-linter-rule
description
Create a new TypeSpec linter rule, lint diagnostic, or design guideline checker with a TDD approach, including implementation, tests, documentation, ruleset registration, and changeset. Use this skill when asked to create, add, implement, or write a new linter rule, lint warning, validation rule, or design guideline enforcement for TypeSpec Azure libraries.
allowed-tools
shell
# Create a TypeSpec Linter Rule Follow these steps in order to create a complete, high-quality linter rule. ## Step 1: IDENTIFY Determine the rule metadata before writing any code: - **Package**: `typespec-azure-core` (data-plane rules), `typespec-azure-resource-manager` (ARM rules), or `typespec-client-generator-core` (client SDK generation rules) - **Rule name**: Must follow these naming conventions: - Use kebab-case (lowercase letters, numbers, hyphens) - DO NOT include the package name in the rule ID (the package is already part of the fully-qualified diagnostic code) - Use `no-<thing>` when the rule bans a construct or usage (e.g., `no-nullable`, `no-enum`, `no-format`) - Use `use-<preferred-thing>` when the rule points users to a standard/preferred TypeSpec pattern (e.g., `use-standard-operations`, `use-extensible-enum`) - Keep names short and concise — prefer `no-enum` over `no-enum-type-usage` - **Severity**: All linter rules are warnings; no severity choice is needed - **Target ruleset(s)**: `data-plane`, `resource-manager`, or both - **Description**: One-line explanation of what the rule enforces Choose the package by scope: - Decorators from `typespec-client-generator-core`, or rules only about client SDK generation → `typespec-client-generator-core` - Rules specific to ARM APIs → `typespec-azure-resource-manager` - Rules that apply to both data-plane and ARM, or only data-plane → `typespec-azure-core` ## Step 2: SCAFFOLD Generate all required files using the repo's scaffolding tool: ```bash pnpm create:linter-rule < rule-name > --package < azure-core | azure-resource-manager | client-generator-core > --description "<description>" ``` This creates: - `packages/<pkg>/src/rules/<rule-name>.ts` — rule skeleton - `packages/<pkg>/test/rules/<rule-name>.test.ts` — test skeleton - `packages/<pkg>/src/rules/<rule-name>.md` — docs skeleton (referenced from the rule via `docs: fileRef.fromPackageRoot(...)`) - Updates `packages/<pkg>/src/linter.ts` — registers the rule ## Step 3: WRITE FAILING TESTS FIRST (TDD) Edit `packages/<pkg>/test/rules/<rule-name>.test.ts`: 1. Write tests for **valid code** that should produce no diagnostics (`.toBeValid()`) 2. Write tests for **invalid code** that should produce specific diagnostics (`.toEmitDiagnostics()`) 3. Create **equivalence classes** for the input and write tests covering at least one instance of each class: - Group inputs by how the rule handles them (e.g., for a rule targeting `ModelProperty`): - Simply defined properties - Properties defined using `spread` or `is` - Properties inherited from a base class - Add boundary conditions specific to the rule logic (e.g., for a name-prefix rule): - Properties with the forbidden prefix - Properties with the prefix text in the middle or end of the name - Properties with names shorter than the prefix 4. Always include at least one test verifying that **library types in `Azure.Core` and `Azure.ResourceManager` are not subject to the rule** Test API reference: ```typescript // No diagnostics expected await tester.expect(`model Foo {}`).toBeValid(); // Specific diagnostic expected await tester.expect(`model foo {}`).toEmitDiagnostics([ { code: "@azure-tools/typespec-<pkg>/<rule-name>", severity: "warning", message: "Expected message text", }, ]); // Test code fix (if rule provides one) await tester .expect(`enum Color { red }`) .applyCodeFix("fix-id") .toEqual(`union Color { string, red: "red" }`); ``` Verify tests fail before implementing: ```bash pnpm --filter "@azure-tools/typespec-<pkg>..." build pnpm --filter "@azure-tools/typespec-<pkg>..." test ``` ## Step 4: IMPLEMENT THE RULE Edit `packages/<pkg>/src/rules/<rule-name>.ts`: - Implement visitor logic in the `create(context)` function - Return a `SemanticNodeListener` with the appropriate hooks: - `model` — for model-level checks - `modelProperty` — for property-level checks - `operation` — for operation-level checks - `enum` — for enum checks - `namespace` — for namespace-level checks - `interface` — for interface checks - `union` / `unionVariant` — for union checks - Use `context.reportDiagnostic({ target })` to report violations - Use `paramMessage` from `@typespec/compiler` for interpolated messages - Add `codefixes` array to `reportDiagnostic()` if a fix is possible ## Step 5: VERIFY TESTS PASS ```bash pnpm --filter "@azure-tools/typespec-<pkg>..." build pnpm --filter "@azure-tools/typespec-<pkg>..." test ``` All tests should pass. If not, fix the implementation until they do. ## Step 6: REGISTER IN RULESETS Add the rule to the appropriate ruleset(s): - **Data-plane rules**: Edit `packages/typespec-azure-rulesets/src/rulesets/data-plane.ts` - **ARM rules**: Edit `packages/typespec-azure-rulesets/src/rulesets/resource-manager.ts` TCGC rules generally go in **both** rulesets. Rules in `typespec-azure-core` that apply to both ARM and data-plane specs also go in **both** rulesets. Only rules that are truly ARM-specific go exclusively in `resource-manager.ts`; otherwise, add the rule to both `resource-manager.ts` and `data-plane.ts` as appropriate. Add an entry: `"@azure-tools/typespec-<pkg>/<rule-name>": true,` Every rule MUST be explicitly listed (enabled or disabled). The `validate-rules-defined.test.ts` test will fail otherwise. Verify: ```bash pnpm --filter "@azure-tools/typespec-azure-rulesets..." build pnpm --filter "@azure-tools/typespec-azure-rulesets..." test ``` ## Step 7: WRITE DOCUMENTATION AND REGENERATE DOCS Edit `packages/<pkg>/src/rules/<rule-name>.md`: - Replace all placeholder text - Write a clear description of what the rule checks and why - Provide realistic ❌ Incorrect and ✅ Correct examples using actual TypeSpec patterns - Add a required **`## Impact`** section: a bulleted `**Area:**` line (e.g. `API`, `SDK`, `Emitters`) followed by a short paragraph describing what breaks or degrades when the rule is violated - Add a required **`## Suppression`** section: state whether suppression is acceptable and why, and point to the correct fix. Suppressions use the `#suppress "<rule-id>" "<justification-string>"` **directive** placed on the line above the target — NOT a `// suppress` comment - Add a **`## LintDiff Equivalent`** section when an equivalent LintDiff (azure-openapi-validator) rule exists, deep-linking to the specific rule id in the [OpenAPI authoring automated guidelines](https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/openapi-authoring-automated-guidelines.md). Omit only when no equivalent exists - This file holds only the extended documentation body — the page title, rule id, and short description are generated from the rule definition. `tspd` renders the page at `website/src/content/docs/docs/libraries/<pkg>/rules/<rule-name>.md` - For ARM rules, also update the alphabetized rule table in `website/src/content/docs/docs/howtos/ARM/arm-rules.md` with the documentation URL, LintDiff equivalent, and impact. This table is authored manually and is not updated by `regen-docs`. Then regenerate the library's reference docs (updates the rule listing): ```bash pnpm --filter "@azure-tools/typespec-<pkg>..." build pnpm --filter "@azure-tools/typespec-<pkg>" regen-docs ``` ## Step 8: CREATE CHANGESET ```bash pnpm change add ``` When prompted: - Select change kind: `feature` (new rule) or `fix` (bugfix to existing rule) - Select affected package: `@azure-tools/typespec-<pkg>` - Write a concise description: "Add `<rule-name>` linter rule that <what it does>" ## Step 9: FINAL VALIDATION Run the general pre-PR validation to ensure everything is ready: ```bash pnpm validate:pr ``` This checks: branch is up to date, build passes, tests pass, lint passes, format is clean, spelling is clean, regen-docs is clean, changeset exists, and diff only contains expected files. If any check fails, fix the issue and re-run. Use `pnpm validate:pr --fix` to auto-fix formatting and lint issues. ## Step 10: EXTERNAL INTEGRATION CHECK New linter rules MUST NOT break existing Azure service specs. After pushing your PR: 1. Apply the `int:azure-specs` label to the PR to trigger the External Integration check: `gh pr edit --add-label "int:azure-specs"` 2. If the agent cannot apply the label automatically, tell the user to apply the `int:azure-specs` label manually in the GitHub UI 3. After applying the label, the External Integration workflow will start. Monitor it via `gh run list --workflow=external-integration.yml` 4. This workflow packages your changes and runs TypeSpec validation against all specs in `Azure/azure-rest-api-specs` 5. Wait for the check to pass before requesting review If the check fails, your rule produces diagnostics on existing specs. To resolve: 1. **Apply an API-neutral fix to the spec** (preferred): If the fix doesn't change API behavior, submit a PR to `Azure/azure-rest-api-specs` on the **main** branch. 2. **Suppress the rule**: If the spec cannot be fixed without changing API behavior, add a `#suppress "<rule-id>" "<justification-string>"` directive on the line above the target (NOT a `// suppress` comment). Suppressions always go to the **main** branch. 3. **Fix on typespec-next**: If the fix requires unreleased TypeSpec APIs or behavior, submit to the **typespec-next** branch (uses nightly builds). 4. **Link your spec fix PR**: Always link the spec fix PR in your linter rule PR description. The External Integration workflow: - Builds and packs all typespec-azure packages from your PR - Checks out `Azure/azure-rest-api-specs` (main branch) - Patches in your packaged changes - Runs `tsp-integration azure-specs --stage validate` - Checks for unexpected git changes ## Important Notes - **Import extensions**: Always use `.js` extensions in imports (e.g., `from "./rules/my-rule.js"`) - **Rule URL**: Must match `https://azure.github.io/typespec-azure/docs/libraries/<pkg>/rules/<rule-name>` - **Test coverage**: Aim for ≥ 95% branch coverage of the rule file - **Existing patterns**: Look at similar existing rules in `packages/<pkg>/src/rules/` for reference - **ARM rules can import from azure-core**: `import { ... } from "@azure-tools/typespec-azure-core"`
Ver en GitHub