Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions docs/rules/no-property-in-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ Instead, checking a node's `type` property is generally considered preferable.

Examples of **incorrect** code for this rule:

```ts
/* eslint eslint-plugin/no-property-in-node: error */

```js
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
Expand All @@ -25,7 +23,7 @@ module.exports = {
return {
'ClassDeclaration, FunctionDeclaration'(node) {
if ('superClass' in node) {
console.log('This is a class declaration:', node);
// This is a class declaration
}
},
};
Expand All @@ -35,9 +33,7 @@ module.exports = {

Examples of **correct** code for this rule:

```ts
/* eslint eslint-plugin/no-property-in-node: error */

```js
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
Expand All @@ -47,7 +43,7 @@ module.exports = {
return {
'ClassDeclaration, FunctionDeclaration'(node) {
if (node.type === 'ClassDeclaration') {
console.log('This is a class declaration:', node);
// This is a class declaration;
}
},
};
Expand Down
21 changes: 15 additions & 6 deletions eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import js from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
import { defineConfig } from 'eslint/config';
import markdown from 'eslint-plugin-markdown';
import pluginN from 'eslint-plugin-n';
import tseslint from 'typescript-eslint';
import eslintPlugin from './lib/index.js';

const dirname = path.dirname(fileURLToPath(import.meta.url));
Expand All @@ -13,14 +13,14 @@ const compat = new FlatCompat({
recommendedConfig: js.configs.recommended,
});

export default defineConfig([
export default tseslint.config([
// Global ignores
{
ignores: ['node_modules', 'coverage', 'dist'],
ignores: ['node_modules', 'coverage', 'dist', 'tests/lib/fixtures'],
},
// Global settings
{
languageOptions: { sourceType: 'module' },
languageOptions: { parser: tseslint.parser, sourceType: 'module' },
},
...compat.extends(
'not-an-aardvark/node',
Expand All @@ -41,11 +41,18 @@ export default defineConfig([
'unicorn/no-null': 'off',
'unicorn/prefer-module': 'off',
'unicorn/prevent-abbreviations': 'off',
'unicorn/no-nested-ternary': 'off',
},
},
// TypeScript rules
tseslint.configs.recommended.map((config) => ({
files: ['**/*.ts', '**/*.mts', '**/*.cts'],
...config,
rules: { ...config.rules, 'n/no-missing-import': 'off' },
})),
{
// Apply eslint-plugin rules to our own rules/tests (but not docs).
files: ['lib/**/*.js', 'tests/**/*.js'],
files: ['lib/**/*.ts', 'tests/**/*.ts'],
plugins: { 'eslint-plugin': eslintPlugin },
rules: {
...eslintPlugin.configs.all.rules,
Expand All @@ -67,12 +74,14 @@ export default defineConfig([
},
{
// Markdown JS code samples in documentation:
files: ['**/*.md/*.js'],
files: ['**/*.md/*.js', '**/*.md/*.ts'],
plugins: { markdown },
linterOptions: { noInlineConfig: true },
rules: {
'no-undef': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'off',

strict: 'off',

'@eslint-community/eslint-comments/require-description': 'off',
Expand Down
20 changes: 5 additions & 15 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,14 @@ import testCaseShorthandStrings from './rules/test-case-shorthand-strings.js';

const require = createRequire(import.meta.url);

const packageMetadata = require("../package.json") as {
name: string;
version: string;
const packageMetadata = require('../package.json') as {
name: string;
version: string;
};

const PLUGIN_NAME = packageMetadata.name.replace(/^eslint-plugin-/, '');
const CONFIG_NAMES = [
'all',
'all-type-checked',
'recommended',
'rules',
'tests',
'rules-recommended',
'tests-recommended',
] as const;
type ConfigName = (typeof CONFIG_NAMES)[number];

const configFilters: Record<ConfigName, (rule: Rule.RuleModule) => boolean> = {
const configFilters: Record<string, (rule: Rule.RuleModule) => boolean> = {
all: (rule: Rule.RuleModule) =>
!(
rule.meta?.docs &&
Expand All @@ -75,7 +65,7 @@ const configFilters: Record<ConfigName, (rule: Rule.RuleModule) => boolean> = {
configFilters.recommended(rule) && configFilters.tests(rule),
};

const createConfig = (configName: ConfigName): Linter.Config => ({
const createConfig = (configName: string): Linter.Config => ({
name: `${PLUGIN_NAME}/${configName}`,
plugins: {
get [PLUGIN_NAME](): ESLint.Plugin {
Expand Down
9 changes: 3 additions & 6 deletions lib/rules/no-meta-schema-default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,9 @@ const rule: Rule.RuleModule = {

case 'properties': {
if ('properties' in value && Array.isArray(value.properties)) {
for (const property of value.properties) {
if (
'value' in property &&
property.value.type === 'ObjectExpression'
) {
checkSchemaElement(property.value);
for (const prop of value.properties) {
if ('value' in prop && prop.value.type === 'ObjectExpression') {
checkSchemaElement(prop.value);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-missing-message-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const rule: Rule.RuleModule = {
collectReportViolationAndSuggestionData(reportInfo);
for (const messageId of reportMessagesAndDataArray
.map((obj) => obj.messageId)
.filter((messageId) => !!messageId)) {
.filter((id) => !!id)) {
const values =
messageId.type === 'Literal'
? [messageId]
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-missing-placeholders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const rule: Rule.RuleModule = {
let match: RegExpExecArray | null;

const messageText: string =
// @ts-expect-error
// @ts-expect-error -- Property 'value' does not exist on type 'ArrayExpression'.ts(2339)
message.value || messageStaticValue.value;
while ((match = PLACEHOLDER_MATCHER.exec(messageText))) {
const matchingProperty =
Expand Down
12 changes: 8 additions & 4 deletions lib/rules/no-only-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,19 @@ const rule: Rule.RuleModule = {
sourceCode.getTokenBefore(onlyProperty);
const tokenAfter =
sourceCode.getTokenAfter(onlyProperty);
if ((tokenBefore && tokenAfter) &&
if (
tokenBefore &&
tokenAfter &&
((isCommaToken(tokenBefore) &&
isCommaToken(tokenAfter)) || // In middle of properties
(isOpeningBraceToken(tokenBefore) &&
isCommaToken(tokenAfter))) // At beginning of properties
(isOpeningBraceToken(tokenBefore) &&
isCommaToken(tokenAfter))) // At beginning of properties
) {
yield fixer.remove(tokenAfter); // Remove extra comma.
}
if ((tokenBefore && tokenAfter) &&
if (
tokenBefore &&
tokenAfter &&
isCommaToken(tokenBefore) &&
isClosingBraceToken(tokenAfter)
) {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-unused-message-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const rule: Rule.RuleModule = {
collectReportViolationAndSuggestionData(reportInfo);
for (const messageId of reportMessagesAndDataArray
.map((obj) => obj.messageId)
.filter((messageId) => !!messageId)) {
.filter((id) => !!id)) {
const values =
messageId.type === 'Literal'
? [messageId]
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-unused-placeholders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const rule: Rule.RuleModule = {
data.type === 'ObjectExpression'
) {
const messageValue: string =
// @ts-expect-error
// @ts-expect-error -- Property 'value' does not exist on type 'SimpleCallExpression'.ts(2339)
message.value || messageStaticValue.value;
// https://github.com/eslint/eslint/blob/2874d75ed8decf363006db25aac2d5f8991bd969/lib/linter.js#L986
const PLACEHOLDER_MATCHER = /{{\s*([^{}]+?)\s*}}/g;
Expand Down
9 changes: 1 addition & 8 deletions lib/rules/no-useless-token-range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,7 @@
* @author Teddy Katz
*/
import type { Rule } from 'eslint';
import type {
CallExpression,
Expression,
MemberExpression,
Node,
Property,
SpreadElement,
} from 'estree';
import type { Expression, MemberExpression, SpreadElement } from 'estree';

import { getKeyName, getSourceCodeIdentifiers } from '../utils.js';

Expand Down
5 changes: 3 additions & 2 deletions lib/rules/require-meta-default-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const rule: Rule.RuleModule = {
}

if (!metaDefaultOptions) {
metaNode &&
if (metaNode) {
context.report({
node: metaNode,
messageId: 'missingDefaultOptions',
Expand All @@ -78,6 +78,7 @@ const rule: Rule.RuleModule = {
);
},
});
}
return {};
}

Expand All @@ -93,7 +94,7 @@ const rule: Rule.RuleModule = {
schemaProperty.type === 'ObjectExpression' &&
schemaProperty.properties
.filter((property) => property.type === 'Property')
// @ts-expect-error
// @ts-expect-error -- Property 'name' does not exist on type 'ArrayExpression'.ts(2339)
.find((property) => property.key.name === 'type')?.value.value ===
'array';

Expand Down
2 changes: 1 addition & 1 deletion lib/rules/require-meta-docs-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const rule: Rule.RuleModule = {
// eslint-disable-next-line unicorn/no-negated-condition -- actually more clear like this
messageId: !urlPropNode
? 'missing'
: // eslint-disable-next-line unicorn/no-nested-ternary,unicorn/no-negated-condition -- this is fine for now
: // eslint-disable-next-line unicorn/no-negated-condition -- this is fine for now
!expectedUrl
? 'wrongType'
: /* otherwise */ 'mismatch',
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/require-meta-schema-description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const rule: Rule.RuleModule = {
continue;
}

// @ts-expect-error
// @ts-expect-error == Property 'name' does not exist on type 'ClassExpression'.ts(2339)
switch (key.name ?? key.value) {
case 'description': {
hadDescription = true;
Expand Down
19 changes: 12 additions & 7 deletions lib/rules/test-case-shorthand-strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,24 +79,29 @@ const rule: Rule.RuleModule = {

let caseInfoFilter: (caseInfo: (typeof caseInfoList)[number]) => boolean;
switch (shorthandOption) {
case 'as-needed':
case 'as-needed': {
caseInfoFilter = (caseInfo) =>
!caseInfo.shorthand && !caseInfo.needsLongform;
break;
case 'never':
}
case 'never': {
caseInfoFilter = (caseInfo) => caseInfo.shorthand;
break;
case 'consistent':
}
case 'consistent': {
caseInfoFilter = isConsistent
? () => false
: (caseInfo) => caseInfo.shorthand;
break;
case 'consistent-as-needed':
}
case 'consistent-as-needed': {
caseInfoFilter = (caseInfo) =>
caseInfo.shorthand === hasCaseNeedingLongform;
break;
default:
return; // invalid option
}
default: {
return;
} // invalid option
}

caseInfoList.filter(caseInfoFilter).forEach((badCaseInfo) => {
Expand All @@ -112,7 +117,7 @@ const rule: Rule.RuleModule = {
badCaseInfo.node,
badCaseInfo.shorthand
? `{code: ${sourceCode.getText(badCaseInfo.node)}}`
: // @ts-expect-error
: // @ts-expect-error -- Property 'properties' does not exist on type 'SimpleLiteral'.ts(2339)
sourceCode.getText(badCaseInfo.node.properties[0].value),
);
},
Expand Down
3 changes: 1 addition & 2 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import type {
Identifier,
MaybeNamedClassDeclaration,
MaybeNamedFunctionDeclaration,
MemberExpression,
ModuleDeclaration,
Node,
ObjectExpression,
Expand Down Expand Up @@ -359,7 +358,7 @@ function getRuleExportsCJS(
*/
function findObjectPropertyValueByKeyName(
obj: ObjectExpression,
keyName: String,
keyName: string,
): Property['value'] | undefined {
const property = obj.properties.find(
(prop) =>
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"@types/estree": "^1.0.8",
"@types/lodash": "^4.17.18",
"@types/node": "^20.19.0",
"@typescript-eslint/parser": "^8.38.0",
"@typescript-eslint/utils": "^8.38.0",
"@typescript-eslint/parser": "^8.39.0",
"@typescript-eslint/utils": "^8.39.0",
"@vitest/coverage-istanbul": "^3.2.4",
"eslint": "^9.31.0",
"eslint-config-not-an-aardvark": "^2.1.0",
Expand All @@ -83,6 +83,7 @@
"release-it": "^17.2.0",
"tsup": "^8.5.0",
"typescript": "^5.9.2",
"typescript-eslint": "^8.39.0",
"vitest": "^3.2.4"
},
"peerDependencies": {
Expand Down
10 changes: 8 additions & 2 deletions tests/lib/rule-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('rule setup is correct', () => {
const file = readFileSync(filePath, 'utf8');

assert.ok(
file.includes("const rule: Rule.RuleModule"),
file.includes('const rule: Rule.RuleModule'),
'is defined as type RuleModule',
);
});
Expand All @@ -68,7 +68,13 @@ describe('rule setup is correct', () => {
});

it('should have documentation for all rules', () => {
const filePath = path.join(import.meta.dirname, '..', '..', 'docs', 'rules');
const filePath = path.join(
import.meta.dirname,
'..',
'..',
'docs',
'rules',
);
const files = readdirSync(filePath);

assert.deepStrictEqual(
Expand Down
Loading