eslint-plugin-conventions 4.2.2 → 4.2.4

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.
Files changed (56) hide show
  1. package/package.json +19 -19
  2. package/src/index.d.ts +15 -173
  3. package/src/index.js +1 -8
  4. package/src/lib/eslint-plugin-conventions.js +0 -1
  5. package/src/oxlint.d.ts +17 -20
  6. package/src/oxlint.js +0 -19
  7. package/src/rules/conventions/analytics-event-naming.js +0 -11
  8. package/src/rules/conventions/consistent-existence-index-check.js +0 -15
  9. package/src/rules/conventions/expiring-todo-comments.js +2 -35
  10. package/src/rules/conventions/filename-case.js +1 -40
  11. package/src/rules/conventions/no-commented-code.js +1 -43
  12. package/src/rules/conventions/no-console-spaces.js +0 -20
  13. package/src/rules/conventions/no-json-schema-tags.js +1 -28
  14. package/src/rules/conventions/no-magic-numbers.js +1 -21
  15. package/src/rules/conventions/no-raw-cross-property-href.js +0 -10
  16. package/src/rules/conventions/prefer-code-point.js +0 -18
  17. package/src/rules/conventions/prefer-dependency-version-strategy.js +0 -26
  18. package/src/rules/conventions/prefer-dom-node-text-content.js +0 -20
  19. package/src/rules/conventions/require-data-testid.js +1 -31
  20. package/src/rules/conventions/utm-taxonomy.js +0 -11
  21. package/src/rules/deprecation/no-deprecated-api.js +1 -19
  22. package/CHANGELOG.md +0 -164
  23. package/src/index.js.map +0 -1
  24. package/src/lib/eslint-plugin-conventions.d.ts +0 -1
  25. package/src/lib/eslint-plugin-conventions.js.map +0 -1
  26. package/src/oxlint.js.map +0 -1
  27. package/src/rules/conventions/analytics-event-naming.d.ts +0 -41
  28. package/src/rules/conventions/analytics-event-naming.js.map +0 -1
  29. package/src/rules/conventions/consistent-existence-index-check.d.ts +0 -19
  30. package/src/rules/conventions/consistent-existence-index-check.js.map +0 -1
  31. package/src/rules/conventions/expiring-todo-comments.d.ts +0 -65
  32. package/src/rules/conventions/expiring-todo-comments.js.map +0 -1
  33. package/src/rules/conventions/filename-case.d.ts +0 -32
  34. package/src/rules/conventions/filename-case.js.map +0 -1
  35. package/src/rules/conventions/no-commented-code.d.ts +0 -26
  36. package/src/rules/conventions/no-commented-code.js.map +0 -1
  37. package/src/rules/conventions/no-console-spaces.d.ts +0 -13
  38. package/src/rules/conventions/no-console-spaces.js.map +0 -1
  39. package/src/rules/conventions/no-json-schema-tags.d.ts +0 -29
  40. package/src/rules/conventions/no-json-schema-tags.js.map +0 -1
  41. package/src/rules/conventions/no-magic-numbers.d.ts +0 -41
  42. package/src/rules/conventions/no-magic-numbers.js.map +0 -1
  43. package/src/rules/conventions/no-raw-cross-property-href.d.ts +0 -24
  44. package/src/rules/conventions/no-raw-cross-property-href.js.map +0 -1
  45. package/src/rules/conventions/prefer-code-point.d.ts +0 -13
  46. package/src/rules/conventions/prefer-code-point.js.map +0 -1
  47. package/src/rules/conventions/prefer-dependency-version-strategy.d.ts +0 -29
  48. package/src/rules/conventions/prefer-dependency-version-strategy.js.map +0 -1
  49. package/src/rules/conventions/prefer-dom-node-text-content.d.ts +0 -13
  50. package/src/rules/conventions/prefer-dom-node-text-content.js.map +0 -1
  51. package/src/rules/conventions/require-data-testid.d.ts +0 -56
  52. package/src/rules/conventions/require-data-testid.js.map +0 -1
  53. package/src/rules/conventions/utm-taxonomy.d.ts +0 -25
  54. package/src/rules/conventions/utm-taxonomy.js.map +0 -1
  55. package/src/rules/deprecation/no-deprecated-api.d.ts +0 -30
  56. package/src/rules/deprecation/no-deprecated-api.js.map +0 -1
@@ -1,17 +1,9 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.filenameCase = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
5
  const eslint_devkit_2 = require("@interlace/eslint-devkit");
11
6
  const eslint_devkit_3 = require("@interlace/eslint-devkit");
12
- /**
13
- * Default uppercase filenames that are conventionally valid across all case conventions
14
- */
15
7
  const DEFAULT_ALLOWED_UPPERCASE_FILES = [
16
8
  'README',
17
9
  'LICENSE',
@@ -108,12 +100,9 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
108
100
  create(context) {
109
101
  const [options] = context.options;
110
102
  const { case: caseType = 'kebabCase', ignore = [], allowedUppercaseFiles = DEFAULT_ALLOWED_UPPERCASE_FILES, allowedKebabCase = [], allowedSnakeCase = [], allowedCamelCase = [], allowedPascalCase = [], } = options || {};
111
- // Convert to different case formats
112
- // oxlint-disable-next-line consistent-function-scoping
113
103
  function toCamelCase(str) {
114
104
  return str.replace(/[-_](.)/g, (_, letter) => letter.toUpperCase());
115
105
  }
116
- // oxlint-disable-next-line consistent-function-scoping
117
106
  function toKebabCase(str) {
118
107
  return str
119
108
  .replace(/([a-z])([A-Z])/g, '$1-$2')
@@ -124,32 +113,22 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
124
113
  const camel = toCamelCase(str);
125
114
  return camel.charAt(0).toUpperCase() + camel.slice(1);
126
115
  }
127
- // oxlint-disable-next-line consistent-function-scoping
128
116
  function toSnakeCase(str) {
129
117
  return str
130
118
  .replace(/([a-z])([A-Z])/g, '$1_$2')
131
119
  .replace(/[\s-]+/g, '_')
132
120
  .toLowerCase();
133
121
  }
134
- // Check if filename matches the expected case pattern
135
- // oxlint-disable-next-line consistent-function-scoping
136
122
  function isCamelCase(str) {
137
- // camelCase: starts with lowercase, no separators, can have uppercase after first char
138
123
  return /^[a-z][a-zA-Z0-9]*$/.test(str);
139
124
  }
140
- // oxlint-disable-next-line consistent-function-scoping
141
125
  function isKebabCase(str) {
142
- // kebab-case: all lowercase with hyphens as separators
143
126
  return /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(str);
144
127
  }
145
- // oxlint-disable-next-line consistent-function-scoping
146
128
  function isPascalCase(str) {
147
- // PascalCase: starts with uppercase, no separators
148
129
  return /^[A-Z][a-zA-Z0-9]*$/.test(str);
149
130
  }
150
- // oxlint-disable-next-line consistent-function-scoping
151
131
  function isSnakeCase(str) {
152
- // snake_case: all lowercase with underscores as separators
153
132
  return /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/.test(str);
154
133
  }
155
134
  function matchesCase(str, expectedCase) {
@@ -166,11 +145,7 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
166
145
  return true;
167
146
  }
168
147
  }
169
- // Generate suggested filename
170
148
  function getSuggestedName(basename, nameWithoutExt, targetCase) {
171
- // Initialized to the untransformed name; every valid CaseType below
172
- // overwrites it. (An unknown case never reaches here — matchesCase
173
- // returns true for unknown cases, so no rename is ever suggested.)
174
149
  let transformed = nameWithoutExt;
175
150
  switch (targetCase) {
176
151
  case 'camelCase':
@@ -186,26 +161,20 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
186
161
  transformed = toSnakeCase(nameWithoutExt);
187
162
  break;
188
163
  }
189
- // Add back the extension
190
164
  const ext = basename.slice(nameWithoutExt.length);
191
165
  return transformed + ext;
192
166
  }
193
167
  return {
194
168
  Program(node) {
195
- // Get filename from context
196
169
  const filename = context.filename;
197
170
  if (!filename) {
198
171
  return;
199
172
  }
200
- // Get just the filename part (without directory)
201
173
  const basename = (0, eslint_devkit_3.getBasename)(filename);
202
- // Remove all extensions for checking (handles .spec.ts, .test.tsx, etc.)
203
174
  const nameWithoutExt = basename.replace(/(\.(spec|test|stories|story|e2e|d))*\.[^.]+$/, '');
204
- // Skip if no name part (e.g., just extension or dotfile)
205
175
  if (!nameWithoutExt) {
206
176
  return;
207
177
  }
208
- // Check if filename should be ignored
209
178
  for (const ignorePattern of ignore) {
210
179
  if (typeof ignorePattern === 'string') {
211
180
  if (basename === ignorePattern) {
@@ -218,16 +187,12 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
218
187
  }
219
188
  }
220
189
  }
221
- // Skip allowed uppercase files (README, LICENSE, etc.) as they are conventionally valid
222
190
  if (allowedUppercaseFiles.includes(nameWithoutExt)) {
223
191
  return;
224
192
  }
225
- // Skip dotfiles (.eslintrc, .gitignore, etc.)
226
193
  if (basename.startsWith('.')) {
227
194
  return;
228
195
  }
229
- // Check if filename is allowed via case-specific overrides
230
- // These allow specific files to use a different case than the global setting
231
196
  if (allowedKebabCase.includes(nameWithoutExt) && matchesCase(nameWithoutExt, 'kebabCase')) {
232
197
  return;
233
198
  }
@@ -240,11 +205,10 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
240
205
  if (allowedPascalCase.includes(nameWithoutExt) && matchesCase(nameWithoutExt, 'pascalCase')) {
241
206
  return;
242
207
  }
243
- // Check if filename matches the expected case
244
208
  if (!matchesCase(nameWithoutExt, caseType)) {
245
209
  const suggestedName = getSuggestedName(basename, nameWithoutExt, caseType);
246
210
  context.report({
247
- node, // Report on the Program node
211
+ node,
248
212
  messageId: 'filenameCase',
249
213
  data: {
250
214
  case: caseType,
@@ -258,8 +222,6 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
258
222
  suggestedName,
259
223
  },
260
224
  fix() {
261
- // This is a file rename operation that can't be auto-fixed
262
- // Just provide the suggestion
263
225
  return null;
264
226
  },
265
227
  },
@@ -270,4 +232,3 @@ exports.filenameCase = (0, eslint_devkit_1.createRule)({
270
232
  };
271
233
  },
272
234
  });
273
- //# sourceMappingURL=filename-case.js.map
@@ -1,36 +1,23 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noCommentedCode = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
5
  const eslint_devkit_2 = require("@interlace/eslint-devkit");
11
- /**
12
- * Check if a comment block contains code-like patterns
13
- */
14
6
  function looksLikeCode(comment, isBlockComment) {
15
- // Remove comment markers for pattern matching
16
7
  let text = comment;
17
8
  if (isBlockComment) {
18
- // Remove /* and */ markers and any leading * on each line
19
9
  text = text.replace(/^\s*\/\*+/, '').replace(/\*+\/\s*$/, '');
20
- // Remove leading * from each line in block comments
21
10
  text = text
22
11
  .split('\n')
23
12
  .map((line) => line.replace(/^\s*\*+\s*/, ''))
24
13
  .join('\n');
25
14
  }
26
15
  else {
27
- // Remove // markers
28
16
  text = text
29
17
  .split('\n')
30
18
  .map((line) => line.replace(/^\s*\/\/+\s*/, ''))
31
19
  .join('\n');
32
20
  }
33
- // Split into lines and check each line
34
21
  const lines = text
35
22
  .split('\n')
36
23
  .map((line) => line.trim())
@@ -44,36 +31,24 @@ function looksLikeCode(comment, isBlockComment) {
44
31
  /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/,
45
32
  /^[{}[\]]/,
46
33
  ];
47
- // Count how many lines look like code
48
34
  let codeLikeLines = 0;
49
- // Check if any line looks like code (but not a TODO comment)
50
35
  for (const line of lines) {
51
- // Skip TODO/FIXME comments
52
36
  if (/^(TODO|FIXME|HACK|XXX)/i.test(line)) {
53
37
  continue;
54
38
  }
55
- // Check if line matches code patterns
56
39
  for (const pattern of codePatterns) {
57
40
  if (pattern.test(line)) {
58
41
  codeLikeLines++;
59
- break; // Count each line only once
42
+ break;
60
43
  }
61
44
  }
62
45
  }
63
- // Consider it code if at least one line looks like code
64
46
  return codeLikeLines > 0;
65
47
  }
66
- /**
67
- * Count lines in a comment
68
- * For single-line comments, the value doesn't include newlines, so we count 1
69
- * For multi-line comments, we count the newlines in the value + 1
70
- */
71
48
  function countCommentLines(comment) {
72
49
  if (!comment)
73
50
  return 0;
74
51
  const newlineCount = (comment.match(/\n/g) || []).length;
75
- // If there are newlines, it's a multi-line comment (newlineCount + 1 lines)
76
- // If no newlines, it's a single-line comment (1 line)
77
52
  return newlineCount > 0 ? newlineCount + 1 : 1;
78
53
  }
79
54
  exports.noCommentedCode = (0, eslint_devkit_2.createRule)({
@@ -151,23 +126,17 @@ exports.noCommentedCode = (0, eslint_devkit_2.createRule)({
151
126
  return {};
152
127
  }
153
128
  const sourceCode = context.sourceCode;
154
- /**
155
- * Check comment nodes
156
- */
157
129
  function checkComment(node) {
158
130
  try {
159
131
  const commentText = node.value || '';
160
132
  const isBlockComment = node.type === 'Block';
161
133
  const lines = countCommentLines(commentText);
162
- // Skip single-line comments if configured
163
134
  if (ignoreSingleLine && lines === 1 && !isBlockComment) {
164
135
  return;
165
136
  }
166
- // Skip if below minimum lines
167
137
  if (lines < minLines) {
168
138
  return;
169
139
  }
170
- // Check if it looks like code
171
140
  if (looksLikeCode(commentText, isBlockComment)) {
172
141
  context.report({
173
142
  node,
@@ -180,7 +149,6 @@ exports.noCommentedCode = (0, eslint_devkit_2.createRule)({
180
149
  messageId: 'removeCode',
181
150
  fix: (fixer) => {
182
151
  try {
183
- // Remove the entire comment
184
152
  return fixer.remove(node);
185
153
  }
186
154
  catch {
@@ -197,44 +165,36 @@ exports.noCommentedCode = (0, eslint_devkit_2.createRule)({
197
165
  }
198
166
  }
199
167
  catch {
200
- // Silently skip if there's an error processing the comment
201
168
  return;
202
169
  }
203
170
  }
204
171
  return {
205
172
  Program() {
206
173
  const comments = sourceCode.getAllComments();
207
- // Group consecutive comments that look like code
208
174
  const groupedComments = [];
209
175
  let currentGroup = [];
210
176
  for (let i = 0; i < comments.length; i++) {
211
177
  const comment = comments[i];
212
178
  const commentText = comment.value || '';
213
179
  const isBlockComment = comment.type === 'Block';
214
- // Check if this comment looks like code
215
180
  if (looksLikeCode(commentText, isBlockComment)) {
216
181
  currentGroup.push(comment);
217
182
  }
218
183
  else {
219
- // If current group has comments, add it to grouped comments
220
184
  if (currentGroup.length > 0) {
221
185
  groupedComments.push([...currentGroup]);
222
186
  currentGroup = [];
223
187
  }
224
188
  }
225
189
  }
226
- // Handle any remaining group
227
190
  if (currentGroup.length > 0) {
228
191
  groupedComments.push(currentGroup);
229
192
  }
230
- // Process each group
231
193
  groupedComments.forEach((group) => {
232
194
  if (group.length === 1) {
233
- // Single comment - use the standard checkComment function
234
195
  checkComment(group[0]);
235
196
  }
236
197
  else {
237
- // Multiple consecutive comments - report as one error
238
198
  const firstComment = group[0];
239
199
  const totalLines = group.reduce((sum, comment) => {
240
200
  const commentText = comment.value || '';
@@ -252,7 +212,6 @@ exports.noCommentedCode = (0, eslint_devkit_2.createRule)({
252
212
  messageId: 'removeCode',
253
213
  fix: (fixer) => {
254
214
  try {
255
- // Remove the entire range of consecutive comments
256
215
  return fixer.removeRange([
257
216
  group[0].range[0],
258
217
  group[group.length - 1].range[1],
@@ -276,4 +235,3 @@ exports.noCommentedCode = (0, eslint_devkit_2.createRule)({
276
235
  };
277
236
  },
278
237
  });
279
- //# sourceMappingURL=no-commented-code.js.map
@@ -1,9 +1,4 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noConsoleSpaces = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
@@ -32,7 +27,6 @@ exports.noConsoleSpaces = (0, eslint_devkit_1.createRule)({
32
27
  },
33
28
  defaultOptions: [],
34
29
  create(context) {
35
- // Console methods that join parameters with spaces
36
30
  const consoleMethods = new Set([
37
31
  'log',
38
32
  'debug',
@@ -44,13 +38,10 @@ exports.noConsoleSpaces = (0, eslint_devkit_1.createRule)({
44
38
  'group',
45
39
  'groupCollapsed',
46
40
  ]);
47
- // oxlint-disable-next-line consistent-function-scoping
48
41
  function isInAllowedContext() {
49
- // For simplicity, we'll skip the allow option for now
50
42
  return false;
51
43
  }
52
44
  function isConsoleMethodCall(node) {
53
- // Check if this is a call to a console method
54
45
  if (node.callee.type === 'MemberExpression' &&
55
46
  node.callee.object.type === 'Identifier' &&
56
47
  node.callee.object.name === 'console' &&
@@ -60,31 +51,23 @@ exports.noConsoleSpaces = (0, eslint_devkit_1.createRule)({
60
51
  }
61
52
  return false;
62
53
  }
63
- // oxlint-disable-next-line consistent-function-scoping
64
54
  function getConsoleMethodName(node) {
65
- // Safe extraction of console method name
66
55
  if (node.callee.type === 'MemberExpression' &&
67
56
  node.callee.property.type === 'Identifier') {
68
57
  return node.callee.property.name;
69
58
  }
70
59
  return 'console';
71
60
  }
72
- // oxlint-disable-next-line consistent-function-scoping
73
61
  function hasLeadingOrTrailingSpaces(text) {
74
- // Check if string starts or ends with whitespace, but not if it's only whitespace
75
- // Only flag if there's actual content with leading/trailing spaces
76
62
  const trimmed = text.trim();
77
63
  return trimmed.length > 0 && /^\s|\s$/.test(text);
78
64
  }
79
- // oxlint-disable-next-line consistent-function-scoping
80
65
  function hasLeadingOrTrailingSpacesInTemplate(text) {
81
- // For template literals, even whitespace-only quasis should be flagged
82
66
  return /^\s|\s$/.test(text);
83
67
  }
84
68
  return {
85
69
  CallExpression(node) {
86
70
  if (isConsoleMethodCall(node) && !isInAllowedContext()) {
87
- // Check each argument for leading/trailing spaces
88
71
  for (const arg of node.arguments) {
89
72
  if (arg.type === 'Literal' && typeof arg.value === 'string') {
90
73
  if (hasLeadingOrTrailingSpaces(arg.value)) {
@@ -103,7 +86,6 @@ exports.noConsoleSpaces = (0, eslint_devkit_1.createRule)({
103
86
  }
104
87
  }
105
88
  else if (arg.type === 'TemplateLiteral') {
106
- // Check template literal quasi values for leading/trailing spaces
107
89
  let hasSpacesInTemplate = false;
108
90
  for (const quasi of arg.quasis) {
109
91
  if (hasLeadingOrTrailingSpacesInTemplate(quasi.value.raw)) {
@@ -119,7 +101,6 @@ exports.noConsoleSpaces = (0, eslint_devkit_1.createRule)({
119
101
  method: getConsoleMethodName(node),
120
102
  arg: 'template literal with spaces',
121
103
  },
122
- // Template literals are harder to fix automatically
123
104
  fix: null,
124
105
  });
125
106
  }
@@ -130,4 +111,3 @@ exports.noConsoleSpaces = (0, eslint_devkit_1.createRule)({
130
111
  };
131
112
  },
132
113
  });
133
- //# sourceMappingURL=no-console-spaces.js.map
@@ -1,17 +1,7 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noJsonSchemaTags = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
- /**
11
- * JSON Schema keywords that are commonly misused as JSDoc tags.
12
- * These have precise semantics in JSON Schema but are invalid
13
- * (or meaningless) in a JSDoc context.
14
- */
15
5
  const DEFAULT_FORBIDDEN_TAGS = new Set([
16
6
  'minimum',
17
7
  'maximum',
@@ -32,13 +22,8 @@ const DEFAULT_FORBIDDEN_TAGS = new Set([
32
22
  'contentMediaType',
33
23
  'contentEncoding',
34
24
  ]);
35
- /**
36
- * Parse a block comment to find `@tagName` occurrences and their positions.
37
- */
38
25
  function findForbiddenTags(commentText, forbiddenSet) {
39
26
  const results = [];
40
- // Match @tagName patterns. We don't anchor at line start because block
41
- // comments can have `* @tag …` or simply `@tag …` on any line.
42
27
  const tagRegex = /@([a-zA-Z][a-zA-Z0-9]*)\b/g;
43
28
  let match;
44
29
  while ((match = tagRegex.exec(commentText)) !== null) {
@@ -49,10 +34,6 @@ function findForbiddenTags(commentText, forbiddenSet) {
49
34
  }
50
35
  return results;
51
36
  }
52
- /**
53
- * Build a human-readable suggestion for how to express the constraint
54
- * in description text instead of a JSON Schema tag.
55
- */
56
37
  function getSuggestionText(tag) {
57
38
  const suggestions = {
58
39
  minimum: 'Include range in description, e.g. "(min: 1)" or "Range: 1-100"',
@@ -116,7 +97,6 @@ exports.noJsonSchemaTags = (0, eslint_devkit_1.createRule)({
116
97
  defaultOptions: [{ additionalForbiddenTags: [] }],
117
98
  create(context, [options = {}]) {
118
99
  const { additionalForbiddenTags = [] } = options;
119
- // Build the full set of forbidden tags
120
100
  const forbiddenTags = new Set(DEFAULT_FORBIDDEN_TAGS);
121
101
  for (const tag of additionalForbiddenTags) {
122
102
  forbiddenTags.add(tag);
@@ -126,20 +106,17 @@ exports.noJsonSchemaTags = (0, eslint_devkit_1.createRule)({
126
106
  Program() {
127
107
  const comments = sourceCode.getAllComments();
128
108
  for (const comment of comments) {
129
- // Only inspect block comments (JSDoc is always /* … */)
130
109
  if (comment.type !== 'Block') {
131
110
  continue;
132
111
  }
133
112
  const commentText = comment.value;
134
113
  const hits = findForbiddenTags(commentText, forbiddenTags);
135
114
  for (const { tag, offset } of hits) {
136
- // Compute absolute source position.
137
- // comment.range[0] → opening `/*`, content starts at +2.
138
115
  const absoluteStart = comment
139
116
  .range[0] +
140
117
  2 +
141
118
  offset;
142
- const absoluteEnd = absoluteStart + 1 + tag.length; // `@` + tagName
119
+ const absoluteEnd = absoluteStart + 1 + tag.length;
143
120
  const suggestion = getSuggestionText(tag);
144
121
  context.report({
145
122
  loc: {
@@ -156,8 +133,6 @@ exports.noJsonSchemaTags = (0, eslint_devkit_1.createRule)({
156
133
  messageId: 'moveToDescription',
157
134
  data: { tag },
158
135
  fix: (fixer) => {
159
- // Remove the entire @tag and its value (to end of line)
160
- // Find the line boundaries
161
136
  const fullSource = sourceCode.getText();
162
137
  let lineStart = absoluteStart;
163
138
  while (lineStart > 0 && fullSource[lineStart - 1] !== '\n') {
@@ -168,7 +143,6 @@ exports.noJsonSchemaTags = (0, eslint_devkit_1.createRule)({
168
143
  fullSource[lineEnd] !== '\n') {
169
144
  lineEnd++;
170
145
  }
171
- // Include the trailing newline if present
172
146
  if (lineEnd < fullSource.length && fullSource[lineEnd] === '\n') {
173
147
  lineEnd++;
174
148
  }
@@ -183,4 +157,3 @@ exports.noJsonSchemaTags = (0, eslint_devkit_1.createRule)({
183
157
  };
184
158
  },
185
159
  });
186
- //# sourceMappingURL=no-json-schema-tags.js.map
@@ -1,26 +1,14 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noMagicNumbers = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
5
  const eslint_devkit_2 = require("@interlace/eslint-devkit");
11
- /** Numbers that are universally idiomatic in JS/TS and need no naming. */
12
6
  const DEFAULT_IGNORE = new Set([-1, 0, 1, 2]);
13
- /** Build a SCREAMING_SNAKE_CASE const name from a numeric value. */
14
7
  function constNameFor(value) {
15
- // e.g. 5000 → MAGIC_5000 · -3 → MAGIC_NEG_3 · 1.5 → MAGIC_1_5
16
8
  const prefix = value < 0 ? 'MAGIC_NEG_' : 'MAGIC_';
17
9
  const digits = String(Math.abs(value)).replace('.', '_');
18
10
  return `${prefix}${digits}`;
19
11
  }
20
- /**
21
- * Walk up the AST to find the nearest statement ancestor that can be used
22
- * as the insertion point for a const declaration.
23
- */
24
12
  function nearestStatement(node) {
25
13
  const STATEMENT_TYPES = new Set([
26
14
  'ExpressionStatement', 'VariableDeclaration', 'ReturnStatement',
@@ -119,12 +107,10 @@ exports.noMagicNumbers = (0, eslint_devkit_1.createRule)({
119
107
  BITWISE_OPS.has(parent.operator));
120
108
  }
121
109
  function isVariableDeclarator(node) {
122
- // const FOO = 42 — the literal is the named constant itself
123
110
  const parent = node.parent;
124
111
  return parent?.type === 'VariableDeclarator';
125
112
  }
126
113
  function isExportedConst(node) {
127
- // export const FOO = 42
128
114
  let current = node;
129
115
  while (current) {
130
116
  if (current.type === 'ExportNamedDeclaration')
@@ -139,7 +125,6 @@ exports.noMagicNumbers = (0, eslint_devkit_1.createRule)({
139
125
  return false;
140
126
  }
141
127
  function isPropertyKey(node) {
142
- // { 42: 'value' } — numeric key in object literal
143
128
  const parent = node.parent;
144
129
  return (parent?.type === 'Property' &&
145
130
  parent.key === node);
@@ -149,15 +134,12 @@ exports.noMagicNumbers = (0, eslint_devkit_1.createRule)({
149
134
  if (typeof node.value !== 'number')
150
135
  return;
151
136
  const value = node.value;
152
- // Skip universally ignored values
153
137
  if (isIgnoredNumber(value))
154
138
  return;
155
- // Skip NaN / Infinity (not numeric literals per se)
156
139
  if (!isFinite(value))
157
140
  return;
158
- // Context-based skips
159
141
  if (isVariableDeclarator(node))
160
- return; // const X = 42
142
+ return;
161
143
  if (isExportedConst(node))
162
144
  return;
163
145
  if (isArrayIndex(node))
@@ -184,7 +166,6 @@ exports.noMagicNumbers = (0, eslint_devkit_1.createRule)({
184
166
  const stmt = nearestStatement(node);
185
167
  if (!stmt)
186
168
  return null;
187
- // Determine indentation from the statement's first token.
188
169
  const firstToken = sourceCode.getFirstToken(stmt);
189
170
  if (!firstToken)
190
171
  return null;
@@ -202,4 +183,3 @@ exports.noMagicNumbers = (0, eslint_devkit_1.createRule)({
202
183
  };
203
184
  },
204
185
  });
205
- //# sourceMappingURL=no-magic-numbers.js.map
@@ -1,16 +1,8 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noRawCrossPropertyHref = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
5
  const eslint_devkit_2 = require("@interlace/eslint-devkit");
11
- // Fixed list of cross-property hosts. Mirrors UTM_PHILOSOPHY.md's
12
- // cross-property travel matrix and ANALYTICS_PHILOSOPHY.md principle 1's
13
- // list of measured surfaces. Edit there and here together.
14
6
  const CROSS_PROPERTY_HOSTS = new Set([
15
7
  'ofriperetz.dev',
16
8
  'interlace.tools',
@@ -44,7 +36,6 @@ exports.noRawCrossPropertyHref = (0, eslint_devkit_1.createRule)({
44
36
  defaultOptions: [],
45
37
  create(context) {
46
38
  function parseHost(value) {
47
- // Only absolute URLs with a hostname.
48
39
  if (!/^https?:\/\//i.test(value))
49
40
  return null;
50
41
  try {
@@ -83,4 +74,3 @@ exports.noRawCrossPropertyHref = (0, eslint_devkit_1.createRule)({
83
74
  };
84
75
  },
85
76
  });
86
- //# sourceMappingURL=no-raw-cross-property-href.js.map
@@ -1,9 +1,4 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.preferCodePoint = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
@@ -36,22 +31,14 @@ exports.preferCodePoint = (0, eslint_devkit_1.createRule)({
36
31
  },
37
32
  defaultOptions: [],
38
33
  create(context) {
39
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, consistent-function-scoping
40
34
  function isInAllowedContext(node) {
41
- // For simplicity, we'll skip the allow option for now
42
- // This would require more complex logic to check comments/code context
43
35
  return false;
44
36
  }
45
- // oxlint-disable-next-line consistent-function-scoping
46
37
  function shouldIgnoreCall(node) {
47
- // The unicorn rule flags ALL charCodeAt calls, but allows some contexts
48
38
  if (node.callee.type === 'MemberExpression') {
49
- // Allow optional chaining
50
39
  if (node.callee.optional) {
51
40
  return true;
52
41
  }
53
- // Allow computed property access where the property is a variable (not literal)
54
- // This means obj[method] is ignored, but obj['charCodeAt'] is still flagged
55
42
  if (node.callee.computed &&
56
43
  node.callee.property.type === 'Identifier') {
57
44
  return true;
@@ -59,16 +46,12 @@ exports.preferCodePoint = (0, eslint_devkit_1.createRule)({
59
46
  }
60
47
  return false;
61
48
  }
62
- // oxlint-disable-next-line consistent-function-scoping
63
49
  function isCharCodeAtCall(node) {
64
- // Check if this is a call to charCodeAt method
65
50
  if (node.callee.type === 'MemberExpression') {
66
- // Direct property access: obj.charCodeAt
67
51
  if (node.callee.property.type === 'Identifier' &&
68
52
  node.callee.property.name === 'charCodeAt') {
69
53
  return true;
70
54
  }
71
- // Computed property access: obj['charCodeAt']
72
55
  if (node.callee.computed &&
73
56
  node.callee.property.type === 'Literal' &&
74
57
  node.callee.property.value === 'charCodeAt') {
@@ -95,4 +78,3 @@ exports.preferCodePoint = (0, eslint_devkit_1.createRule)({
95
78
  };
96
79
  },
97
80
  });
98
- //# sourceMappingURL=prefer-code-point.js.map