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
@@ -0,0 +1,107 @@
1
+ import pluginJs from "@eslint/js";
2
+ import tsParser from "@typescript-eslint/parser";
3
+ import { defineConfig } from "eslint/config";
4
+ import tseslint from "typescript-eslint";
5
+
6
+ // Import ourselves from dist — this IS the plugin (run `bun run build` first)
7
+ import absolutePlugin from "./dist/index.js";
8
+
9
+ export default defineConfig([
10
+ { ignores: ["dist/**", "node_modules/**", ".absolutejs/**"] },
11
+
12
+ pluginJs.configs.recommended,
13
+
14
+ ...tseslint.configs.recommended,
15
+
16
+ {
17
+ files: ["**/*.ts"],
18
+ languageOptions: {
19
+ parser: tsParser,
20
+ parserOptions: {
21
+ project: "./tsconfig.json"
22
+ }
23
+ },
24
+ rules: {
25
+ "@typescript-eslint/consistent-type-assertions": [
26
+ "error",
27
+ { assertionStyle: "never" }
28
+ ],
29
+ "@typescript-eslint/no-unnecessary-type-assertion": "error"
30
+ }
31
+ },
32
+ {
33
+ files: ["**/*.{ts,js,mjs}"],
34
+ plugins: {
35
+ absolute: absolutePlugin
36
+ },
37
+ rules: {
38
+ "absolute/explicit-object-types": "error",
39
+ "absolute/max-depth-extended": ["error", 1],
40
+ "absolute/min-var-length": [
41
+ "error",
42
+ { allowedVars: ["_", "id"], minLength: 3 }
43
+ ],
44
+ "absolute/no-explicit-return-type": "error",
45
+ "absolute/no-useless-function": "error",
46
+ "absolute/sort-exports": [
47
+ "error",
48
+ { caseSensitive: true, natural: true, order: "asc" }
49
+ ],
50
+ "absolute/sort-keys-fixable": [
51
+ "error",
52
+ { caseSensitive: true, natural: true, order: "asc" }
53
+ ],
54
+ "arrow-body-style": ["error", "as-needed"],
55
+ "consistent-return": "error",
56
+ eqeqeq: "error",
57
+ "func-style": [
58
+ "error",
59
+ "expression",
60
+ { allowArrowFunctions: true }
61
+ ],
62
+ "no-await-in-loop": "error",
63
+ "no-duplicate-imports": "error",
64
+ "no-else-return": "error",
65
+ "no-empty-function": "error",
66
+ "no-floating-decimal": "error",
67
+ "no-implicit-coercion": "error",
68
+ "no-implicit-globals": "error",
69
+ "no-loop-func": "error",
70
+ "no-magic-numbers": [
71
+ "warn",
72
+ { detectObjects: false, enforceConst: true, ignore: [0, 1, 2] }
73
+ ],
74
+ "no-nested-ternary": "error",
75
+ "no-new-wrappers": "error",
76
+ "no-param-reassign": "error",
77
+ "no-return-await": "error",
78
+ "no-shadow": "error",
79
+ "no-unneeded-ternary": "error",
80
+ "no-useless-assignment": "error",
81
+ "no-useless-concat": "error",
82
+ "no-useless-return": "error",
83
+ "no-var": "error",
84
+ "prefer-arrow-callback": "error",
85
+ "prefer-const": "error",
86
+ "prefer-destructuring": [
87
+ "error",
88
+ { array: true, object: true },
89
+ { enforceForRenamedProperties: false }
90
+ ],
91
+ "prefer-template": "error"
92
+ }
93
+ },
94
+ {
95
+ files: ["eslint.config.mjs"],
96
+ rules: {
97
+ "@typescript-eslint/no-unused-expressions": "off"
98
+ }
99
+ },
100
+ {
101
+ files: ["**/*.test.ts"],
102
+ rules: {
103
+ "absolute/min-var-length": "off",
104
+ "no-magic-numbers": "off"
105
+ }
106
+ }
107
+ ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-absolute",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
4
4
  "description": "ESLint plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,21 +11,24 @@
11
11
  "license": "CC BY-NC 4.0",
12
12
  "author": "Alex Kahn",
13
13
  "scripts": {
14
- "test": "echo \"Error: no test specified\" && exit 1",
15
- "build": "rm -rf dist && bun build src/index.js --outdir dist --splitting --target=bun",
16
- "format": "prettier --write \"./**/*.{js,jsx,ts,tsx,css,json,mjs}\"",
17
- "dev": "bun run --watch example/server.ts",
14
+ "test": "bun test tests/",
15
+ "build": "rm -rf dist && bun build src/index.ts --outdir dist --splitting --target=bun --external eslint --external @typescript-eslint/utils",
16
+ "format": "absolutejs prettier --write",
18
17
  "release": "bun run format && bun run build && bun publish",
19
18
  "prune": "ts-prune --error",
20
- "type-check": "bun run tsc --noEmit"
19
+ "lint": "bun run build && bun run absolutejs eslint",
20
+ "typecheck": "bun run tsc --noEmit"
21
21
  },
22
22
  "devDependencies": {
23
- "eslint": "9.23.0",
24
- "prettier": "3.5.3",
23
+ "@types/bun": "1.3.3",
24
+ "@absolutejs/absolute": "0.16.10",
25
+ "@types/react": "19.2.14",
26
+ "@typescript-eslint/rule-tester": "8.56.0",
27
+ "@typescript-eslint/utils": "8.56.0",
28
+ "eslint": "10",
29
+ "prettier": "3.8.1",
25
30
  "ts-prune": "0.10.3",
26
- "typescript": "5.8.2",
27
- "@types/react": "19.1.0",
28
- "@types/bun": "latest",
29
- "typescript-eslint": "8.28.0"
31
+ "typescript": "5.9.3",
32
+ "typescript-eslint": "8.56.0"
30
33
  }
31
34
  }
package/src/index.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { noNestedJSXReturn } from "./rules/no-nested-jsx-return";
2
+ import { explicitObjectTypes } from "./rules/explicit-object-types";
3
+ import { sortKeysFixable } from "./rules/sort-keys-fixable";
4
+ import { noTransitionCSSProperties } from "./rules/no-transition-cssproperties";
5
+ import { noExplicitReturnTypes } from "./rules/no-explicit-return-types";
6
+ import { maxJSXNesting } from "./rules/max-jsx-nesting";
7
+ import { seperateStyleFiles } from "./rules/seperate-style-files";
8
+ import { noUnnecessaryKey } from "./rules/no-unnecessary-key";
9
+ import { sortExports } from "./rules/sort-exports";
10
+ import { localizeReactProps } from "./rules/localize-react-props";
11
+ import { noOrNoneComponent } from "./rules/no-or-none-component";
12
+ import { noButtonNavigation } from "./rules/no-button-navigation";
13
+ import { noMultiStyleObjects } from "./rules/no-multi-style-objects";
14
+ import { noUselessFunction } from "./rules/no-useless-function";
15
+ import { minVarLength } from "./rules/min-var-length";
16
+ import { maxDepthExtended } from "./rules/max-depth-extended";
17
+ import { springNamingConvention } from "./rules/spring-naming-convention";
18
+ import { inlineStyleLimit } from "./rules/inline-style-limit";
19
+ import { noInlinePropTypes } from "./rules/no-inline-prop-types";
20
+ import { noUnnecessaryDiv } from "./rules/no-unnecessary-div";
21
+
22
+ export default {
23
+ rules: {
24
+ "explicit-object-types": explicitObjectTypes,
25
+ "inline-style-limit": inlineStyleLimit,
26
+ "localize-react-props": localizeReactProps,
27
+ "max-depth-extended": maxDepthExtended,
28
+ "max-jsxnesting": maxJSXNesting,
29
+ "min-var-length": minVarLength,
30
+ "no-button-navigation": noButtonNavigation,
31
+ "no-explicit-return-type": noExplicitReturnTypes,
32
+ "no-inline-prop-types": noInlinePropTypes,
33
+ "no-multi-style-objects": noMultiStyleObjects,
34
+ "no-nested-jsx-return": noNestedJSXReturn,
35
+ "no-or-none-component": noOrNoneComponent,
36
+ "no-transition-cssproperties": noTransitionCSSProperties,
37
+ "no-unnecessary-div": noUnnecessaryDiv,
38
+ "no-unnecessary-key": noUnnecessaryKey,
39
+ "no-useless-function": noUselessFunction,
40
+ "seperate-style-files": seperateStyleFiles,
41
+ "sort-exports": sortExports,
42
+ "sort-keys-fixable": sortKeysFixable,
43
+ "spring-naming-convention": springNamingConvention
44
+ }
45
+ };
@@ -0,0 +1,75 @@
1
+ import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
+
3
+ type Options = [];
4
+ type MessageIds = "objectLiteralNeedsType" | "arrayOfObjectLiteralsNeedsType";
5
+
6
+ export const explicitObjectTypes: TSESLint.RuleModule<MessageIds, Options> = {
7
+ create(context) {
8
+ /**
9
+ * Returns true if the node is an object literal.
10
+ * @param {ASTNode} node The AST node to check.
11
+ */
12
+ const isObjectLiteral = (
13
+ node: TSESTree.Node | null | undefined
14
+ ): node is TSESTree.ObjectExpression =>
15
+ node !== null &&
16
+ node !== undefined &&
17
+ node.type === "ObjectExpression";
18
+
19
+ return {
20
+ VariableDeclarator(node: TSESTree.VariableDeclarator) {
21
+ // Skip if there's no initializer.
22
+ if (!node.init) return;
23
+
24
+ // Skip if the variable already has a type annotation.
25
+ if (node.id.type === "Identifier" && node.id.typeAnnotation)
26
+ return;
27
+
28
+ // Check if the initializer is an object literal.
29
+ if (
30
+ isObjectLiteral(node.init) &&
31
+ node.id.type === "Identifier"
32
+ ) {
33
+ context.report({
34
+ messageId: "objectLiteralNeedsType",
35
+ node: node.id
36
+ });
37
+ return;
38
+ }
39
+
40
+ // Check if the initializer is an array literal containing any object literals.
41
+ if (node.init.type !== "ArrayExpression") {
42
+ return;
43
+ }
44
+
45
+ const hasObjectLiteral = node.init.elements.some((element) => {
46
+ if (!element || element.type === "SpreadElement")
47
+ return false;
48
+ return isObjectLiteral(element);
49
+ });
50
+
51
+ if (hasObjectLiteral && node.id.type === "Identifier") {
52
+ context.report({
53
+ messageId: "arrayOfObjectLiteralsNeedsType",
54
+ node: node.id
55
+ });
56
+ }
57
+ }
58
+ };
59
+ },
60
+ defaultOptions: [],
61
+ meta: {
62
+ docs: {
63
+ description:
64
+ "Require explicit type annotations for object literals and arrays of object literals"
65
+ },
66
+ messages: {
67
+ arrayOfObjectLiteralsNeedsType:
68
+ "Array of object literals must have an explicit type annotation.",
69
+ objectLiteralNeedsType:
70
+ "Object literal must have an explicit type annotation."
71
+ },
72
+ schema: [],
73
+ type: "problem"
74
+ }
75
+ };
@@ -0,0 +1,88 @@
1
+ import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
+
3
+ const DEFAULT_MAX_KEYS = 3;
4
+
5
+ type Options = [number | { maxKeys?: number }];
6
+ type MessageIds = "extractStyle";
7
+
8
+ export const inlineStyleLimit: TSESLint.RuleModule<MessageIds, Options> = {
9
+ create(context) {
10
+ const [option] = context.options;
11
+ // If a number is passed directly, use it as maxKeys; otherwise, extract maxKeys from the object (default to 3)
12
+ const maxKeys =
13
+ typeof option === "number"
14
+ ? option
15
+ : (option && option.maxKeys) || DEFAULT_MAX_KEYS;
16
+
17
+ return {
18
+ JSXAttribute(node: TSESTree.JSXAttribute) {
19
+ // Check if the attribute name is 'style'
20
+ if (
21
+ node.name.type !== "JSXIdentifier" ||
22
+ node.name.name !== "style"
23
+ ) {
24
+ return;
25
+ }
26
+
27
+ // Ensure the value is a JSX expression container with an object literal
28
+ if (
29
+ !node.value ||
30
+ node.value.type !== "JSXExpressionContainer" ||
31
+ !node.value.expression ||
32
+ node.value.expression.type !== "ObjectExpression"
33
+ ) {
34
+ return;
35
+ }
36
+
37
+ const styleObject = node.value.expression;
38
+
39
+ // Count only "Property" nodes (ignoring spread elements or others)
40
+ const keyCount = styleObject.properties.filter(
41
+ (prop): prop is TSESTree.Property =>
42
+ prop.type === "Property"
43
+ ).length;
44
+
45
+ // Report only if the number of keys exceeds the allowed maximum
46
+ if (keyCount > maxKeys) {
47
+ context.report({
48
+ data: { max: maxKeys },
49
+ messageId: "extractStyle",
50
+ node
51
+ });
52
+ }
53
+ }
54
+ };
55
+ },
56
+ defaultOptions: [DEFAULT_MAX_KEYS],
57
+ meta: {
58
+ docs: {
59
+ description:
60
+ "Disallow inline style objects with too many keys and encourage extracting them"
61
+ },
62
+ messages: {
63
+ extractStyle:
64
+ "Inline style objects should be extracted into a separate object or file when containing more than {{max}} keys."
65
+ },
66
+ schema: [
67
+ {
68
+ anyOf: [
69
+ {
70
+ type: "number"
71
+ },
72
+ {
73
+ additionalProperties: false,
74
+ properties: {
75
+ maxKeys: {
76
+ description:
77
+ "Maximum number of keys allowed in an inline style object before it must be extracted.",
78
+ type: "number"
79
+ }
80
+ },
81
+ type: "object"
82
+ }
83
+ ]
84
+ }
85
+ ],
86
+ type: "suggestion"
87
+ }
88
+ };