SKILL.md
SKILL.mdBrowse 2 files
1,609 tokens
6,426 bytes
Token encoding: o200k_base
Snapshot 8bff5da
1---2name: n8n:create-community-node-lint-rule3description: >-4 Create new ESLint rules for the @n8n/eslint-plugin-community-nodes package.5 Use when adding a lint rule, creating a community node lint, or working on6 eslint-plugin-community-nodes. Guides rule implementation, tests, docs, and7 plugin registration.8---9 10# Create Community Node Lint Rule11 12Guide for adding new ESLint rules to `packages/@n8n/eslint-plugin-community-nodes/`.13 14All paths below are relative to `packages/@n8n/eslint-plugin-community-nodes/`.15 16## Step 1: Understand the Rule17 18Before writing code, clarify:19- **What** does the rule detect? (missing property, wrong pattern, bad value)20- **Where** does it apply? (`.node.ts` files, credential classes, both)21- **Severity**: `error` (must fix) or `warn` (should fix)?22- **Fixable?** Can it be auto-fixed safely, or only suggest?23- **Scope**: Both `recommended` configs, or exclude from `recommendedWithoutN8nCloudSupport`?24 25## Step 2: Implement the Rule26 27Create `src/rules/<rule-name>.ts`:28 29```typescript30import { AST_NODE_TYPES } from '@typescript-eslint/utils';31 32import {33 isNodeTypeClass, // or isCredentialTypeClass34 findClassProperty,35 findObjectProperty,36 createRule,37} from '../utils/index.js';38 39export const YourRuleNameRule = createRule({40 name: 'rule-name',41 meta: {42 type: 'problem', // or 'suggestion'43 docs: {44 description: 'One-line description of what the rule enforces',45 },46 messages: {47 messageId: 'Human-readable message. Use {{placeholder}} for dynamic data.',48 },49 fixable: 'code', // omit if not auto-fixable50 hasSuggestions: true, // omit if no suggestions51 schema: [], // add options schema if configurable52 },53 defaultOptions: [],54 create(context) {55 return {56 ClassDeclaration(node) {57 if (!isNodeTypeClass(node)) return;58 59 const descriptionProperty = findClassProperty(node, 'description');60 if (!descriptionProperty) return;61 62 const descriptionValue = descriptionProperty.value;63 if (descriptionValue?.type !== AST_NODE_TYPES.ObjectExpression) return;64 65 // Rule logic here — use findObjectProperty(), getLiteralValue(), etc.66 67 context.report({68 node: targetNode,69 messageId: 'messageId',70 data: { /* template vars */ },71 fix(fixer) {72 return fixer.replaceText(targetNode, 'replacement');73 },74 });75 },76 };77 },78});79```80 81**Naming**: Export as `PascalCaseRule` (e.g. `MissingPairedItemRule`). The `name` field is kebab-case.82 83**Available AST helpers** — see [reference.md](reference.md) for the full catalog of `ast-utils` and `file-utils` exports.84 85## Step 3: Write Tests86 87Create `src/rules/<rule-name>.test.ts`:88 89```typescript90import { RuleTester } from '@typescript-eslint/rule-tester';91 92import { YourRuleNameRule } from './rule-name.js';93 94const ruleTester = new RuleTester();95 96// Helper to generate test code — keeps test cases readable97function createNodeCode(/* parameterize the varying parts */): string {98 return `99import type { INodeType, INodeTypeDescription } from 'n8n-workflow';100 101export class TestNode implements INodeType {102 description: INodeTypeDescription = {103 displayName: 'Test Node',104 name: 'testNode',105 group: ['input'],106 version: 1,107 description: 'A test node',108 defaults: { name: 'Test Node' },109 inputs: [],110 outputs: [],111 properties: [],112 };113}`;114}115 116ruleTester.run('rule-name', YourRuleNameRule, {117 valid: [118 { name: 'class that does not implement INodeType', code: '...' },119 { name: 'node with correct pattern', code: createNodeCode(/* correct */) },120 ],121 invalid: [122 {123 name: 'descriptive case name',124 code: createNodeCode(/* incorrect */),125 errors: [{ messageId: 'messageId', data: { /* expected template vars */ } }],126 output: createNodeCode(/* expected after fix */), // or `output: null` if no fix127 },128 ],129});130```131 132**Test guidelines:**133- Always test that non-INodeType classes are skipped (valid case)134- Test both the error message and the fixed output for fixable rules135- For rules with options, test each option combination136- For rules using filesystem, mock with `vi.mock('../utils/file-utils.js')`137- For suggestion-only rules, use `errors: [{ messageId, suggestions: [...] }]`138 139## Step 4: Register the Rule140 141### 4a. Add to `src/rules/index.ts`142 143```typescript144import { YourRuleNameRule } from './rule-name.js';145 146// Add to the rules object:147export const rules = {148 // ... existing rules149 'rule-name': YourRuleNameRule,150} satisfies Record<string, AnyRuleModule>;151```152 153### 4b. Add to `src/plugin.ts` configs154 155Add to **both** config objects (unless the rule depends on n8n cloud features):156 157```typescript158'@n8n/community-nodes/rule-name': 'error', // or 'warn'159```160 161- Use `error` for rules that catch bugs or required patterns162- Use `warn` for style/convention rules (like `options-sorted-alphabetically`)163- If the rule uses `no-restricted-globals` or `no-restricted-imports` patterns,164 only add to `recommended` (not `recommendedWithoutN8nCloudSupport`)165 166## Step 5: Write Documentation167 168Create `docs/rules/<rule-name>.md`:169 170```markdown171# Description of what the rule does (`@n8n/community-nodes/rule-name`)172 173<!-- end auto-generated rule header -->174 175## Rule Details176 177Explain why this rule exists and what problem it prevents.178 179## Examples180 181### Incorrect182 183\`\`\`typescript184// code that triggers the rule185\`\`\`186 187### Correct188 189\`\`\`typescript190// code that passes the rule191\`\`\`192```193 194The header above `<!-- end auto-generated rule header -->` will be regenerated by `pnpm build:docs`. Write a reasonable first version — it gets overwritten.195 196## Step 6: Verify197 198Run from `packages/@n8n/eslint-plugin-community-nodes/`:199 200```bash201pushd packages/@n8n/eslint-plugin-community-nodes202pnpm test <rule-name>.test.ts # tests pass203pnpm typecheck # types are clean204pnpm build # compiles205pnpm build:docs # regenerates doc headers and README table206pnpm lint:docs # docs match schema207popd208```209 210## Checklist211 212- [ ] Rule file: `src/rules/<rule-name>.ts`213- [ ] Test file: `src/rules/<rule-name>.test.ts`214- [ ] Registered in `src/rules/index.ts`215- [ ] Added to configs in `src/plugin.ts`216- [ ] Doc file: `docs/rules/<rule-name>.md`217- [ ] README table updated via `pnpm build:docs`218- [ ] All verification commands pass219 Discovery context
Discovered by repository scan. No exact path reference found in the snapshot’s root AGENTS.md.
