eslint-plugin-llm-core-mcp 0.29.0 โ†’ 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"embedded-docs.d.ts","sourceRoot":"","sources":["../src/embedded-docs.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuC/C,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,MAAM,EAAm4B,CAAC"}
1
+ {"version":3,"file":"embedded-docs.d.ts","sourceRoot":"","sources":["../src/embedded-docs.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAwC/C,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,MAAM,EAA25B,CAAC"}
@@ -26,6 +26,7 @@ export const embeddedDocs = {
26
26
  "no-inline-disable": "# llm-core/no-inline-disable\n\n๐Ÿ“ Disallow eslint-disable comments that suppress lint errors instead of fixing them.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, ๐Ÿงน `hygiene`, โœ… `recommended`.\n\n<!-- end auto-generated rule header -->\n\nDisallow eslint-disable comments that suppress lint errors instead of fixing them.\n\n## Rule Details\n\nLLMs frequently add `// eslint-disable-next-line` or `/* eslint-disable */` comments to silence lint errors rather than fixing the underlying code. This bypasses all other lint rules, defeating the purpose of linting.\n\nThis rule catches:\n\n- `// eslint-disable-next-line`\n- `// eslint-disable-line`\n- `/* eslint-disable ... */`\n- `/* eslint-enable ... */`\n\n## Examples\n\n### Incorrect\n\n```ts\n// eslint-disable-next-line no-unused-vars\nconst x = 1;\n\n/* eslint-disable no-console */\nconsole.log(\"debug\");\n/* eslint-enable no-console */\n\nconst y = 1; // eslint-disable-line no-unused-vars\n```\n\n### Correct\n\n```ts\n// Fix the code instead of disabling the rule\nconst x = computeValue();\nuseValue(x);\n\n// Use a proper logger instead of console\nlogger.debug(\"debug info\", { context });\n\n// If a rule doesn't apply to certain files, configure it in eslint.config.mjs\n// instead of disabling inline\n```\n\n## Why No Escape Hatches?\n\nWhen an LLM encounters a lint error, it has two options:\n\n1. Fix the code to satisfy the rule\n2. Add a disable comment to suppress the error\n\nOption 2 is always easier, so LLMs default to it. This rule removes that escape hatch, forcing the LLM to actually fix the code โ€” which is the entire point of linting.\n\n## Error Messages\n\nError messages follow a structured teaching format designed for LLM self-correction:\n\n1. **What's wrong** โ€” identifies the specific disable comment\n2. **Why** โ€” explains that suppressing rules hides problems\n3. **How to fix** โ€” three alternatives: fix the code, configure the rule properly, or refactor\n",
27
27
  "no-llm-artifacts": "# llm-core/no-llm-artifacts\n\n๐Ÿ“ Disallow common LLM placeholder comments and incomplete code markers that indicate skipped implementation.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, ๐Ÿงน `hygiene`, โœ… `recommended`.\n\n<!-- end auto-generated rule header -->\n\nDisallow common LLM placeholder comments and stub function bodies that indicate incomplete code generation.\n\n## Rule Details\n\nLLMs frequently save tokens by outputting placeholder comments like `// ... existing code ...`, `// TODO: implement`, or `// rest of the function remains the same` instead of writing the actual code. When applied automatically by an agent, these placeholders silently replace real logic with nothing.\n\nThis rule detects two categories of LLM artifacts:\n\n1. **Placeholder comments** โ€” Comments that indicate skipped or abbreviated code\n2. **Stub function bodies** โ€” Functions whose only statement is `throw new Error(\"Not implemented\")`\n\n## Examples\n\n### Incorrect\n\n```ts\n/* eslint llm-core/no-llm-artifacts: \"error\" */\n\n// ... existing code ...\nfunction processData(items: Item[]) {\n // implementation goes here\n}\n\n// rest of the function remains the same\n\nfunction validate(input: string) {\n throw new Error(\"Not implemented\");\n}\n\n// abbreviated for brevity\n// add error handling as needed\n```\n\n### Correct\n\n```ts\n/* eslint llm-core/no-llm-artifacts: \"error\" */\n\n// This function processes items by filtering and transforming\nfunction processData(items: Item[]) {\n return items.filter(isValid).map(transform);\n}\n\n// TODO(#123): add caching for repeated lookups\nfunction validate(input: string) {\n if (!input.trim()) {\n throw new Error(\"Input must not be empty\");\n }\n return schema.parse(input);\n}\n```\n\n## Detected Patterns\n\n### Placeholder Comments\n\n| Pattern | Example |\n| ---------------------- | ---------------------------------------------------------- |\n| Ellipsis placeholders | `// ... existing code ...`, `// ...rest of the code...` |\n| \"Remains the same\" | `// rest of the function remains the same` |\n| Lazy TODO | `// TODO: implement`, `// TODO implement` |\n| \"Code here\" markers | `// add implementation here`, `// your code here` |\n| \"As needed\" deferrals | `// add error handling as needed` |\n| Brevity markers | `// abbreviated for brevity`, `// omitted for clarity` |\n| Reference to elsewhere | `// similar to above`, `// same as before` |\n| \"Continue here\" | `// continue from here`, `// continue implementation here` |\n| \"See above/below\" | `// see implementation above`, `// see above for details` |\n\n### Stub Function Bodies\n\nFunctions whose only statement is `throw new Error(msg)` where `msg` matches \"not implemented\" or \"TODO: implement\" (case-insensitive).\n\n## What This Rule Allows\n\n- **Specific TODOs** โ€” `// TODO(#123): validate input against schema` (has actionable context)\n- **Prose comments** โ€” `// This handles the edge case where input is empty`\n- **Legitimate throws** โ€” `throw new Error(\"XML format is not supported\")` (real error, not a placeholder)\n- **Functions with real logic** โ€” Even if they contain a \"not implemented\" throw alongside other statements\n\n## Error Messages\n\n### `noLlmArtifact`\n\n> LLM placeholder detected: '...'. Replace with actual implementation.\n\nFired for placeholder comments. The message explains that these comments replace real logic when applied, and suggests writing specific TODOs if work must be deferred.\n\n### `notImplementedStub`\n\n> Function body is a 'not implemented' stub โ€” write the actual implementation.\n\nFired for functions whose sole body is a \"not implemented\" throw. The message explains that these stubs pass type checks but fail at runtime.\n",
28
28
  "no-magic-numbers": "# llm-core/no-magic-numbers\n\n๐Ÿ“ Disallow magic numbers and enforce named constants for clarity.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, ๐Ÿ† `best-practices`, โœ… `recommended`.\n\n<!-- end auto-generated rule header -->\n\nDisallow magic numbers and enforce named constants for clarity.\n\n## Rule Details\n\nLLMs scatter hardcoded numbers throughout generated code โ€” timeouts, limits, sizes, retry counts โ€” without explaining what they represent. This rule forces numbers to be extracted into named constants.\n\n## Examples\n\n### Incorrect\n\n```ts\nif (retries > 5) {\n throw new Error(\"Too many retries\");\n}\n\nsetTimeout(callback, 3000);\n\nif (file.size > 1048576) {\n throw new Error(\"File too large\");\n}\n```\n\n### Correct\n\n```ts\nconst MAX_RETRIES = 5;\nif (retries > MAX_RETRIES) {\n throw new Error(\"Too many retries\");\n}\n\nconst RETRY_DELAY_MS = 3000;\nsetTimeout(callback, RETRY_DELAY_MS);\n\nconst MAX_FILE_SIZE_BYTES = 1048576;\nif (file.size > MAX_FILE_SIZE_BYTES) {\n throw new Error(\"File too large\");\n}\n```\n\n## What This Rule Allows\n\nBy default, these are permitted without named constants:\n\n- **`0`, `1`, `-1`, `2`** โ€” ubiquitous in loops, checks, and arithmetic\n- **Array indexes** โ€” `items[3]` (configurable)\n- **Default parameter values** โ€” `function retry(attempts = 3)` (configurable)\n- **Enum initializers** โ€” `enum Status { Active = 10 }` (configurable)\n- **Type contexts** โ€” type-level numeric literals\n- **Const declarations** โ€” `const MAX = 5` (this IS the named constant)\n\n## Options\n\n### `ignore`\n\nNumbers to allow without named constants. Default: `[0, 1, -1, 2]`.\n\n### `ignoreArrayIndexes`\n\nAllow numbers as computed array/object indexes. Default: `true`.\n\n### `ignoreDefaultValues`\n\nAllow numbers as default parameter values. Default: `true`.\n\n### `ignoreEnums`\n\nAllow numbers in enum initializers. Default: `true`.\n\n### `skipTestFiles`\n\nWhether to skip test files (`.test.ts`, `.spec.ts`, etc.). Default: `true`.\n\nTest files are full of numeric literals in assertions โ€” `expect(sum(2, 3)).toBe(5)` โ€” where extracting to constants hurts readability.\n\n### `ignoreObjectProperties`\n\nAllow numbers used as object literal property values. Default: `false`.\n\nUseful for data files like pricing tables, model config maps, and HTTP status maps where the values **are** the data:\n\n```ts\n// With ignoreObjectProperties: true โ€” no errors\nconst PRICING = { basic: 9.99, pro: 29.99, enterprise: 99.99 };\nconst HTTP_STATUS = { BAD_REQUEST: 400, NOT_FOUND: 404 };\n```\n\nNumbers outside object literals are still flagged even with this option enabled. This only applies to object literal property values (`ObjectExpression`) โ€” destructuring defaults like `function f({ timeout = 5000 }) {}` are still flagged.\n\n```json\n{\n \"llm-core/no-magic-numbers\": [\n \"error\",\n {\n \"ignore\": [0, 1, -1, 2, 100],\n \"ignoreArrayIndexes\": true,\n \"ignoreDefaultValues\": true,\n \"ignoreEnums\": true,\n \"skipTestFiles\": true,\n \"ignoreObjectProperties\": true\n }\n ]\n}\n```\n\n## Error Messages\n\nError messages follow a structured teaching format designed for LLM self-correction:\n\n1. **What's wrong** โ€” identifies the specific magic number\n2. **Why** โ€” explains that readers can't tell what the number represents\n3. **How to fix** โ€” shows a before/after extraction to a named constant using the actual number\n",
29
+ "no-redundant-comments": "# llm-core/no-redundant-comments\n\n๐Ÿ“ Disallow comments that merely narrate the next line of code without adding intent.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, ๐Ÿงน `hygiene`, โœ… `recommended`.\n\n<!-- end auto-generated rule header -->\n\nDisallow comments that merely narrate adjacent code instead of explaining intent, constraints, or non-obvious behavior.\n\n## Rule Details\n\nLLMs often add conversational comments that describe the next line of code in plain English: `// Validate the input`, `// Return the result`, or `// Check if the user exists`. These comments do not preserve design intent. They make files noisier and train future edits to keep narrating implementation mechanics instead of documenting why the code exists.\n\nThis rule reports narrow, high-confidence cases where a line comment immediately precedes code that already says the same thing.\n\n## Examples\n\n### Incorrect\n\n```ts\n// Validate the user input\nvalidateUser(input);\n\n// Return the result\nreturn result;\n\n// Check if the user exists\nif (user) {\n activateUser(user);\n}\n\n// Set the user name\nuser.name = name;\n```\n\n### Correct\n\n```ts\n// Reject webhook payloads before persistence because they are untrusted\nvalidateWebhookPayload(payload);\n\n// Only return cached data when the caller accepts stale results\nreturn cache.get(key);\n\n// This branch handles retry after a 429 response\nif (shouldRetry(response)) {\n retry();\n}\n```\n\n## What Counts as a Redundant Comment\n\n| Pattern | Triggers? |\n| -------------------------------------------------------------- | --------- |\n| `// Return the result` before `return result` | Yes |\n| `// Validate the user input` before `validateUser(input)` | Yes |\n| `// Set the user name` before `user.name = name` | Yes |\n| `// Validate before persisting because payloads are untrusted` | No |\n| `// TODO(#123): add request tracing` | No |\n| JSDoc API documentation | No |\n| ESLint or TypeScript directive comments | No |\n\n## Error Messages\n\nThe error message teaches:\n\n1. **What's wrong** -- the comment narrates adjacent code without adding intent\n2. **Why** -- conversational comments are common LLM noise and reduce maintainability\n3. **How to fix** -- delete the comment or rewrite it to explain why, constraints, or tradeoffs\n",
29
30
  "no-redundant-logic": "# llm-core/no-redundant-logic\n\n๐Ÿ“ Disallow redundant boolean logic and unnecessary control flow patterns.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, โœ… `recommended`, ๐ŸŽจ `style`.\n\n๐Ÿ’ก This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).\n\n<!-- end auto-generated rule header -->\n\nFlags four patterns where LLMs produce verbose-but-correct boolean logic that can be simplified without changing semantics.\n\n## Rule Details\n\n### Pattern 1 โ€” Redundant boolean comparison\n\nExplicit `=== true`, `!== true`, `=== false`, or `!== false` comparisons on an expression that already evaluates to a boolean.\n\nOnly strict equality (`===`/`!==`) is flagged. Loose equality (`==`/`!=`) has different truthy/falsy semantics and is intentionally excluded.\n\n> **Known limitation:** This rule does not use type information. If the compared expression is a union type (e.g., `string | boolean`), the `=== true` comparison may be intentional type narrowing, not a redundant check. Disable the rule on that line if this applies.\n\n#### Incorrect\n\n```ts\nif (isActive === true) {\n}\nif (isValid !== true) {\n}\nif (hasPermission === false) {\n}\nwhile (running !== false) {}\n```\n\n#### Correct\n\n```ts\nif (isActive) {\n}\nif (!isValid) {\n}\nif (!hasPermission) {\n}\nwhile (running) {}\n```\n\n### Pattern 2 โ€” Unnecessary else after return/throw\n\nAn `else` block that follows an `if` block ending in `return` or `throw` is unreachable via fall-through. The `else` can be removed and its body placed at the outer scope.\n\nOnly flags when:\n\n- The `if` consequent ends with `return` or `throw`\n- The `else` is a simple block (single `return` or `throw`), not an `else if` chain\n- Pattern 4 does not apply to the same node (to avoid double-reporting)\n\n#### Incorrect\n\n```ts\nfunction getLabel(status: string): string {\n if (status === \"active\") {\n return \"Active\";\n } else {\n return \"Inactive\";\n }\n}\n```\n\n#### Correct\n\n```ts\nfunction getLabel(status: string): string {\n if (status === \"active\") {\n return \"Active\";\n }\n return \"Inactive\";\n}\n```\n\n### Pattern 3 โ€” Ternary returning boolean literals\n\nA ternary of the form `condition ? true : false` or `condition ? false : true` is identical to the condition (or its negation).\n\n#### Incorrect\n\n```ts\nconst isEligible = age >= 18 ? true : false;\nconst isBlocked = isAdmin ? false : true;\n```\n\n#### Correct\n\n```ts\nconst isEligible = age >= 18;\nconst isBlocked = !isAdmin;\n```\n\n### Pattern 4 โ€” If/else returning or assigning boolean literals\n\nWhen both branches of an `if`/`else` exclusively `return` or assign the same variable to a boolean literal, the entire construct reduces to a single expression.\n\n#### Incorrect\n\n```ts\nif (items.length > 0) {\n return true;\n} else {\n return false;\n}\n\nlet isValid;\nif (age >= 18) {\n isValid = true;\n} else {\n isValid = false;\n}\n```\n\n#### Correct\n\n```ts\nreturn items.length > 0;\nconst isValid = age >= 18;\n```\n\n## Out of Scope\n\n- De Morgan transformations (`!(a && b)` โ†’ `!a || !b`) โ€” too subjective\n- `!!value` double-negation โ€” intentional type-coercion pattern\n- Loose equality (`== true`) โ€” different semantics\n- Complex boolean simplification โ€” requires symbolic reasoning\n\n## Error Messages\n\nEach pattern has a distinct `messageId`:\n\n| Pattern | `messageId` |\n| ------- | ---------------------------- |\n| 1 | `redundantBooleanComparison` |\n| 2 | `unnecessaryElse` |\n| 3 | `ternaryBooleanLiteral` |\n| 4 | `ifElseBooleanLiteral` |\n\nAll four messages follow the standard what/why/how format.\n\n## Suggestions\n\nAll four patterns provide suggestions (not auto-fixes) โ€” the transformations are safe but the developer should confirm intent before applying.\n",
30
31
  "no-swallowed-errors": "# llm-core/no-swallowed-errors\n\n๐Ÿ“ Disallow catch blocks that only log to console and swallow the error.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, ๐Ÿ† `best-practices`, โœ… `recommended`.\n\n<!-- end auto-generated rule header -->\n\nDisallow `catch` blocks that only call `console.log`, `console.warn`, `console.error`, or `console.debug` without rethrowing, returning, or delegating the failure to a real error handler.\n\n## Rule Details\n\nLLMs often generate placeholder error handling like `catch (error) { console.error(error); }`. That looks intentional, but it still swallows the failure: callers do not see an error, control flow continues, and production systems quietly drift into bad state.\n\nThis rule focuses on the narrow, high-signal case where a non-empty `catch` block contains **only console logging calls**. It deliberately does **not** overlap with `no-empty-catch` โ€” truly empty or comment-only blocks belong to that rule.\n\n## Examples\n\n### Incorrect\n\n```ts\ntry {\n await processOrder(order);\n} catch (error) {\n console.error(error);\n}\n\ntry {\n await loadConfig();\n} catch (error) {\n console.warn(\"Config failed\", error);\n console.debug(error);\n}\n```\n\n### Correct\n\n```ts\ntry {\n await processOrder(order);\n} catch (error) {\n throw new Error(\"Failed to process order\", { cause: error });\n}\n\ntry {\n return await loadConfig();\n} catch (error) {\n logger.error(\"Config load failed\", { error });\n return null;\n}\n\ntry {\n await publishEvent(event);\n} catch (error) {\n Sentry.captureException(error);\n}\n\ntry {\n await performWork();\n} catch (error) {\n console.error(error);\n throw error;\n}\n```\n\n## What This Rule Flags\n\n| Catch body contents | Flagged? |\n| ----------------------------------------------- | -------- |\n| `console.error(error)` | โœ… Yes |\n| `console.log(error); console.warn(\"failed\", e)` | โœ… Yes |\n| `console.error(error); throw error;` | โŒ No |\n| `console.error(error); handleError(error);` | โŒ No |\n| `handleError(error)` | โŒ No |\n| empty `catch {}` | โŒ No |\n\n## Why Console-Only Handling Is Risky\n\n- Logging alone does not change control flow.\n- Callers cannot recover because they never learn the operation failed.\n- Background tasks can keep running with partial or invalid state.\n- The code looks \"handled\" in review even though the failure was dropped.\n\n## Error Messages\n\nThe teaching message explains:\n\n1. **What's wrong** โ€” the catch block only logs and swallows the error\n2. **Why** โ€” execution continues as if nothing failed\n3. **How to fix** โ€” rethrow, return an explicit fallback, or delegate to a real handler such as a logger or error tracker\n",
31
32
  "no-type-assertion-any": "# llm-core/no-type-assertion-any\n\n๐Ÿ“ Disallow type assertions to `any` that bypass TypeScript's type safety.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, โœ… `recommended`, โŒจ๏ธ `typescript`.\n\n<!-- end auto-generated rule header -->\n\nDisallow type assertions to `any` (`as any` and `<any>` syntax).\n\n## Rule Details\n\nLLMs reach for `as any` as the default escape hatch when types don't align. This completely disables TypeScript's type checking at the assertion site and for every downstream usage of the value. It is the single most common way generated code defeats type safety.\n\n## Examples\n\n### Incorrect\n\n```ts\n// Bypasses all type checking\nconst result = data as any;\n\n// Silently accesses potentially nonexistent property\n(response as any).body;\n\n// Hides a type incompatibility\nprocess(input as any);\n\n// Angle bracket syntax (same problem)\nconst value = <any>data;\n```\n\n### Correct\n\n```ts\n// Assert to a specific known type\nconst result = data as ExpectedType;\n\n// Double assertion through unknown (explicit escape hatch)\nconst result = data as unknown as ExpectedType;\n\n// Use unknown and narrow with type guards\nfunction process(data: unknown) {\n if (typeof data === \"string\") {\n handle(data); // TypeScript knows it's a string\n }\n}\n\n// Properly type the response\nconst body = (response as ResponseWithBody).body;\n```\n\n## What This Rule Catches\n\nThe rule flags both forms of type assertion to `any`:\n\n1. **`as any`** โ€” `value as any`\n2. **`<any>`** โ€” `<any>value` (angle bracket syntax)\n\n### What This Rule Does NOT Catch\n\n- `any` in type annotations (`const x: any`) โ€” use `@typescript-eslint/no-explicit-any` for this\n- `any` in generic type arguments (`Array<any>`) โ€” use `llm-core/no-any-in-generic` for this\n- Implicit `any` from missing type annotations โ€” use `@typescript-eslint/no-unsafe-*` rules for this\n\n## Error Messages\n\nThe error message teaches the proper alternative:\n\n1. **What's wrong** โ€” the assertion bypasses all type checking\n2. **Why** โ€” `any` disables TypeScript's safety and leaks into downstream code\n3. **How to fix** โ€” assert to a specific type, or use `unknown` with type guards\n",
@@ -39,5 +40,5 @@ export const embeddedDocs = {
39
40
  "throw-error-objects": "# llm-core/throw-error-objects\n\n๐Ÿ“ Disallow throwing non-Error values such as strings, template literals, plain objects, or arrays.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, ๐Ÿ† `best-practices`, โœ… `recommended`.\n\n<!-- end auto-generated rule header -->\n\nDisallow throwing string literals, template literals, plain objects, arrays, or other non-Error values.\n\n## Rule Details\n\nLLMs often generate `throw \"something went wrong\"` or `throw { code: 404 }` as a shorthand. These patterns lose the stack trace, break `e instanceof Error` checks, and cause silent failures in logging and error-reporting tools that expect an `Error` object.\n\nThis is a syntax-only rule and does not require type information. It allows `throw` of identifiers, member expressions, call expressions, and `new` expressions because it cannot statically prove their type โ€” those forms are assumed to be Error instances or safe wrappers.\n\n## Examples\n\n### Incorrect\n\n```ts\n// String literal โ€” no stack trace\nthrow \"something went wrong\";\n\n// Template literal โ€” still no stack trace\nthrow `failed to connect to ${host}`;\n\n// Plain object โ€” instanceof Error fails, .stack is undefined\nthrow { code: 404, message: \"not found\" };\n\n// Array โ€” completely wrong type\nthrow [\"validation\", \"failed\"];\n\n// Number\nthrow 500;\n```\n\n### Correct\n\n```ts\n// Error instance โ€” stack trace, instanceof, .message all work\nthrow new Error(\"something went wrong\");\n\n// Error subclass\nthrow new ValidationError(\"invalid input\");\n\n// Identifier โ€” may hold an Error, allowed\nthrow err;\n\n// Call expression โ€” assumed to create a proper Error\nthrow createError(\"context\", { cause: err });\n\n// Enrich an existing error with context\nthrow Object.assign(new Error(\"not found\"), { code: 404 });\n```\n\n## What This Rule Does NOT Flag\n\n- `throw identifier` โ€” the identifier may hold an Error; type-checking would be needed to verify\n- `throw expr.property` โ€” same reason\n- `throw callExpression()` โ€” assumed to return an Error\n- `throw new SomeThing()` โ€” assumed to construct an Error\n\n## Error Messages\n\nThe error message teaches:\n\n1. **What's wrong** โ€” the thrown value is not an Error instance\n2. **Why** โ€” stack traces are lost, catch handlers receive unexpected types\n3. **How to fix** โ€” `new Error(msg)`, `Object.assign(new Error(...), extras)`, or Error subclasses\n",
40
41
  "uninvoked-array-callback": "# llm-core/uninvoked-array-callback\n\n๐Ÿ“ Disallow callbacks on sparse arrays created with Array(length) because holes skip callback invocation.\n\n๐Ÿ’ผ This rule is enabled in the following configs: ๐ŸŒ `all`, ๐Ÿ† `best-practices`, โœ… `recommended`.\n\n<!-- end auto-generated rule header -->\n\n## Rule details\n\nThis rule flags array callback methods called directly on sparse arrays created with `Array(length)` or `new Array(length)`. Those constructors create holes, not present `undefined` elements. JavaScript array callback methods skip holes, so callbacks such as `.map(...)`, `.forEach(...)`, `.filter(...)`, `.some(...)`, and `.every(...)` may run zero times even though the code looks like it should run once per index.\n\nLLMs often generate this pattern when they want to create `n` rows, placeholders, tasks, or test cases. The code silently returns another sparse array or performs no side effects.\n\nFlagged patterns:\n\n```ts\nconst rows = new Array(5).map((_, index) => createRow(index));\n\nArray(count).forEach((_, index) => {\n save(index);\n});\n\nconst ids = new Array(3).map((_, index) => index).filter((index) => index > 0);\n```\n\nCorrect patterns:\n\n```ts\nconst rows = Array.from({ length: 5 }, (_, index) => createRow(index));\n\nnew Array(count).fill(null).forEach((_, index) => {\n save(index);\n});\n\nconst ids = [...new Array(3)]\n .map((_, index) => index)\n .filter((index) => index > 0);\n```\n\n## What counts as a sparse array callback\n\n| Pattern | Triggers? | Why |\n| --------------------------------------- | --------- | ----------------------------------------------------------- |\n| `new Array(5).map(callback)` | Yes | Length-only arrays contain holes, so callbacks are skipped. |\n| `Array(count).forEach(callback)` | Yes | `Array(length)` has the same sparse-array behavior. |\n| `new Array(5).fill(null).map(callback)` | No | `.fill(...)` materializes present elements first. |\n| `new Array(5).fill(null, 1).map(cb)` | Yes | Partial fills leave holes outside the filled range. |\n| `[...new Array(5)].map(callback)` | No | Spreading materializes present `undefined` elements. |\n| `Array.from({ length: 5 }, callback)` | No | `Array.from` invokes the mapping callback for each index. |\n| `new Array(\"a\", \"b\").map(callback)` | No | Multiple arguments create present elements. |\n| `Array(true).map(callback)` | No | Non-number single arguments create one present element. |\n| `collection.map(callback)` | No | The rule stays narrow and only targets Array constructors. |\n\n## Error messages\n\nThe error message teaches:\n\n1. **What's wrong** โ€” `Array(length)` created sparse slots, so the callback will not run for them.\n2. **Why** โ€” LLM-generated code often expects one callback invocation per index, but array methods skip holes.\n3. **How to fix** โ€” use `Array.from({ length }, mapper)` or materialize elements with `.fill(...)` before calling callback methods.\n",
41
42
  };
42
- export const ruleNames = ["bad-comparison-sequence", "bad-min-max-func", "consistent-catch-param-name", "explicit-export-types", "filename-match-export", "max-complexity", "max-file-length", "max-function-length", "max-nesting-depth", "max-params", "missing-throw", "naming-conventions", "no-any-in-generic", "no-async-array-callbacks", "no-async-promise-executor", "no-commented-out-code", "no-dynamic-code-execution", "no-empty-catch", "no-exported-function-expressions", "no-floating-promise", "no-hallucinated-local-imports", "no-hallucinated-package-imports", "no-incorrect-sort", "no-inline-disable", "no-llm-artifacts", "no-magic-numbers", "no-redundant-logic", "no-swallowed-errors", "no-type-assertion-any", "no-unbounded-promise-all", "no-unsafe-array-access", "no-weak-randomness-for-secrets", "prefer-early-return", "prefer-nullish-coalescing", "prefer-unknown-in-catch", "structured-logging", "throw-error-objects", "uninvoked-array-callback"];
43
+ export const ruleNames = ["bad-comparison-sequence", "bad-min-max-func", "consistent-catch-param-name", "explicit-export-types", "filename-match-export", "max-complexity", "max-file-length", "max-function-length", "max-nesting-depth", "max-params", "missing-throw", "naming-conventions", "no-any-in-generic", "no-async-array-callbacks", "no-async-promise-executor", "no-commented-out-code", "no-dynamic-code-execution", "no-empty-catch", "no-exported-function-expressions", "no-floating-promise", "no-hallucinated-local-imports", "no-hallucinated-package-imports", "no-incorrect-sort", "no-inline-disable", "no-llm-artifacts", "no-magic-numbers", "no-redundant-comments", "no-redundant-logic", "no-swallowed-errors", "no-type-assertion-any", "no-unbounded-promise-all", "no-unsafe-array-access", "no-weak-randomness-for-secrets", "prefer-early-return", "prefer-nullish-coalescing", "prefer-unknown-in-catch", "structured-logging", "throw-error-objects", "uninvoked-array-callback"];
43
44
  //# sourceMappingURL=embedded-docs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"embedded-docs.js","sourceRoot":"","sources":["../src/embedded-docs.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,MAAM,CAAC,MAAM,YAAY,GAA2B;IAClD,yBAAyB,EAAE,yyEAAyyE;IACp0E,kBAAkB,EAAE,6oFAA6oF;IACjqF,6BAA6B,EAAE,ipGAAipG;IAChrG,uBAAuB,EAAE,slLAAslL;IAC/mL,uBAAuB,EAAE,8qFAA8qF;IACvsF,gBAAgB,EAAE,8mHAA8mH;IAChoH,iBAAiB,EAAE,wrEAAwrE;IAC3sE,qBAAqB,EAAE,ksEAAksE;IACztE,mBAAmB,EAAE,+qEAA+qE;IACpsE,YAAY,EAAE,i8EAAi8E;IAC/8E,eAAe,EAAE,2vDAA2vD;IAC5wD,oBAAoB,EAAE,0sDAA0sD;IAChuD,mBAAmB,EAAE,srFAAsrF;IAC3sF,0BAA0B,EAAE,yyHAAyyH;IACr0H,2BAA2B,EAAE,ooEAAooE;IACjqE,uBAAuB,EAAE,8kGAA8kG;IACvmG,2BAA2B,EAAE,y/GAAy/G;IACthH,gBAAgB,EAAE,kxFAAkxF;IACpyF,kCAAkC,EAAE,6/HAA6/H;IACjiI,qBAAqB,EAAE,4iHAA4iH;IACnkH,+BAA+B,EAAE,qhFAAqhF;IACtjF,iCAAiC,EAAE,yiKAAyiK;IAC5kK,mBAAmB,EAAE,gwDAAgwD;IACrxD,mBAAmB,EAAE,w7DAAw7D;IAC78D,kBAAkB,EAAE,63HAA63H;IACj5H,kBAAkB,EAAE,o5GAAo5G;IACx6G,oBAAoB,EAAE,g1HAAg1H;IACt2H,qBAAqB,EAAE,kyFAAkyF;IACzzF,uBAAuB,EAAE,oqEAAoqE;IAC7rE,0BAA0B,EAAE,qqHAAqqH;IACjsH,wBAAwB,EAAE,w6GAAw6G;IACl8G,gCAAgC,EAAE,q6IAAq6I;IACv8I,qBAAqB,EAAE,8mGAA8mG;IACroG,2BAA2B,EAAE,kwDAAkwD;IAC/xD,yBAAyB,EAAE,uzEAAuzE;IACl1E,oBAAoB,EAAE,6hGAA6hG;IACnjG,qBAAqB,EAAE,+2EAA+2E;IACt4E,0BAA0B,EAAE,4nGAA4nG;CACzpG,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAa,CAAC,yBAAyB,EAAC,kBAAkB,EAAC,6BAA6B,EAAC,uBAAuB,EAAC,uBAAuB,EAAC,gBAAgB,EAAC,iBAAiB,EAAC,qBAAqB,EAAC,mBAAmB,EAAC,YAAY,EAAC,eAAe,EAAC,oBAAoB,EAAC,mBAAmB,EAAC,0BAA0B,EAAC,2BAA2B,EAAC,uBAAuB,EAAC,2BAA2B,EAAC,gBAAgB,EAAC,kCAAkC,EAAC,qBAAqB,EAAC,+BAA+B,EAAC,iCAAiC,EAAC,mBAAmB,EAAC,mBAAmB,EAAC,kBAAkB,EAAC,kBAAkB,EAAC,oBAAoB,EAAC,qBAAqB,EAAC,uBAAuB,EAAC,0BAA0B,EAAC,wBAAwB,EAAC,gCAAgC,EAAC,qBAAqB,EAAC,2BAA2B,EAAC,yBAAyB,EAAC,oBAAoB,EAAC,qBAAqB,EAAC,0BAA0B,CAAC,CAAC"}
1
+ {"version":3,"file":"embedded-docs.js","sourceRoot":"","sources":["../src/embedded-docs.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,MAAM,CAAC,MAAM,YAAY,GAA2B;IAClD,yBAAyB,EAAE,yyEAAyyE;IACp0E,kBAAkB,EAAE,6oFAA6oF;IACjqF,6BAA6B,EAAE,ipGAAipG;IAChrG,uBAAuB,EAAE,slLAAslL;IAC/mL,uBAAuB,EAAE,8qFAA8qF;IACvsF,gBAAgB,EAAE,8mHAA8mH;IAChoH,iBAAiB,EAAE,wrEAAwrE;IAC3sE,qBAAqB,EAAE,ksEAAksE;IACztE,mBAAmB,EAAE,+qEAA+qE;IACpsE,YAAY,EAAE,i8EAAi8E;IAC/8E,eAAe,EAAE,2vDAA2vD;IAC5wD,oBAAoB,EAAE,0sDAA0sD;IAChuD,mBAAmB,EAAE,srFAAsrF;IAC3sF,0BAA0B,EAAE,yyHAAyyH;IACr0H,2BAA2B,EAAE,ooEAAooE;IACjqE,uBAAuB,EAAE,8kGAA8kG;IACvmG,2BAA2B,EAAE,y/GAAy/G;IACthH,gBAAgB,EAAE,kxFAAkxF;IACpyF,kCAAkC,EAAE,6/HAA6/H;IACjiI,qBAAqB,EAAE,4iHAA4iH;IACnkH,+BAA+B,EAAE,qhFAAqhF;IACtjF,iCAAiC,EAAE,yiKAAyiK;IAC5kK,mBAAmB,EAAE,gwDAAgwD;IACrxD,mBAAmB,EAAE,w7DAAw7D;IAC78D,kBAAkB,EAAE,63HAA63H;IACj5H,kBAAkB,EAAE,o5GAAo5G;IACx6G,uBAAuB,EAAE,w/EAAw/E;IACjhF,oBAAoB,EAAE,g1HAAg1H;IACt2H,qBAAqB,EAAE,kyFAAkyF;IACzzF,uBAAuB,EAAE,oqEAAoqE;IAC7rE,0BAA0B,EAAE,qqHAAqqH;IACjsH,wBAAwB,EAAE,w6GAAw6G;IACl8G,gCAAgC,EAAE,q6IAAq6I;IACv8I,qBAAqB,EAAE,8mGAA8mG;IACroG,2BAA2B,EAAE,kwDAAkwD;IAC/xD,yBAAyB,EAAE,uzEAAuzE;IACl1E,oBAAoB,EAAE,6hGAA6hG;IACnjG,qBAAqB,EAAE,+2EAA+2E;IACt4E,0BAA0B,EAAE,4nGAA4nG;CACzpG,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAa,CAAC,yBAAyB,EAAC,kBAAkB,EAAC,6BAA6B,EAAC,uBAAuB,EAAC,uBAAuB,EAAC,gBAAgB,EAAC,iBAAiB,EAAC,qBAAqB,EAAC,mBAAmB,EAAC,YAAY,EAAC,eAAe,EAAC,oBAAoB,EAAC,mBAAmB,EAAC,0BAA0B,EAAC,2BAA2B,EAAC,uBAAuB,EAAC,2BAA2B,EAAC,gBAAgB,EAAC,kCAAkC,EAAC,qBAAqB,EAAC,+BAA+B,EAAC,iCAAiC,EAAC,mBAAmB,EAAC,mBAAmB,EAAC,kBAAkB,EAAC,kBAAkB,EAAC,uBAAuB,EAAC,oBAAoB,EAAC,qBAAqB,EAAC,uBAAuB,EAAC,0BAA0B,EAAC,wBAAwB,EAAC,gCAAgC,EAAC,qBAAqB,EAAC,2BAA2B,EAAC,yBAAyB,EAAC,oBAAoB,EAAC,qBAAqB,EAAC,0BAA0B,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-llm-core-mcp",
3
- "version": "0.29.0",
3
+ "version": "0.29.1",
4
4
  "description": "MCP server for just-in-time linting guidance from eslint-plugin-llm-core",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "@modelcontextprotocol/sdk": "^1.29.0",
43
43
  "@typescript-eslint/parser": "^8.0.0",
44
44
  "eslint": "^10.1.0",
45
- "eslint-plugin-llm-core": "0.32.0",
45
+ "eslint-plugin-llm-core": "0.33.0",
46
46
  "zod": "^3.23.0"
47
47
  },
48
48
  "devDependencies": {