eslint-plugin-absolute 0.1.6 → 0.2.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.
Files changed (49) hide show
  1. package/.absolutejs/eslint.cache.json +49 -0
  2. package/.absolutejs/prettier.cache.json +49 -0
  3. package/.absolutejs/tsconfig.tsbuildinfo +1 -0
  4. package/.claude/settings.local.json +10 -0
  5. package/dist/index.js +1787 -1457
  6. package/eslint.config.mjs +107 -0
  7. package/package.json +15 -12
  8. package/src/index.ts +45 -0
  9. package/src/rules/explicit-object-types.ts +75 -0
  10. package/src/rules/inline-style-limit.ts +88 -0
  11. package/src/rules/localize-react-props.ts +454 -0
  12. package/src/rules/max-depth-extended.ts +153 -0
  13. package/src/rules/{max-jsx-nesting.js → max-jsx-nesting.ts} +37 -38
  14. package/src/rules/min-var-length.ts +360 -0
  15. package/src/rules/no-button-navigation.ts +270 -0
  16. package/src/rules/no-explicit-return-types.ts +83 -0
  17. package/src/rules/no-inline-prop-types.ts +68 -0
  18. package/src/rules/no-multi-style-objects.ts +80 -0
  19. package/src/rules/no-nested-jsx-return.ts +205 -0
  20. package/src/rules/no-or-none-component.ts +63 -0
  21. package/src/rules/no-transition-cssproperties.ts +131 -0
  22. package/src/rules/no-unnecessary-div.ts +65 -0
  23. package/src/rules/no-unnecessary-key.ts +111 -0
  24. package/src/rules/no-useless-function.ts +56 -0
  25. package/src/rules/seperate-style-files.ts +79 -0
  26. package/src/rules/sort-exports.ts +424 -0
  27. package/src/rules/sort-keys-fixable.ts +647 -0
  28. package/src/rules/spring-naming-convention.ts +160 -0
  29. package/tsconfig.json +4 -1
  30. package/src/index.js +0 -45
  31. package/src/rules/explicit-object-types.js +0 -54
  32. package/src/rules/inline-style-limit.js +0 -77
  33. package/src/rules/localize-react-props.js +0 -418
  34. package/src/rules/max-depth-extended.js +0 -124
  35. package/src/rules/min-var-length.js +0 -300
  36. package/src/rules/no-button-navigation.js +0 -232
  37. package/src/rules/no-explicit-return-types.js +0 -64
  38. package/src/rules/no-inline-prop-types.js +0 -55
  39. package/src/rules/no-multi-style-objects.js +0 -70
  40. package/src/rules/no-nested-jsx-return.js +0 -154
  41. package/src/rules/no-or-none-component.js +0 -50
  42. package/src/rules/no-transition-cssproperties.js +0 -102
  43. package/src/rules/no-unnecessary-div.js +0 -40
  44. package/src/rules/no-unnecessary-key.js +0 -128
  45. package/src/rules/no-useless-function.js +0 -43
  46. package/src/rules/seperate-style-files.js +0 -62
  47. package/src/rules/sort-exports.js +0 -397
  48. package/src/rules/sort-keys-fixable.js +0 -459
  49. package/src/rules/spring-naming-convention.js +0 -111
@@ -1,397 +0,0 @@
1
- /**
2
- * @fileoverview Enforce that top-level export declarations are sorted.
3
- *
4
- * This rule supports the following options:
5
- * - order: "asc" or "desc" (default: "asc")
6
- * - caseSensitive: boolean (default: false)
7
- * - natural: boolean (default: false)
8
- * - minKeys: integer, minimum number of exports in a contiguous block to check (default: 2)
9
- * - variablesBeforeFunctions: boolean (default: false)
10
- *
11
- * For example, given this code:
12
- *
13
- * export const a = 1;
14
- * export const c = 2;
15
- * export const b = 3;
16
- *
17
- * The rule will report an error and auto-fix it (if run with --fix) to:
18
- *
19
- * export const a = 1;
20
- * export const b = 3;
21
- * export const c = 2;
22
- *
23
- * When variablesBeforeFunctions is true, exports whose values are functions should come after
24
- * exports whose values are not functions.
25
- */
26
-
27
- export default {
28
- meta: {
29
- type: "suggestion",
30
- docs: {
31
- description:
32
- "Enforce that top-level export declarations are sorted by exported name and, optionally, that variable exports come before function exports",
33
- category: "Stylistic Issues",
34
- recommended: false
35
- },
36
- fixable: "code",
37
- schema: [
38
- {
39
- type: "object",
40
- properties: {
41
- order: {
42
- enum: ["asc", "desc"]
43
- },
44
- caseSensitive: {
45
- type: "boolean"
46
- },
47
- natural: {
48
- type: "boolean"
49
- },
50
- minKeys: {
51
- type: "integer",
52
- minimum: 2
53
- },
54
- variablesBeforeFunctions: {
55
- type: "boolean"
56
- }
57
- },
58
- additionalProperties: false
59
- }
60
- ],
61
- messages: {
62
- alphabetical:
63
- "Export declarations are not sorted alphabetically. Expected order: {{expectedOrder}}.",
64
- variablesBeforeFunctions:
65
- "Non-function exports should come before function exports."
66
- }
67
- },
68
-
69
- create(context) {
70
- const sourceCode = context.getSourceCode();
71
- const options = context.options[0] || {};
72
- const order = options.order || "asc";
73
- const caseSensitive =
74
- options.caseSensitive !== undefined ? options.caseSensitive : false;
75
- const natural = options.natural !== undefined ? options.natural : false;
76
- const minKeys = options.minKeys !== undefined ? options.minKeys : 2;
77
- const variablesBeforeFunctions =
78
- options.variablesBeforeFunctions !== undefined
79
- ? options.variablesBeforeFunctions
80
- : false;
81
-
82
- /**
83
- * Helper to generate normalized export text.
84
- * @param {ASTNode} node
85
- * @returns {string}
86
- */
87
- function generateExportText(node) {
88
- // Normalize by trimming and ensuring a consistent semicolon.
89
- return sourceCode
90
- .getText(node)
91
- .trim()
92
- .replace(/\s*;?\s*$/, ";");
93
- }
94
-
95
- /**
96
- * Compare two strings using the options.
97
- * @param {string} a
98
- * @param {string} b
99
- * @returns {number}
100
- */
101
- function compareStrings(a, b) {
102
- let strA = a;
103
- let strB = b;
104
- if (!caseSensitive) {
105
- strA = strA.toLowerCase();
106
- strB = strB.toLowerCase();
107
- }
108
- let cmp = natural
109
- ? strA.localeCompare(strB, undefined, { numeric: true })
110
- : strA.localeCompare(strB);
111
- return order === "asc" ? cmp : -cmp;
112
- }
113
-
114
- /**
115
- * Extracts the exported name from an ExportNamedDeclaration.
116
- * Supports declarations (e.g. export const a = 1) with a single declarator
117
- * and export specifiers (e.g. export { a }).
118
- * @param {ASTNode} node
119
- * @returns {string|null}
120
- */
121
- function getExportName(node) {
122
- if (node.declaration) {
123
- const decl = node.declaration;
124
- if (decl.type === "VariableDeclaration") {
125
- if (decl.declarations.length === 1) {
126
- const id = decl.declarations[0].id;
127
- if (id.type === "Identifier") {
128
- return id.name;
129
- }
130
- }
131
- } else if (
132
- decl.type === "FunctionDeclaration" ||
133
- decl.type === "ClassDeclaration"
134
- ) {
135
- if (decl.id && decl.id.type === "Identifier") {
136
- return decl.id.name;
137
- }
138
- }
139
- } else if (node.specifiers && node.specifiers.length === 1) {
140
- const spec = node.specifiers[0];
141
- return spec.exported.name || spec.exported.value;
142
- }
143
- return null;
144
- }
145
-
146
- /**
147
- * Determines if the export is a function export.
148
- * @param {ASTNode} node
149
- * @returns {boolean}
150
- */
151
- function isFunctionExport(node) {
152
- if (node.declaration) {
153
- const decl = node.declaration;
154
- if (decl.type === "VariableDeclaration") {
155
- if (decl.declarations.length === 1) {
156
- const init = decl.declarations[0].init;
157
- return (
158
- init &&
159
- (init.type === "FunctionExpression" ||
160
- init.type === "ArrowFunctionExpression")
161
- );
162
- }
163
- } else if (decl.type === "FunctionDeclaration") {
164
- return true;
165
- }
166
- // Treat ClassDeclaration as non-function by default (can be adjusted if desired)
167
- return false;
168
- }
169
- // For export specifiers, we cannot reliably tell.
170
- return false;
171
- }
172
-
173
- /**
174
- * Comparator that implements the full sort order.
175
- * - First, type exports (exportKind: "type") come before value exports.
176
- * - Next, if variablesBeforeFunctions is enabled, non-function exports come before function exports.
177
- * - Finally, sort by name using the provided options.
178
- * @param {object} a
179
- * @param {object} b
180
- * @returns {number}
181
- */
182
- function sortComparator(a, b) {
183
- const kindA = a.node.exportKind || "value";
184
- const kindB = b.node.exportKind || "value";
185
- if (kindA !== kindB) {
186
- return kindA === "type" ? -1 : 1;
187
- }
188
- if (variablesBeforeFunctions) {
189
- if (a.isFunction !== b.isFunction) {
190
- return a.isFunction ? 1 : -1;
191
- }
192
- }
193
- return compareStrings(a.name, b.name);
194
- }
195
-
196
- /**
197
- * Recursively traverses a node to check for Identifier references.
198
- * Returns true if any Identifier matches one of the names in laterNames.
199
- * Uses a WeakSet to avoid infinite recursion on cyclic structures.
200
- * @param {ASTNode} node
201
- * @param {Set<string>} laterNames
202
- * @param {WeakSet<Object>} visited
203
- * @returns {boolean}
204
- */
205
- function hasForwardDependency(
206
- node,
207
- laterNames,
208
- visited = new WeakSet()
209
- ) {
210
- if (!node || typeof node !== "object") {
211
- return false;
212
- }
213
- if (visited.has(node)) {
214
- return false;
215
- }
216
- visited.add(node);
217
-
218
- if (node.type === "Identifier" && laterNames.has(node.name)) {
219
- return true;
220
- }
221
-
222
- for (const key in node) {
223
- if (Object.prototype.hasOwnProperty.call(node, key)) {
224
- const value = node[key];
225
- if (Array.isArray(value)) {
226
- for (const element of value) {
227
- if (element && typeof element === "object") {
228
- if (
229
- hasForwardDependency(
230
- element,
231
- laterNames,
232
- visited
233
- )
234
- ) {
235
- return true;
236
- }
237
- }
238
- }
239
- } else if (value && typeof value === "object") {
240
- if (hasForwardDependency(value, laterNames, visited)) {
241
- return true;
242
- }
243
- }
244
- }
245
- }
246
- return false;
247
- }
248
-
249
- /**
250
- * Process a contiguous block of eligible ExportNamedDeclaration nodes.
251
- * @param {ASTNode[]} block
252
- */
253
- function processExportBlock(block) {
254
- if (block.length < minKeys) {
255
- return;
256
- }
257
-
258
- const items = block
259
- .map((node) => {
260
- const name = getExportName(node);
261
- if (name === null) {
262
- return null;
263
- }
264
- return {
265
- name,
266
- node,
267
- isFunction: isFunctionExport(node),
268
- text: sourceCode.getText(node)
269
- };
270
- })
271
- .filter(Boolean);
272
-
273
- if (items.length < minKeys) {
274
- return;
275
- }
276
-
277
- // Create a sorted copy using our comparator.
278
- const sortedItems = items.slice().sort(sortComparator);
279
-
280
- // Determine if the block is unsorted.
281
- let reportNeeded = false;
282
- let messageId = "alphabetical";
283
- for (let i = 1; i < items.length; i++) {
284
- if (sortComparator(items[i - 1], items[i]) > 0) {
285
- reportNeeded = true;
286
- if (
287
- variablesBeforeFunctions &&
288
- items[i - 1].isFunction &&
289
- !items[i].isFunction
290
- ) {
291
- messageId = "variablesBeforeFunctions";
292
- }
293
- break;
294
- }
295
- }
296
-
297
- // If already sorted, do nothing.
298
- if (!reportNeeded) {
299
- return;
300
- }
301
-
302
- // Dependency check: if any export in the block references a later export,
303
- // skip reporting an error (to preserve the dependency order).
304
- const exportNames = items.map((item) => item.name);
305
- for (let i = 0; i < items.length; i++) {
306
- const laterNames = new Set(exportNames.slice(i + 1));
307
- const nodeToCheck = items[i].node.declaration || items[i].node;
308
- if (hasForwardDependency(nodeToCheck, laterNames)) {
309
- // A forward dependency exists; do not report an error for this block.
310
- return;
311
- }
312
- }
313
-
314
- // Report the error only if there is no dependency issue.
315
- const expectedOrder = sortedItems
316
- .map((item) => item.name)
317
- .join(", ");
318
- context.report({
319
- node: items[0].node,
320
- messageId,
321
- data: {
322
- expectedOrder
323
- },
324
- fix(fixer) {
325
- // Only fix if all nodes in the block are fixable.
326
- const fixableNodes = block.filter((n) => {
327
- if (n.declaration) {
328
- if (
329
- n.declaration.type === "VariableDeclaration" &&
330
- n.declaration.declarations.length === 1 &&
331
- n.declaration.declarations[0].id.type ===
332
- "Identifier"
333
- ) {
334
- return true;
335
- }
336
- if (
337
- (n.declaration.type === "FunctionDeclaration" ||
338
- n.declaration.type ===
339
- "ClassDeclaration") &&
340
- n.declaration.id &&
341
- n.declaration.id.type === "Identifier"
342
- ) {
343
- return true;
344
- }
345
- return false;
346
- }
347
- if (n.specifiers && n.specifiers.length === 1) {
348
- return true;
349
- }
350
- return false;
351
- });
352
- if (fixableNodes.length < minKeys) {
353
- return null;
354
- }
355
- const sortedText = sortedItems
356
- .map((item) => generateExportText(item.node))
357
- .join("\n");
358
- const first = block[0].range[0];
359
- const last = block[block.length - 1].range[1];
360
- // Prevent circular fixes: only apply the change if the text differs.
361
- const originalText = sourceCode
362
- .getText()
363
- .slice(first, last);
364
- if (originalText === sortedText) {
365
- return null;
366
- }
367
- return fixer.replaceTextRange([first, last], sortedText);
368
- }
369
- });
370
- }
371
-
372
- return {
373
- "Program:exit"(node) {
374
- const body = node.body;
375
- let block = [];
376
- for (let i = 0; i < body.length; i++) {
377
- const n = body[i];
378
- if (
379
- n.type === "ExportNamedDeclaration" &&
380
- !n.source && // skip re-exports like export * from '...'
381
- getExportName(n) !== null
382
- ) {
383
- block.push(n);
384
- } else {
385
- if (block.length) {
386
- processExportBlock(block);
387
- block = [];
388
- }
389
- }
390
- }
391
- if (block.length) {
392
- processExportBlock(block);
393
- }
394
- }
395
- };
396
- }
397
- };