eslint-plugin-conventions 4.0.0
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.
- package/README.md +80 -0
- package/package.json +55 -0
- package/src/index.d.ts +198 -0
- package/src/index.js +60 -0
- package/src/index.js.map +1 -0
- package/src/lib/eslint-plugin-conventions.d.ts +1 -0
- package/src/lib/eslint-plugin-conventions.js +7 -0
- package/src/lib/eslint-plugin-conventions.js.map +1 -0
- package/src/rules/conventions/consistent-existence-index-check.d.ts +19 -0
- package/src/rules/conventions/consistent-existence-index-check.js +141 -0
- package/src/rules/conventions/consistent-existence-index-check.js.map +1 -0
- package/src/rules/conventions/expiring-todo-comments.d.ts +24 -0
- package/src/rules/conventions/expiring-todo-comments.js +307 -0
- package/src/rules/conventions/expiring-todo-comments.js.map +1 -0
- package/src/rules/conventions/filename-case.d.ts +32 -0
- package/src/rules/conventions/filename-case.js +264 -0
- package/src/rules/conventions/filename-case.js.map +1 -0
- package/src/rules/conventions/no-commented-code.d.ts +26 -0
- package/src/rules/conventions/no-commented-code.js +278 -0
- package/src/rules/conventions/no-commented-code.js.map +1 -0
- package/src/rules/conventions/no-console-spaces.d.ts +13 -0
- package/src/rules/conventions/no-console-spaces.js +128 -0
- package/src/rules/conventions/no-console-spaces.js.map +1 -0
- package/src/rules/conventions/prefer-code-point.d.ts +13 -0
- package/src/rules/conventions/prefer-code-point.js +95 -0
- package/src/rules/conventions/prefer-code-point.js.map +1 -0
- package/src/rules/conventions/prefer-dependency-version-strategy.d.ts +29 -0
- package/src/rules/conventions/prefer-dependency-version-strategy.js +226 -0
- package/src/rules/conventions/prefer-dependency-version-strategy.js.map +1 -0
- package/src/rules/conventions/prefer-dom-node-text-content.d.ts +13 -0
- package/src/rules/conventions/prefer-dom-node-text-content.js +147 -0
- package/src/rules/conventions/prefer-dom-node-text-content.js.map +1 -0
- package/src/rules/deprecation/no-deprecated-api.d.ts +30 -0
- package/src/rules/deprecation/no-deprecated-api.js +174 -0
- package/src/rules/deprecation/no-deprecated-api.js.map +1 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
+
* MIT license that can be found in the LICENSE file.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.preferDependencyVersionStrategy = void 0;
|
|
9
|
+
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
+
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
11
|
+
exports.preferDependencyVersionStrategy = (0, eslint_devkit_2.createRule)({
|
|
12
|
+
name: 'prefer-dependency-version-strategy',
|
|
13
|
+
meta: {
|
|
14
|
+
type: 'suggestion',
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Enforce consistent version strategy (caret, tilde, exact, etc.) for package.json dependencies',
|
|
17
|
+
},
|
|
18
|
+
fixable: 'code',
|
|
19
|
+
messages: {
|
|
20
|
+
preferStrategy: (0, eslint_devkit_1.formatLLMMessage)({
|
|
21
|
+
icon: eslint_devkit_1.MessageIcons.PACKAGE,
|
|
22
|
+
issueName: 'Dependency Version Strategy',
|
|
23
|
+
description: 'Dependency "{{name}}" should use {{strategy}} version',
|
|
24
|
+
severity: 'MEDIUM',
|
|
25
|
+
fix: 'Change "{{current}}" to "{{expected}}" for version flexibility',
|
|
26
|
+
documentationLink: 'https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies',
|
|
27
|
+
}),
|
|
28
|
+
invalidStrategy: (0, eslint_devkit_1.formatLLMMessage)({
|
|
29
|
+
icon: eslint_devkit_1.MessageIcons.WARNING,
|
|
30
|
+
issueName: 'Invalid Version Strategy',
|
|
31
|
+
description: 'Strategy "{{strategy}}" is not valid',
|
|
32
|
+
severity: 'MEDIUM',
|
|
33
|
+
fix: 'Use one of: caret (^), tilde (~), exact (no prefix), range (<, >, ||), or any',
|
|
34
|
+
documentationLink: 'https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies',
|
|
35
|
+
}),
|
|
36
|
+
},
|
|
37
|
+
schema: [
|
|
38
|
+
{
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
strategy: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
enum: ['caret', 'tilde', 'exact', 'range', 'any'],
|
|
44
|
+
description: 'Version strategy to enforce: caret (^), tilde (~), exact (no prefix), range (allows <, >, ||), or any (allows all)',
|
|
45
|
+
},
|
|
46
|
+
allowWorkspace: {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'Allow workspace: protocol versions',
|
|
49
|
+
default: true,
|
|
50
|
+
},
|
|
51
|
+
allowFile: {
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
description: 'Allow file: protocol versions',
|
|
54
|
+
default: true,
|
|
55
|
+
},
|
|
56
|
+
allowLink: {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
description: 'Allow link: protocol versions',
|
|
59
|
+
default: true,
|
|
60
|
+
},
|
|
61
|
+
overrides: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
additionalProperties: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
enum: ['caret', 'tilde', 'exact', 'range', 'any'],
|
|
66
|
+
},
|
|
67
|
+
description: 'Package-specific strategy overrides. Key is package name, value is strategy. Example: { "react": "exact", "lodash": "tilde" }',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
additionalProperties: false,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
defaultOptions: [
|
|
75
|
+
{
|
|
76
|
+
strategy: 'caret',
|
|
77
|
+
allowWorkspace: true,
|
|
78
|
+
allowFile: true,
|
|
79
|
+
allowLink: true,
|
|
80
|
+
overrides: {},
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
create(context) {
|
|
84
|
+
const options = context.options[0] || {};
|
|
85
|
+
const { strategy = 'caret', allowWorkspace = true, allowFile = true, allowLink = true, overrides = {}, } = options;
|
|
86
|
+
// Validate strategy
|
|
87
|
+
const validStrategies = [
|
|
88
|
+
'caret',
|
|
89
|
+
'tilde',
|
|
90
|
+
'exact',
|
|
91
|
+
'range',
|
|
92
|
+
'any',
|
|
93
|
+
];
|
|
94
|
+
if (!validStrategies.includes(strategy)) {
|
|
95
|
+
context.report({
|
|
96
|
+
loc: { line: 1, column: 0 },
|
|
97
|
+
messageId: 'invalidStrategy',
|
|
98
|
+
data: { strategy },
|
|
99
|
+
});
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
// If strategy is 'any', allow all versions
|
|
103
|
+
if (strategy === 'any') {
|
|
104
|
+
return {};
|
|
105
|
+
}
|
|
106
|
+
function checkVersion(node, depName, version) {
|
|
107
|
+
// Skip special protocols
|
|
108
|
+
if (allowWorkspace && version.startsWith('workspace:'))
|
|
109
|
+
return;
|
|
110
|
+
if (allowFile && version.startsWith('file:'))
|
|
111
|
+
return;
|
|
112
|
+
if (allowLink && version.startsWith('link:'))
|
|
113
|
+
return;
|
|
114
|
+
// Skip if not a semantic version (allow prefixes like ^, ~)
|
|
115
|
+
// Match patterns like: 1.0.0, ^1.0.0, ~1.0.0, >=1.0.0, etc.
|
|
116
|
+
if (!version.match(/^[\^~<>=]?\d+\.\d+\.\d+/))
|
|
117
|
+
return;
|
|
118
|
+
// Check for package-specific override
|
|
119
|
+
const packageStrategy = overrides[depName] || strategy;
|
|
120
|
+
// If override is 'any', skip this package
|
|
121
|
+
if (packageStrategy === 'any')
|
|
122
|
+
return;
|
|
123
|
+
let expectedVersion = version;
|
|
124
|
+
let needsFix = false;
|
|
125
|
+
// Determine expected format based on strategy (package override or default)
|
|
126
|
+
// First, extract the base version (remove any existing prefix)
|
|
127
|
+
const baseVersion = version.replace(/^[\^~<>=]+/, '');
|
|
128
|
+
switch (packageStrategy) {
|
|
129
|
+
case 'caret':
|
|
130
|
+
if (!version.startsWith('^')) {
|
|
131
|
+
expectedVersion = `^${baseVersion}`;
|
|
132
|
+
needsFix = true;
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
case 'tilde':
|
|
136
|
+
if (!version.startsWith('~')) {
|
|
137
|
+
expectedVersion = `~${baseVersion}`;
|
|
138
|
+
needsFix = true;
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
case 'exact': {
|
|
142
|
+
// Remove any prefix to get exact version
|
|
143
|
+
if (version !== baseVersion) {
|
|
144
|
+
expectedVersion = baseVersion;
|
|
145
|
+
needsFix = true;
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'range':
|
|
150
|
+
// Allow ranges like ">=1.0.0 <2.0.0" or "1.0.0 || 2.0.0"
|
|
151
|
+
if (!version.includes('||') &&
|
|
152
|
+
!version.includes('>=') &&
|
|
153
|
+
!version.includes('<=') &&
|
|
154
|
+
!version.includes('>') &&
|
|
155
|
+
!version.includes('<') &&
|
|
156
|
+
!version.includes(' - ')) {
|
|
157
|
+
// If it's just a version, suggest caret as default for ranges
|
|
158
|
+
// Use baseVersion to avoid double-prefixing (e.g., ^^18.0.0)
|
|
159
|
+
expectedVersion = `^${baseVersion}`;
|
|
160
|
+
needsFix = true;
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
if (needsFix) {
|
|
165
|
+
context.report({
|
|
166
|
+
node: node.value,
|
|
167
|
+
messageId: 'preferStrategy',
|
|
168
|
+
data: {
|
|
169
|
+
name: depName,
|
|
170
|
+
strategy: packageStrategy,
|
|
171
|
+
current: version,
|
|
172
|
+
expected: expectedVersion,
|
|
173
|
+
},
|
|
174
|
+
fix(fixer) {
|
|
175
|
+
return fixer.replaceText(node.value, JSON.stringify(expectedVersion));
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Check an object expression for dependency version violations
|
|
182
|
+
*/
|
|
183
|
+
const checkObjectExpression = (node) => {
|
|
184
|
+
for (const prop of node.properties) {
|
|
185
|
+
if (prop.type === 'Property' &&
|
|
186
|
+
prop.key &&
|
|
187
|
+
prop.value &&
|
|
188
|
+
prop.value.type === 'Literal') {
|
|
189
|
+
const depName = prop.key.type === 'Identifier'
|
|
190
|
+
? prop.key.name
|
|
191
|
+
: prop.key.type === 'Literal'
|
|
192
|
+
? String(prop.key.value)
|
|
193
|
+
: null;
|
|
194
|
+
if (depName && typeof prop.value.value === 'string') {
|
|
195
|
+
checkVersion(prop, depName, prop.value.value);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
// Check package.json dependencies properties
|
|
202
|
+
'Property[key.value="dependencies"], Property[key.value="devDependencies"], Property[key.value="peerDependencies"]'(node) {
|
|
203
|
+
if (node.value.type !== 'ObjectExpression')
|
|
204
|
+
return;
|
|
205
|
+
checkObjectExpression(node.value);
|
|
206
|
+
},
|
|
207
|
+
// Also check object literals (for testing and general use)
|
|
208
|
+
ObjectExpression(node) {
|
|
209
|
+
// Only check if it looks like a dependencies object (has string keys and version-like values)
|
|
210
|
+
const hasVersionLikeValues = node.properties.some((prop) => {
|
|
211
|
+
if (prop.type === 'Property' && prop.value.type === 'Literal') {
|
|
212
|
+
const value = String(prop.value.value);
|
|
213
|
+
// Check if value looks like a version (starts with ^, ~, or is a semantic version)
|
|
214
|
+
return (/^[\^~]?\d+\.\d+\.\d+/.test(value) ||
|
|
215
|
+
value.startsWith('workspace:'));
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
});
|
|
219
|
+
if (hasVersionLikeValues) {
|
|
220
|
+
checkObjectExpression(node);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=prefer-dependency-version-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-dependency-version-strategy.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-conventions/src/rules/conventions/prefer-dependency-version-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
3
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
4
|
+
* MIT license that can be found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* ESLint Rule: prefer-dom-node-text-content
|
|
8
|
+
* Prefer textContent over innerText for DOM node text access
|
|
9
|
+
*/
|
|
10
|
+
import type { TSESLint } from '@interlace/eslint-devkit';
|
|
11
|
+
export declare const preferDomNodeTextContent: TSESLint.RuleModule<"preferDomNodeTextContent", [], unknown, TSESLint.RuleListener> & {
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
+
* MIT license that can be found in the LICENSE file.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.preferDomNodeTextContent = void 0;
|
|
9
|
+
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
+
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
11
|
+
exports.preferDomNodeTextContent = (0, eslint_devkit_1.createRule)({
|
|
12
|
+
name: 'prefer-dom-node-text-content',
|
|
13
|
+
meta: {
|
|
14
|
+
type: 'suggestion',
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Prefer textContent over innerText for better performance and reliability',
|
|
17
|
+
},
|
|
18
|
+
hasSuggestions: true,
|
|
19
|
+
messages: {
|
|
20
|
+
preferDomNodeTextContent: (0, eslint_devkit_2.formatLLMMessage)({
|
|
21
|
+
icon: eslint_devkit_2.MessageIcons.PERFORMANCE,
|
|
22
|
+
issueName: 'DOM Text Access',
|
|
23
|
+
description: 'Use textContent instead of innerText',
|
|
24
|
+
severity: 'MEDIUM',
|
|
25
|
+
fix: 'Replace innerText with textContent',
|
|
26
|
+
documentationLink: 'https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-text-content.md',
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
schema: [
|
|
30
|
+
{
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: {},
|
|
33
|
+
additionalProperties: false,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
defaultOptions: [],
|
|
38
|
+
create(context) {
|
|
39
|
+
function isInAllowedContext() {
|
|
40
|
+
// For simplicity, we'll skip the allow option for now
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
function isLikelyDomElement(node) {
|
|
44
|
+
const obj = node.object;
|
|
45
|
+
// Check if it's a variable/identifier that might be a DOM element
|
|
46
|
+
if (obj.type === 'Identifier') {
|
|
47
|
+
const name = obj.name;
|
|
48
|
+
// Common DOM element variable names
|
|
49
|
+
if (name.match(/^(element|el|div|span|node|ref|dom|elem)$/i)) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
// Variables that end with common DOM suffixes
|
|
53
|
+
if (name.match(/(Element|Node|Ref)$/)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Check for DOM method calls like document.querySelector, getElementById, etc.
|
|
58
|
+
if (obj.type === 'CallExpression' &&
|
|
59
|
+
obj.callee.type === 'MemberExpression') {
|
|
60
|
+
const methodName = obj.callee.property?.name;
|
|
61
|
+
if (methodName &&
|
|
62
|
+
[
|
|
63
|
+
'querySelector',
|
|
64
|
+
'querySelectorAll',
|
|
65
|
+
'getElementById',
|
|
66
|
+
'getElementsByClassName',
|
|
67
|
+
'getElementsByTagName',
|
|
68
|
+
'createElement',
|
|
69
|
+
].includes(methodName)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Check for property access on known DOM objects
|
|
74
|
+
if (obj.type === 'MemberExpression') {
|
|
75
|
+
const propName = obj.property?.name;
|
|
76
|
+
if (propName &&
|
|
77
|
+
[
|
|
78
|
+
'current',
|
|
79
|
+
'children',
|
|
80
|
+
'childNodes',
|
|
81
|
+
'parentNode',
|
|
82
|
+
'element',
|
|
83
|
+
].includes(propName)) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Check for 'this.element' pattern
|
|
88
|
+
if (obj.type === 'MemberExpression' &&
|
|
89
|
+
obj.object.type === 'ThisExpression' &&
|
|
90
|
+
obj.property.type === 'Identifier' &&
|
|
91
|
+
obj.property.name === 'element') {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function isInnerTextAccess(node) {
|
|
97
|
+
// Check if this is accessing .innerText property
|
|
98
|
+
if (node.property.type === 'Identifier' &&
|
|
99
|
+
node.property.name === 'innerText') {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
// Also check computed property access like element["innerText"]
|
|
103
|
+
if (node.computed &&
|
|
104
|
+
node.property.type === 'Literal' &&
|
|
105
|
+
node.property.value === 'innerText') {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
MemberExpression(node) {
|
|
112
|
+
if (isInnerTextAccess(node) &&
|
|
113
|
+
isLikelyDomElement(node) &&
|
|
114
|
+
!isInAllowedContext()) {
|
|
115
|
+
context.report({
|
|
116
|
+
node,
|
|
117
|
+
messageId: 'preferDomNodeTextContent',
|
|
118
|
+
data: {
|
|
119
|
+
current: 'innerText',
|
|
120
|
+
fix: 'textContent',
|
|
121
|
+
},
|
|
122
|
+
suggest: [
|
|
123
|
+
{
|
|
124
|
+
messageId: 'preferDomNodeTextContent',
|
|
125
|
+
data: {
|
|
126
|
+
replacement: 'textContent',
|
|
127
|
+
suggestion: 'Replace with textContent',
|
|
128
|
+
},
|
|
129
|
+
fix(fixer) {
|
|
130
|
+
if (node.property.type === 'Identifier') {
|
|
131
|
+
return fixer.replaceText(node.property, 'textContent');
|
|
132
|
+
}
|
|
133
|
+
else if (node.property.type === 'Literal' &&
|
|
134
|
+
node.property.value === 'innerText') {
|
|
135
|
+
return fixer.replaceText(node.property, '"textContent"');
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=prefer-dom-node-text-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-dom-node-text-content.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-conventions/src/rules/conventions/prefer-dom-node-text-content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
3
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
4
|
+
* MIT license that can be found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* ESLint Rule: no-deprecated-api
|
|
8
|
+
* Detects deprecated API usage with replacement context and migration timeline
|
|
9
|
+
*/
|
|
10
|
+
import type { TSESLint } from '@interlace/eslint-devkit';
|
|
11
|
+
type MessageIds = 'deprecatedAPI' | 'useReplacement';
|
|
12
|
+
interface DeprecatedAPI {
|
|
13
|
+
name: string;
|
|
14
|
+
replacement: string;
|
|
15
|
+
deprecatedSince: string;
|
|
16
|
+
removalDate?: string;
|
|
17
|
+
reason: string;
|
|
18
|
+
migrationGuide?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface Options {
|
|
21
|
+
/** Array of deprecated APIs to detect */
|
|
22
|
+
apis?: DeprecatedAPI[];
|
|
23
|
+
/** Days before removal date to start warning */
|
|
24
|
+
warnDaysBeforeRemoval?: number;
|
|
25
|
+
}
|
|
26
|
+
type RuleOptions = [Options?];
|
|
27
|
+
export declare const noDeprecatedApi: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
|
|
28
|
+
name: string;
|
|
29
|
+
};
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
+
* MIT license that can be found in the LICENSE file.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.noDeprecatedApi = void 0;
|
|
9
|
+
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
+
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
11
|
+
exports.noDeprecatedApi = (0, eslint_devkit_2.createRule)({
|
|
12
|
+
name: 'no-deprecated-api',
|
|
13
|
+
meta: {
|
|
14
|
+
type: 'problem',
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Prevent usage of deprecated APIs with migration context',
|
|
17
|
+
},
|
|
18
|
+
fixable: 'code',
|
|
19
|
+
hasSuggestions: true,
|
|
20
|
+
messages: {
|
|
21
|
+
// 🎯 Token optimization: 44% reduction (48→27 tokens) - removes verbose labels
|
|
22
|
+
deprecatedAPI: (0, eslint_devkit_1.formatLLMMessage)({
|
|
23
|
+
icon: eslint_devkit_1.MessageIcons.DEPRECATION,
|
|
24
|
+
issueName: 'Deprecated API',
|
|
25
|
+
cwe: 'CWE-1078',
|
|
26
|
+
description: 'Deprecated API detected',
|
|
27
|
+
severity: 'HIGH',
|
|
28
|
+
fix: 'Migrate to recommended alternative with timeline guidance',
|
|
29
|
+
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference',
|
|
30
|
+
}),
|
|
31
|
+
useReplacement: (0, eslint_devkit_1.formatLLMMessage)({
|
|
32
|
+
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
33
|
+
issueName: 'Use Replacement',
|
|
34
|
+
description: 'Replace with recommended API',
|
|
35
|
+
severity: 'LOW',
|
|
36
|
+
fix: 'Replace with {{replacement}}',
|
|
37
|
+
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference',
|
|
38
|
+
}),
|
|
39
|
+
},
|
|
40
|
+
schema: [
|
|
41
|
+
{
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: {
|
|
44
|
+
apis: {
|
|
45
|
+
type: 'array',
|
|
46
|
+
items: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
name: { type: 'string' },
|
|
50
|
+
replacement: { type: 'string' },
|
|
51
|
+
deprecatedSince: { type: 'string' },
|
|
52
|
+
removalDate: { type: 'string' },
|
|
53
|
+
reason: { type: 'string' },
|
|
54
|
+
migrationGuide: { type: 'string' },
|
|
55
|
+
},
|
|
56
|
+
required: ['name', 'replacement', 'deprecatedSince', 'reason'],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
warnDaysBeforeRemoval: {
|
|
60
|
+
type: 'number',
|
|
61
|
+
default: 90,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
defaultOptions: [
|
|
69
|
+
{
|
|
70
|
+
apis: [],
|
|
71
|
+
warnDaysBeforeRemoval: 90,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
create(context) {
|
|
75
|
+
const options = context.options[0] || {};
|
|
76
|
+
const { apis = [], warnDaysBeforeRemoval = 90 } = options || {};
|
|
77
|
+
// Early return if no deprecated APIs configured
|
|
78
|
+
if (!apis || apis.length === 0) {
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Calculate days until removal
|
|
83
|
+
*/
|
|
84
|
+
const calculateDaysRemaining = (removalDate) => {
|
|
85
|
+
if (!removalDate)
|
|
86
|
+
return null;
|
|
87
|
+
const removal = new Date(removalDate);
|
|
88
|
+
const now = new Date();
|
|
89
|
+
const diff = removal.getTime() - now.getTime();
|
|
90
|
+
return Math.ceil(diff / (1000 * 60 * 60 * 24));
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Determine urgency level
|
|
94
|
+
*/
|
|
95
|
+
const getUrgencyLevel = (daysRemaining) => {
|
|
96
|
+
if (daysRemaining === null)
|
|
97
|
+
return 'low';
|
|
98
|
+
if (daysRemaining < 0)
|
|
99
|
+
return 'critical'; // Already past removal date!
|
|
100
|
+
if (daysRemaining < 30)
|
|
101
|
+
return 'critical';
|
|
102
|
+
if (daysRemaining < warnDaysBeforeRemoval)
|
|
103
|
+
return 'high';
|
|
104
|
+
return 'medium';
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
// Check member expressions (e.g., obj.deprecatedMethod())
|
|
108
|
+
MemberExpression(node) {
|
|
109
|
+
if (node.property.type !== 'Identifier')
|
|
110
|
+
return;
|
|
111
|
+
const apiName = node.property.name;
|
|
112
|
+
const deprecatedApi = apis.find((api) => api.name === apiName);
|
|
113
|
+
if (!deprecatedApi)
|
|
114
|
+
return;
|
|
115
|
+
const daysRemaining = calculateDaysRemaining(deprecatedApi.removalDate);
|
|
116
|
+
const urgency = getUrgencyLevel(daysRemaining);
|
|
117
|
+
context.report({
|
|
118
|
+
node,
|
|
119
|
+
messageId: 'deprecatedAPI',
|
|
120
|
+
data: {
|
|
121
|
+
apiName: deprecatedApi.name,
|
|
122
|
+
replacement: deprecatedApi.replacement,
|
|
123
|
+
deprecatedSince: deprecatedApi.deprecatedSince,
|
|
124
|
+
daysRemaining: String(daysRemaining ?? 'Unknown'),
|
|
125
|
+
urgency: urgency.toUpperCase(),
|
|
126
|
+
migrationGuide: deprecatedApi.migrationGuide || 'See documentation',
|
|
127
|
+
},
|
|
128
|
+
suggest: [
|
|
129
|
+
{
|
|
130
|
+
messageId: 'useReplacement',
|
|
131
|
+
data: { replacement: deprecatedApi.replacement },
|
|
132
|
+
fix: (fixer) => {
|
|
133
|
+
return fixer.replaceText(node.property, deprecatedApi.replacement);
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
// Check call expressions (e.g., deprecatedFunction())
|
|
140
|
+
CallExpression(node) {
|
|
141
|
+
if (node.callee.type !== 'Identifier')
|
|
142
|
+
return;
|
|
143
|
+
const apiName = node.callee.name;
|
|
144
|
+
const deprecatedApi = apis.find((api) => api.name === apiName);
|
|
145
|
+
if (!deprecatedApi)
|
|
146
|
+
return;
|
|
147
|
+
const daysRemaining = calculateDaysRemaining(deprecatedApi.removalDate);
|
|
148
|
+
const urgency = getUrgencyLevel(daysRemaining);
|
|
149
|
+
context.report({
|
|
150
|
+
node,
|
|
151
|
+
messageId: 'deprecatedAPI',
|
|
152
|
+
data: {
|
|
153
|
+
apiName: deprecatedApi.name,
|
|
154
|
+
replacement: deprecatedApi.replacement,
|
|
155
|
+
deprecatedSince: deprecatedApi.deprecatedSince,
|
|
156
|
+
daysRemaining: String(daysRemaining ?? 'Unknown'),
|
|
157
|
+
urgency: urgency.toUpperCase(),
|
|
158
|
+
migrationGuide: deprecatedApi.migrationGuide || 'See documentation',
|
|
159
|
+
},
|
|
160
|
+
suggest: [
|
|
161
|
+
{
|
|
162
|
+
messageId: 'useReplacement',
|
|
163
|
+
data: { replacement: deprecatedApi.replacement },
|
|
164
|
+
fix: (fixer) => {
|
|
165
|
+
return fixer.replaceText(node.callee, deprecatedApi.replacement);
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
//# sourceMappingURL=no-deprecated-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-deprecated-api.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-conventions/src/rules/deprecation/no-deprecated-api.ts"],"names":[],"mappings":"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"}
|