@futdevpro/dynamo-eslint 1.14.3 → 1.14.6

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 (67) hide show
  1. package/.eslintrc.json +4 -0
  2. package/.vscode/settings.json +11 -0
  3. package/README.md +17 -2
  4. package/build/configs/base.js +19 -7
  5. package/build/configs/base.js.map +1 -1
  6. package/build/plugin/index.d.ts +2 -0
  7. package/build/plugin/index.d.ts.map +1 -1
  8. package/build/plugin/index.js +3 -0
  9. package/build/plugin/index.js.map +1 -1
  10. package/build/plugin/rules/explicit-types.d.ts +4 -0
  11. package/build/plugin/rules/explicit-types.d.ts.map +1 -0
  12. package/build/plugin/rules/explicit-types.js +179 -0
  13. package/build/plugin/rules/explicit-types.js.map +1 -0
  14. package/build/plugin/rules/explicit-types.spec.d.ts +2 -0
  15. package/build/plugin/rules/explicit-types.spec.d.ts.map +1 -0
  16. package/build/plugin/rules/explicit-types.spec.js +162 -0
  17. package/build/plugin/rules/explicit-types.spec.js.map +1 -0
  18. package/build/plugin/rules/import/import-order.d.ts.map +1 -1
  19. package/build/plugin/rules/import/import-order.js +0 -9
  20. package/build/plugin/rules/import/import-order.js.map +1 -1
  21. package/build/plugin/rules/import/no-import-type.d.ts.map +1 -1
  22. package/build/plugin/rules/import/no-import-type.js +23 -12
  23. package/build/plugin/rules/import/no-import-type.js.map +1 -1
  24. package/build/plugin/rules/import/no-js-import.d.ts.map +1 -1
  25. package/build/plugin/rules/import/no-js-import.js +19 -11
  26. package/build/plugin/rules/import/no-js-import.js.map +1 -1
  27. package/build/plugin/rules/naming-patterns.d.ts.map +1 -1
  28. package/build/plugin/rules/naming-patterns.js +7 -2
  29. package/build/plugin/rules/naming-patterns.js.map +1 -1
  30. package/build/scripts/dynamo-fix.d.ts +24 -0
  31. package/build/scripts/dynamo-fix.d.ts.map +1 -1
  32. package/build/scripts/dynamo-fix.js +57 -2
  33. package/build/scripts/dynamo-fix.js.map +1 -1
  34. package/build/scripts/eslintrc-audit.d.ts +24 -0
  35. package/build/scripts/eslintrc-audit.d.ts.map +1 -1
  36. package/build/scripts/eslintrc-audit.js +65 -0
  37. package/build/scripts/eslintrc-audit.js.map +1 -1
  38. package/build/scripts/fix-return-types.d.ts +25 -0
  39. package/build/scripts/fix-return-types.d.ts.map +1 -1
  40. package/build/scripts/fix-return-types.js +80 -9
  41. package/build/scripts/fix-return-types.js.map +1 -1
  42. package/build/scripts/validate-imports.d.ts +24 -0
  43. package/build/scripts/validate-imports.d.ts.map +1 -1
  44. package/build/scripts/validate-imports.js +62 -1
  45. package/build/scripts/validate-imports.js.map +1 -1
  46. package/build/scripts/validate-naming.d.ts +24 -0
  47. package/build/scripts/validate-naming.d.ts.map +1 -1
  48. package/build/scripts/validate-naming.js +72 -9
  49. package/build/scripts/validate-naming.js.map +1 -1
  50. package/eslint.config.js +9 -49
  51. package/futdevpro-dynamo-eslint-1.14.6.tgz +0 -0
  52. package/package.json +1 -1
  53. package/samples/package.json.example +1 -1
  54. package/src/configs/base.ts +34 -22
  55. package/src/plugin/index.ts +3 -0
  56. package/src/plugin/rules/explicit-types.spec.ts +190 -0
  57. package/src/plugin/rules/explicit-types.ts +186 -0
  58. package/src/plugin/rules/import/import-order.ts +0 -9
  59. package/src/plugin/rules/import/no-import-type.ts +21 -12
  60. package/src/plugin/rules/import/no-js-import.ts +25 -15
  61. package/src/plugin/rules/naming-patterns.ts +6 -2
  62. package/src/scripts/dynamo-fix.ts +66 -2
  63. package/src/scripts/eslintrc-audit.ts +79 -6
  64. package/src/scripts/fix-return-types.ts +91 -9
  65. package/src/scripts/validate-imports.ts +71 -2
  66. package/src/scripts/validate-naming.ts +108 -17
  67. package/futdevpro-dynamo-eslint-01.14.3.tgz +0 -0
@@ -15,16 +15,16 @@ module.exports = [
15
15
  'node_modules/**',
16
16
  'dist/**',
17
17
  'build/**',
18
- '*.d.ts'
19
- ]
18
+ '*.d.ts',
19
+ ],
20
20
  },
21
21
  {
22
- files: ['**/*.ts', '**/*.tsx'],
22
+ files: [ '**/*.ts', '**/*.tsx' ],
23
23
  languageOptions: {
24
24
  parser: tsParser,
25
25
  parserOptions: {
26
26
  ecmaVersion: 'latest',
27
- sourceType: 'module'
27
+ sourceType: 'module',
28
28
  },
29
29
  globals: {
30
30
  // Browser globals
@@ -38,8 +38,8 @@ module.exports = [
38
38
  __filename: 'readonly',
39
39
  module: 'readonly',
40
40
  require: 'readonly',
41
- exports: 'readonly'
42
- }
41
+ exports: 'readonly',
42
+ },
43
43
  },
44
44
  plugins: {
45
45
  '@typescript-eslint': tsPlugin,
@@ -49,24 +49,35 @@ module.exports = [
49
49
  },
50
50
  rules: {
51
51
  // ESLint recommended rules
52
- 'no-warning-comments': ['warn', { terms: ['todo', 'fixme', 'removable', '??'], location: 'anywhere' }],
53
- 'indent': ['warn', 2, { SwitchCase: 1 }],
54
- 'max-len': ['warn', { code: 100, comments: 120 }],
55
- 'max-lines': ['warn', 1000],
52
+ 'no-warning-comments': [ 'warn', { terms: [ 'todo', 'fixme', 'removable', '??' ], location: 'anywhere' }],
53
+ 'indent': [ 'warn', 2, { SwitchCase: 1 }],
54
+ 'max-len': [ 'warn', { code: 120, comments: 120 }],
55
+ 'max-lines': [ 'warn', 1000 ],
56
56
  'linebreak-style': 'off',
57
- 'semi': ['warn', 'always'],
57
+ 'semi': [ 'warn', 'always' ],
58
58
  'no-unused-vars': 'off',
59
59
  'no-prototype-builtins': 'off',
60
60
  'no-empty': 'warn',
61
- 'comma-dangle': ['warn', { arrays: 'always-multiline', objects: 'always-multiline', functions: 'only-multiline', imports: 'never', exports: 'never' }],
62
- 'brace-style': ['warn', '1tbs', { allowSingleLine: false }],
63
- 'object-curly-spacing': ['warn', 'always'],
64
- 'array-bracket-spacing': ['warn', 'always', { objectsInArrays: false, arraysInArrays: false }],
61
+ 'comma-dangle': [
62
+ 'warn',
63
+ {
64
+ arrays: 'always-multiline',
65
+ objects: 'always-multiline',
66
+ functions: 'only-multiline',
67
+ imports: 'never',
68
+ exports: 'never',
69
+ },
70
+ ],
71
+ 'brace-style': [ 'warn', '1tbs', { allowSingleLine: false }],
72
+ 'object-curly-spacing': [ 'warn', 'always' ],
73
+ 'array-bracket-spacing': [ 'warn', 'always', { objectsInArrays: false, arraysInArrays: false }],
65
74
  'padding-line-between-statements': [
66
75
  'warn',
67
- { blankLine: 'always', prev: '*', next: ['return','throw','if','for','while','switch','default'] },
68
- { blankLine: 'always', prev: ['const','let','var','break'], next: '*' },
69
- { blankLine: 'any', prev: ['const','let','var'], next: ['const','let','var'] },
76
+ { blankLine: 'always', prev: '*', next: [ 'return','throw','if','for','while','switch','default' ] },
77
+ { blankLine: 'always', prev: [ 'const','let','var','break' ], next: '*' },
78
+ { blankLine: 'any', prev: [ 'const','let','var' ], next: [ 'const','let','var' ] },
79
+ { blankLine: 'any', prev: '*', next: 'import' },
80
+ { blankLine: 'any', prev: 'import', next: '*' },
70
81
  ],
71
82
  'prefer-const': 'warn',
72
83
  'no-case-declarations': 'off',
@@ -74,17 +85,18 @@ module.exports = [
74
85
  'keyword-spacing': 'warn',
75
86
  'no-else-return': 'warn',
76
87
  'no-duplicate-imports': 'warn',
77
- 'max-params': ['warn', 4],
78
- 'max-params-no-constructor/max-params-no-constructor': ['warn', 5],
79
- 'quotes': ['warn', 'single', { allowTemplateLiterals: true }],
88
+ 'max-params': [ 'warn', 4 ],
89
+ 'max-params-no-constructor/max-params-no-constructor': [ 'warn', 5 ],
90
+ 'quotes': [ 'warn', 'single', { allowTemplateLiterals: true }],
80
91
 
81
92
  // TypeScript rules
82
93
  '@typescript-eslint/no-unused-vars': 'warn',
83
- '@typescript-eslint/explicit-function-return-type': ['warn', { allowTypedFunctionExpressions: false }],
94
+ '@typescript-eslint/explicit-function-return-type': [ 'warn', { allowTypedFunctionExpressions: false }],
84
95
  '@typescript-eslint/no-explicit-any': 'warn',
85
96
  '@typescript-eslint/typedef': 'warn',
86
97
 
87
98
  // Dynamo custom rules
99
+ '@futdevpro/dynamo/explicit-types': 'warn',
88
100
  '@futdevpro/dynamo/import-order': 'warn',
89
101
  '@futdevpro/dynamo/naming-patterns': 'warn',
90
102
  '@futdevpro/dynamo/no-import-type': 'warn',
@@ -1,3 +1,4 @@
1
+ import explicitTypesRule from './rules/explicit-types';
1
2
  import importOrderRule from './rules/import/import-order';
2
3
  import namingPatternsRule from './rules/naming-patterns';
3
4
  import noImportTypeRule from './rules/import/no-import-type';
@@ -5,6 +6,7 @@ import noJsExtensionRule from './rules/import/no-js-import';
5
6
 
6
7
  export = {
7
8
  rules: {
9
+ 'explicit-types': explicitTypesRule,
8
10
  'import-order': importOrderRule,
9
11
  'no-import-type': noImportTypeRule,
10
12
  'no-js-import': noJsExtensionRule,
@@ -14,6 +16,7 @@ export = {
14
16
  configs: {
15
17
  recommended: {
16
18
  rules: {
19
+ '@futdevpro/dynamo/explicit-types': 'warn',
17
20
  '@futdevpro/dynamo/import-order': 'warn',
18
21
  '@futdevpro/dynamo/no-import-type': 'warn',
19
22
  '@futdevpro/dynamo/no-js-import': 'warn',
@@ -0,0 +1,190 @@
1
+ import explicitTypesRule from './explicit-types';
2
+
3
+ describe('| explicit-types', () => {
4
+ it('| should be a valid ESLint rule', () => {
5
+ expect(explicitTypesRule.meta?.type).toBe('suggestion');
6
+ expect(explicitTypesRule.meta?.docs?.description).toContain('explicit type annotations');
7
+ });
8
+
9
+ it('| should have create function that returns visitor object', () => {
10
+ const mockContext = {
11
+ report: () => {},
12
+ } as any;
13
+
14
+ const result = explicitTypesRule.create(mockContext);
15
+
16
+ expect(typeof result).toBe('object');
17
+ expect(typeof result.FunctionDeclaration).toBe('function');
18
+ expect(typeof result.ArrowFunctionExpression).toBe('function');
19
+ expect(typeof result.VariableDeclarator).toBe('function');
20
+ expect(typeof result.PropertyDefinition).toBe('function');
21
+ });
22
+
23
+ it('| should report missing return types on function declarations', () => {
24
+ const mockContext = {
25
+ report: (options: any) => {
26
+ expect(options.messageId).toBe('missingReturnType');
27
+ expect(options.data.name).toBe('testFunction');
28
+ },
29
+ } as any;
30
+
31
+ const mockNode = {
32
+ type: 'FunctionDeclaration' as const,
33
+ id: { name: 'testFunction' },
34
+ returnType: null,
35
+ params: [],
36
+ } as any;
37
+
38
+ const rule = explicitTypesRule.create(mockContext);
39
+ rule.FunctionDeclaration(mockNode);
40
+ });
41
+
42
+ it('| should not report when function has return type', () => {
43
+ const mockContext = {
44
+ report: (options: any) => {
45
+ fail('Should not report when function has return type');
46
+ },
47
+ } as any;
48
+
49
+ const mockNode = {
50
+ type: 'FunctionDeclaration' as const,
51
+ id: { name: 'testFunction' },
52
+ returnType: { type: 'TSTypeAnnotation' },
53
+ params: [],
54
+ } as any;
55
+
56
+ const rule = explicitTypesRule.create(mockContext);
57
+ rule.FunctionDeclaration(mockNode);
58
+ });
59
+
60
+ it('| should report missing return types on arrow functions', () => {
61
+ const mockContext = {
62
+ report: (options: any) => {
63
+ expect(options.messageId).toBe('missingArrowReturnType');
64
+ },
65
+ } as any;
66
+
67
+ const mockNode = {
68
+ type: 'ArrowFunctionExpression' as const,
69
+ returnType: null,
70
+ params: [],
71
+ } as any;
72
+
73
+ const rule = explicitTypesRule.create(mockContext);
74
+ rule.ArrowFunctionExpression(mockNode);
75
+ });
76
+
77
+ it('| should report missing types on variable declarations', () => {
78
+ const mockContext = {
79
+ report: (options: any) => {
80
+ expect(options.messageId).toBe('missingVariableType');
81
+ expect(options.data.name).toBe('testVar');
82
+ },
83
+ } as any;
84
+
85
+ const mockNode = {
86
+ type: 'VariableDeclarator' as const,
87
+ id: { name: 'testVar', typeAnnotation: null },
88
+ init: null,
89
+ } as any;
90
+
91
+ const rule = explicitTypesRule.create(mockContext);
92
+ rule.VariableDeclarator(mockNode);
93
+ });
94
+
95
+ it('| should not report when variable has type annotation', () => {
96
+ const mockContext = {
97
+ report: (options: any) => {
98
+ fail('Should not report when variable has type annotation');
99
+ },
100
+ } as any;
101
+
102
+ const mockNode = {
103
+ type: 'VariableDeclarator' as const,
104
+ id: { name: 'testVar', typeAnnotation: { type: 'TSTypeAnnotation' } },
105
+ init: null,
106
+ } as any;
107
+
108
+ const rule = explicitTypesRule.create(mockContext);
109
+ rule.VariableDeclarator(mockNode);
110
+ });
111
+
112
+ it('| should not report when variable has typed initializer', () => {
113
+ const mockContext = {
114
+ report: (options: any) => {
115
+ fail('Should not report when variable has typed initializer');
116
+ },
117
+ } as any;
118
+
119
+ const mockNode = {
120
+ type: 'VariableDeclarator' as const,
121
+ id: { name: 'testVar', typeAnnotation: null },
122
+ init: { type: 'CallExpression' },
123
+ } as any;
124
+
125
+ const rule = explicitTypesRule.create(mockContext);
126
+ rule.VariableDeclarator(mockNode);
127
+ });
128
+
129
+ it('| should report missing parameter types', () => {
130
+ const mockContext = {
131
+ report: (options: any) => {
132
+ expect(options.messageId).toBe('missingParameterType');
133
+ expect(options.data.name).toBe('param');
134
+ },
135
+ } as any;
136
+
137
+ const mockNode = {
138
+ type: 'FunctionDeclaration' as const,
139
+ id: { name: 'testFunction' },
140
+ returnType: { type: 'TSTypeAnnotation' },
141
+ params: [
142
+ { type: 'Identifier', name: 'param', typeAnnotation: null }
143
+ ],
144
+ } as any;
145
+
146
+ const rule = explicitTypesRule.create(mockContext);
147
+ rule.FunctionDeclaration(mockNode);
148
+ });
149
+
150
+ it('| should report missing class property types', () => {
151
+ const mockContext = {
152
+ report: (options: any) => {
153
+ expect(options.messageId).toBe('missingPropertyType');
154
+ expect(options.data.name).toBe('property');
155
+ },
156
+ } as any;
157
+
158
+ const mockNode = {
159
+ type: 'PropertyDefinition' as const,
160
+ key: { name: 'property' },
161
+ typeAnnotation: null,
162
+ value: null,
163
+ } as any;
164
+
165
+ const rule = explicitTypesRule.create(mockContext);
166
+ rule.PropertyDefinition(mockNode);
167
+ });
168
+
169
+ it('| should report missing destructuring types', () => {
170
+ const mockContext = {
171
+ report: (options: any) => {
172
+ expect(options.messageId).toBe('missingDestructuringType');
173
+ },
174
+ } as any;
175
+
176
+ const objectPatternNode = {
177
+ type: 'ObjectPattern' as const,
178
+ typeAnnotation: null,
179
+ } as any;
180
+
181
+ const arrayPatternNode = {
182
+ type: 'ArrayPattern' as const,
183
+ typeAnnotation: null,
184
+ } as any;
185
+
186
+ const rule = explicitTypesRule.create(mockContext);
187
+ rule.ObjectPattern(objectPatternNode);
188
+ rule.ArrayPattern(arrayPatternNode);
189
+ });
190
+ });
@@ -0,0 +1,186 @@
1
+ import { Rule } from 'eslint';
2
+
3
+ const rule: Rule.RuleModule = {
4
+ meta: {
5
+ type: 'suggestion',
6
+ docs: {
7
+ description: 'Enforce explicit type annotations on all TypeScript declarations',
8
+ recommended: true,
9
+ },
10
+ schema: [],
11
+ messages: {
12
+ missingReturnType: 'Function "{{name}}" must have an explicit return type annotation.',
13
+ missingArrowReturnType: 'Arrow function must have an explicit return type annotation.',
14
+ missingVariableType: 'Variable "{{name}}" must have an explicit type annotation.',
15
+ missingParameterType: 'Parameter "{{name}}" must have an explicit type annotation.',
16
+ missingPropertyType: 'Class property "{{name}}" must have an explicit type annotation.',
17
+ missingDestructuringType: 'Destructuring assignment must have explicit type annotations.',
18
+ },
19
+ },
20
+ create(context) {
21
+ return {
22
+ // Function declarations
23
+ FunctionDeclaration(node: any) {
24
+ try {
25
+ // Check return type
26
+ if (!node.returnType) {
27
+ context.report({
28
+ node,
29
+ messageId: 'missingReturnType',
30
+ data: { name: node.id?.name || 'anonymous' },
31
+ });
32
+ }
33
+
34
+ // Check function parameters with defensive checks
35
+ if (node.params && Array.isArray(node.params)) {
36
+ node.params.forEach((param: any) => {
37
+ try {
38
+ if (param && param.type === 'Identifier' && !param.typeAnnotation) {
39
+ context.report({
40
+ node: param,
41
+ messageId: 'missingParameterType',
42
+ data: { name: param.name || 'unknown' },
43
+ });
44
+ }
45
+ } catch (paramError) {
46
+ console.error('[explicit-types] Error processing function parameter:', paramError);
47
+ }
48
+ });
49
+ }
50
+ } catch (error) {
51
+ console.error('[explicit-types] Error in FunctionDeclaration visitor:', error);
52
+ }
53
+ },
54
+
55
+ // Arrow functions
56
+ ArrowFunctionExpression(node: any) {
57
+ try {
58
+ // Check return type
59
+ if (!node.returnType) {
60
+ context.report({
61
+ node,
62
+ messageId: 'missingArrowReturnType',
63
+ });
64
+ }
65
+
66
+ // Check arrow function parameters with defensive checks
67
+ if (node.params && Array.isArray(node.params)) {
68
+ node.params.forEach((param: any) => {
69
+ try {
70
+ if (param && param.type === 'Identifier' && !param.typeAnnotation) {
71
+ context.report({
72
+ node: param,
73
+ messageId: 'missingParameterType',
74
+ data: { name: param.name || 'unknown' },
75
+ });
76
+ }
77
+ } catch (paramError) {
78
+ console.error('[explicit-types] Error processing arrow function parameter:', paramError);
79
+ }
80
+ });
81
+ }
82
+ } catch (error) {
83
+ console.error('[explicit-types] Error in ArrowFunctionExpression visitor:', error);
84
+ }
85
+ },
86
+
87
+ // Variable declarations
88
+ VariableDeclarator(node: any) {
89
+ try {
90
+ // Defensive check for node.id
91
+ if (!node.id) {
92
+ return;
93
+ }
94
+
95
+ if (!node.id.typeAnnotation) {
96
+ // Check if this variable is declared in a for loop
97
+ let isInForLoop = false;
98
+ let parent = node.parent;
99
+
100
+ while (parent) {
101
+ if (parent.type === 'ForStatement' || parent.type === 'ForInStatement' || parent.type === 'ForOfStatement') {
102
+ isInForLoop = true;
103
+ break;
104
+ }
105
+ parent = parent.parent;
106
+ }
107
+
108
+ // Skip if variable is in a for loop
109
+ if (isInForLoop) {
110
+ return;
111
+ }
112
+
113
+ // Skip if variable is initialized with a typed value that can be inferred
114
+ const hasTypedInitializer = node.init && (
115
+ node.init.type === 'CallExpression' ||
116
+ node.init.type === 'NewExpression' ||
117
+ node.init.type === 'ArrayExpression' ||
118
+ node.init.type === 'ObjectExpression' ||
119
+ node.init.type === 'Literal'
120
+ );
121
+
122
+ if (!hasTypedInitializer) {
123
+ context.report({
124
+ node: node.id,
125
+ messageId: 'missingVariableType',
126
+ data: { name: (node.id as any)?.name || 'destructured' },
127
+ });
128
+ }
129
+ }
130
+ } catch (error) {
131
+ console.error('[explicit-types] Error in VariableDeclarator visitor:', error);
132
+ }
133
+ },
134
+
135
+ // Class properties
136
+ PropertyDefinition(node: any) {
137
+ try {
138
+ // Defensive check for node.key
139
+ if (!node.key) {
140
+ return;
141
+ }
142
+
143
+ if (!node.typeAnnotation && !node.value) {
144
+ context.report({
145
+ node: node.key,
146
+ messageId: 'missingPropertyType',
147
+ data: { name: (node.key as any)?.name || 'computed' },
148
+ });
149
+ }
150
+ } catch (error) {
151
+ console.error('[explicit-types] Error in PropertyDefinition visitor:', error);
152
+ }
153
+ },
154
+
155
+ // Object destructuring
156
+ ObjectPattern(node: any) {
157
+ try {
158
+ if (!node.typeAnnotation) {
159
+ context.report({
160
+ node,
161
+ messageId: 'missingDestructuringType',
162
+ });
163
+ }
164
+ } catch (error) {
165
+ console.error('[explicit-types] Error in ObjectPattern visitor:', error);
166
+ }
167
+ },
168
+
169
+ // Array destructuring
170
+ ArrayPattern(node: any) {
171
+ try {
172
+ if (!node.typeAnnotation) {
173
+ context.report({
174
+ node,
175
+ messageId: 'missingDestructuringType',
176
+ });
177
+ }
178
+ } catch (error) {
179
+ console.error('[explicit-types] Error in ArrayPattern visitor:', error);
180
+ }
181
+ },
182
+ };
183
+ },
184
+ };
185
+
186
+ export default rule;
@@ -113,11 +113,6 @@ const rule: Rule.RuleModule = {
113
113
  context.report({
114
114
  node: importNode,
115
115
  messageId: 'misordered',
116
- fix(fixer) {
117
- // This is complex to fix automatically, so we'll just report for now
118
- // Future enhancement: reorder imports automatically
119
- return null;
120
- },
121
116
  });
122
117
  }
123
118
 
@@ -139,10 +134,6 @@ const rule: Rule.RuleModule = {
139
134
  context.report({
140
135
  node: firstImportOfNextGroup,
141
136
  messageId: 'missingEmptyLine',
142
- fix(fixer) {
143
- // Add empty line before the first import of next group
144
- return fixer.insertTextBefore(firstImportOfNextGroup, '\n');
145
- },
146
137
  });
147
138
  }
148
139
  }
@@ -15,19 +15,28 @@ const rule: Rule.RuleModule = {
15
15
 
16
16
  return {
17
17
  ImportDeclaration(node: any) {
18
- // Check for import type usage
19
- if (node.importKind === 'type') {
20
- context.report({
21
- node,
22
- messageId: 'forbiddenImportType',
23
- fix(fixer) {
24
- // Remove 'type' keyword
25
- const importText = sourceCode.getText(node);
26
- const newImportText = importText.replace(/import\s+type\s+/, 'import ');
18
+ try {
19
+ // Check for import type usage
20
+ if (node.importKind === 'type') {
21
+ context.report({
22
+ node,
23
+ messageId: 'forbiddenImportType',
24
+ fix(fixer) {
25
+ try {
26
+ // Remove 'type' keyword
27
+ const importText = sourceCode.getText(node);
28
+ const newImportText = importText.replace(/import\s+type\s+/, 'import ');
27
29
 
28
- return fixer.replaceText(node, newImportText);
29
- },
30
- });
30
+ return fixer.replaceText(node, newImportText);
31
+ } catch (fixError) {
32
+ console.error('[no-import-type] Error in fix function:', fixError);
33
+ return null;
34
+ }
35
+ },
36
+ });
37
+ }
38
+ } catch (error) {
39
+ console.error('[no-import-type] Error in ImportDeclaration visitor:', error);
31
40
  }
32
41
  },
33
42
  };
@@ -10,22 +10,32 @@ const rule: Rule.RuleModule = {
10
10
  },
11
11
  fixable: 'code',
12
12
  },
13
- create(context) {
14
- return {
15
- ImportDeclaration(node: any) {
16
- const source = node.source.value as string;
17
-
18
- if (source.endsWith('.js')) {
19
- context.report({
20
- node: node.source,
21
- messageId: 'forbiddenJsExtension',
22
- fix(fixer) {
23
- // Remove .js extension
24
- const newSource = source.replace(/\.js$/, '');
13
+ create(context: Rule.RuleContext): Rule.RuleListener {
14
+ // List of allowed packages that can use .js extension
15
+ const allowedJsPackages = [
16
+ 'discord.js',
17
+ ];
25
18
 
26
- return fixer.replaceText(node.source, `'${newSource}'`);
27
- },
28
- });
19
+ return {
20
+ ImportDeclaration(node): void {
21
+ try {
22
+ const source: string = node.source?.value as string;
23
+
24
+ if (source && source.endsWith('.js')) {
25
+ // Check if the import is from an allowed package
26
+ const isAllowedPackage = allowedJsPackages.some((pkg: string): boolean =>
27
+ source.includes(pkg) || source.startsWith(pkg)
28
+ );
29
+
30
+ if (!isAllowedPackage) {
31
+ context.report({
32
+ node: node.source,
33
+ messageId: 'forbiddenJsExtension',
34
+ });
35
+ }
36
+ }
37
+ } catch (error) {
38
+ console.error('[no-js-import] Error in ImportDeclaration visitor:', error);
29
39
  }
30
40
  },
31
41
  };
@@ -13,8 +13,12 @@ const rule: Rule.RuleModule = {
13
13
  create(context) {
14
14
  return {
15
15
  Identifier(node) {
16
- // Future: use dyfmUtils naming patterns to validate identifiers
17
- void node;
16
+ try {
17
+ // Future: use dyfmUtils naming patterns to validate identifiers
18
+ void node;
19
+ } catch (error) {
20
+ console.error('[naming-patterns] Error in Identifier visitor:', error);
21
+ }
18
22
  },
19
23
  };
20
24
  },