@mrpalmer/eslint-plugin 1.0.0 → 1.0.2

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.
@@ -1,8 +1,8 @@
1
1
  import path from 'node:path';
2
2
  import { createRule } from '../utils/create-rule.js';
3
- import { loadConfig } from '../utils/ts-config.js';
4
3
  import { getImportPathOptions } from '../utils/import-path-options.js';
5
4
  import { getShortestPath } from '../utils/shortest-path.js';
5
+ import { loadConfig } from '../utils/ts-config.js';
6
6
  export default createRule({
7
7
  meta: {
8
8
  type: 'suggestion',
@@ -15,6 +15,7 @@ export default createRule({
15
15
  type: 'object',
16
16
  properties: {
17
17
  breakTies: {
18
+ description: 'When the aliased and relative paths are the same length, which should be preferred.',
18
19
  type: 'string',
19
20
  enum: ['alias', 'relative'],
20
21
  },
@@ -22,6 +23,11 @@ export default createRule({
22
23
  additionalProperties: false,
23
24
  },
24
25
  ],
26
+ defaultOptions: [
27
+ {
28
+ breakTies: 'alias',
29
+ },
30
+ ],
25
31
  messages: {
26
32
  shortenImport: 'Import can be shortened to "{{path}}"',
27
33
  shortenExport: 'Export can be shortened to "{{path}}"',
@@ -1,4 +1,4 @@
1
- import { type TSESLint } from '@typescript-eslint/utils';
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
2
  import { type MinimatchOptions } from 'minimatch';
3
3
  import type { Arrayable } from '../types.js';
4
4
  import { type ImportType as ImportType_ } from '../utils/import-type.js';
@@ -1,11 +1,11 @@
1
- import { TSESTree } from '@typescript-eslint/utils';
1
+ import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/types';
2
2
  import { minimatch } from 'minimatch';
3
- import { reverse, findOutOfOrder, groupBy } from '../utils/array.js';
4
- import { findRootNode, findEndOfLineWithComments, findStartOfLineWithComments, } from '../utils/ast.js';
3
+ import { findOutOfOrder, groupBy, reverse } from '../utils/array.js';
4
+ import { findEndOfLineWithComments, findRootNode, findStartOfLineWithComments, } from '../utils/ast.js';
5
5
  import { createRule } from '../utils/create-rule.js';
6
+ import { importType, } from '../utils/import-type.js';
6
7
  import { getSettings } from '../utils/settings.js';
7
8
  import { loadConfig } from '../utils/ts-config.js';
8
- import { importType, } from '../utils/import-type.js';
9
9
  const categories = {
10
10
  import: 'import',
11
11
  exports: 'exports',
@@ -21,34 +21,34 @@ const defaultGroups = [
21
21
  // REPORTING AND FIXING
22
22
  function isRequireExpression(expr) {
23
23
  return (expr != null &&
24
- expr.type === TSESTree.AST_NODE_TYPES.CallExpression &&
24
+ expr.type === AST_NODE_TYPES.CallExpression &&
25
25
  // eslint-disable-next-line eslint-plugin/no-property-in-node
26
26
  'name' in expr.callee &&
27
27
  expr.callee.name === 'require' &&
28
28
  expr.arguments.length === 1 &&
29
- expr.arguments[0].type === TSESTree.AST_NODE_TYPES.Literal);
29
+ expr.arguments[0].type === AST_NODE_TYPES.Literal);
30
30
  }
31
31
  function isSupportedRequireModule(node) {
32
- if (node.type !== TSESTree.AST_NODE_TYPES.VariableDeclaration) {
32
+ if (node.type !== AST_NODE_TYPES.VariableDeclaration) {
33
33
  return false;
34
34
  }
35
35
  if (node.declarations.length !== 1) {
36
36
  return false;
37
37
  }
38
38
  const decl = node.declarations[0];
39
- const isPlainRequire = (decl.id.type === TSESTree.AST_NODE_TYPES.Identifier ||
40
- decl.id.type === TSESTree.AST_NODE_TYPES.ObjectPattern) &&
39
+ const isPlainRequire = (decl.id.type === AST_NODE_TYPES.Identifier ||
40
+ decl.id.type === AST_NODE_TYPES.ObjectPattern) &&
41
41
  isRequireExpression(decl.init);
42
- const isRequireWithMemberExpression = (decl.id.type === TSESTree.AST_NODE_TYPES.Identifier ||
43
- decl.id.type === TSESTree.AST_NODE_TYPES.ObjectPattern) &&
42
+ const isRequireWithMemberExpression = (decl.id.type === AST_NODE_TYPES.Identifier ||
43
+ decl.id.type === AST_NODE_TYPES.ObjectPattern) &&
44
44
  decl.init != null &&
45
- decl.init.type === TSESTree.AST_NODE_TYPES.CallExpression &&
46
- decl.init.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
45
+ decl.init.type === AST_NODE_TYPES.CallExpression &&
46
+ decl.init.callee.type === AST_NODE_TYPES.MemberExpression &&
47
47
  isRequireExpression(decl.init.callee.object);
48
48
  return isPlainRequire || isRequireWithMemberExpression;
49
49
  }
50
50
  function isPlainImportModule(node) {
51
- return node.type === TSESTree.AST_NODE_TYPES.ImportDeclaration;
51
+ return node.type === AST_NODE_TYPES.ImportDeclaration;
52
52
  }
53
53
  function canCrossNodeWhileReorder(node) {
54
54
  return isSupportedRequireModule(node) || isPlainImportModule(node);
@@ -276,8 +276,7 @@ function registerNode(context, settings, importEntry, ranks, imported) {
276
276
  if (rank !== -1) {
277
277
  let importNode = importEntry.node;
278
278
  if (importEntry.type === 'require' &&
279
- importNode.parent?.parent?.type ===
280
- TSESTree.AST_NODE_TYPES.VariableDeclaration) {
279
+ importNode.parent?.parent?.type === AST_NODE_TYPES.VariableDeclaration) {
281
280
  importNode = importNode.parent.parent;
282
281
  }
283
282
  imported.push({
@@ -292,7 +291,7 @@ function registerNode(context, settings, importEntry, ranks, imported) {
292
291
  }
293
292
  }
294
293
  function isSideEffectImport(node, sourceCode) {
295
- if (node.type !== TSESTree.AST_NODE_TYPES.ImportDeclaration) {
294
+ if (node.type !== AST_NODE_TYPES.ImportDeclaration) {
296
295
  return false;
297
296
  }
298
297
  return (node.specifiers.length === 0 &&
@@ -300,22 +299,19 @@ function isSideEffectImport(node, sourceCode) {
300
299
  !isPunctuator(sourceCode.getFirstToken(node, { skip: 1 }), '{'));
301
300
  }
302
301
  function isPunctuator(token, value) {
303
- return (token &&
304
- token.type === TSESTree.AST_TOKEN_TYPES.Punctuator &&
305
- token.value === value);
302
+ return (token && token.type === AST_TOKEN_TYPES.Punctuator && token.value === value);
306
303
  }
307
304
  function getRequireBlock(node) {
308
305
  let n = node;
309
306
  // Handle cases like `const baz = require('foo').bar.baz`
310
307
  // and `const foo = require('foo')()`
311
- while ((n.parent?.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
308
+ while ((n.parent?.type === AST_NODE_TYPES.MemberExpression &&
312
309
  n.parent.object === n) ||
313
- (n.parent?.type === TSESTree.AST_NODE_TYPES.CallExpression &&
314
- n.parent.callee === n)) {
310
+ (n.parent?.type === AST_NODE_TYPES.CallExpression && n.parent.callee === n)) {
315
311
  n = n.parent;
316
312
  }
317
- if (n.parent?.type === TSESTree.AST_NODE_TYPES.VariableDeclarator &&
318
- n.parent.parent.parent.type === TSESTree.AST_NODE_TYPES.Program) {
313
+ if (n.parent?.type === AST_NODE_TYPES.VariableDeclarator &&
314
+ n.parent.parent.parent.type === AST_NODE_TYPES.Program) {
319
315
  return n.parent.parent.parent;
320
316
  }
321
317
  return undefined;
@@ -482,9 +478,11 @@ export default createRule({
482
478
  type: 'object',
483
479
  properties: {
484
480
  groups: {
481
+ description: 'The order of import types.',
485
482
  type: 'array',
486
483
  },
487
484
  pathGroups: {
485
+ description: 'Custom path patterns and their import types.',
488
486
  type: 'array',
489
487
  items: {
490
488
  type: 'object',
@@ -515,6 +513,12 @@ export default createRule({
515
513
  additionalProperties: false,
516
514
  },
517
515
  ],
516
+ defaultOptions: [
517
+ {
518
+ groups: defaultGroups,
519
+ pathGroups: [],
520
+ },
521
+ ],
518
522
  messages: {
519
523
  error: '{{error}}',
520
524
  noLineBetweenImports: 'There should be no empty line between import statements',
@@ -628,9 +632,9 @@ function getErrorMessage(error) {
628
632
  return undefined;
629
633
  }
630
634
  function isStaticRequire(node) {
631
- return (node.callee.type === TSESTree.AST_NODE_TYPES.Identifier &&
635
+ return (node.callee.type === AST_NODE_TYPES.Identifier &&
632
636
  node.callee.name === 'require' &&
633
637
  node.arguments.length === 1 &&
634
- node.arguments[0].type === TSESTree.AST_NODE_TYPES.Literal &&
638
+ node.arguments[0].type === AST_NODE_TYPES.Literal &&
635
639
  typeof node.arguments[0].value === 'string');
636
640
  }
@@ -1,4 +1,4 @@
1
- import { type TSESLint } from '@typescript-eslint/utils';
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
2
  export interface Options {
3
3
  ignoreCase?: boolean;
4
4
  types?: NamedTypes;
@@ -1,5 +1,5 @@
1
- import { TSESTree } from '@typescript-eslint/utils';
2
- import { groupBy, reverse, findOutOfOrder } from '../utils/array.js';
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/types';
2
+ import { findOutOfOrder, groupBy, reverse } from '../utils/array.js';
3
3
  import { createRule } from '../utils/create-rule.js';
4
4
  //region rule
5
5
  // REPORTING AND FIXING
@@ -21,24 +21,23 @@ function findSpecifierEnd(sourceCode, node) {
21
21
  }
22
22
  function isRequireExpression(expr) {
23
23
  return (expr != null &&
24
- expr.type === TSESTree.AST_NODE_TYPES.CallExpression &&
25
- expr.callee.type === TSESTree.AST_NODE_TYPES.Identifier &&
24
+ expr.type === AST_NODE_TYPES.CallExpression &&
25
+ expr.callee.type === AST_NODE_TYPES.Identifier &&
26
26
  expr.callee.name === 'require' &&
27
27
  expr.arguments.length === 1 &&
28
- expr.arguments[0].type === TSESTree.AST_NODE_TYPES.Literal);
28
+ expr.arguments[0].type === AST_NODE_TYPES.Literal);
29
29
  }
30
30
  function isCJSExports(context, node) {
31
- if (node.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
32
- node.object.type === TSESTree.AST_NODE_TYPES.Identifier &&
33
- node.property.type === TSESTree.AST_NODE_TYPES.Identifier &&
31
+ if (node.type === AST_NODE_TYPES.MemberExpression &&
32
+ node.object.type === AST_NODE_TYPES.Identifier &&
33
+ node.property.type === AST_NODE_TYPES.Identifier &&
34
34
  node.object.name === 'module' &&
35
35
  node.property.name === 'exports') {
36
36
  return !context.sourceCode
37
37
  .getScope(node)
38
38
  .variables.some((variable) => variable.name === 'module');
39
39
  }
40
- if (node.type === TSESTree.AST_NODE_TYPES.Identifier &&
41
- node.name === 'exports') {
40
+ if (node.type === AST_NODE_TYPES.Identifier && node.name === 'exports') {
42
41
  return !context.sourceCode
43
42
  .getScope(node)
44
43
  .variables.some((variable) => variable.name === 'exports');
@@ -46,14 +45,14 @@ function isCJSExports(context, node) {
46
45
  return false;
47
46
  }
48
47
  function getNamedCJSExports(context, node) {
49
- if (node.type !== TSESTree.AST_NODE_TYPES.MemberExpression) {
48
+ if (node.type !== AST_NODE_TYPES.MemberExpression) {
50
49
  return undefined;
51
50
  }
52
51
  const result = [];
53
52
  let root = node;
54
53
  let parent;
55
- while (root.type === TSESTree.AST_NODE_TYPES.MemberExpression) {
56
- if (root.property.type !== TSESTree.AST_NODE_TYPES.Identifier) {
54
+ while (root.type === AST_NODE_TYPES.MemberExpression) {
55
+ if (root.property.type !== AST_NODE_TYPES.Identifier) {
57
56
  return undefined;
58
57
  }
59
58
  result.unshift(root.property.name);
@@ -259,13 +258,13 @@ function makeOutOfOrderReport(context, imported) {
259
258
  }
260
259
  function isSimpleObjectPropertyList(properties) {
261
260
  return properties.every((p) => {
262
- if (p.type !== TSESTree.AST_NODE_TYPES.Property) {
261
+ if (p.type !== AST_NODE_TYPES.Property) {
263
262
  return false;
264
263
  }
265
- if (p.key.type !== TSESTree.AST_NODE_TYPES.Identifier) {
264
+ if (p.key.type !== AST_NODE_TYPES.Identifier) {
266
265
  return false;
267
266
  }
268
- return p.value.type === TSESTree.AST_NODE_TYPES.Identifier;
267
+ return p.value.type === AST_NODE_TYPES.Identifier;
269
268
  });
270
269
  }
271
270
  export default createRule({
@@ -280,9 +279,11 @@ export default createRule({
280
279
  type: 'object',
281
280
  properties: {
282
281
  ignoreCase: {
282
+ description: 'Whether to ignore case when sorting.',
283
283
  type: 'boolean',
284
284
  },
285
285
  types: {
286
+ description: 'Whether to group type and value imports/exports, and if so, which should come first.',
286
287
  type: 'string',
287
288
  enum: ['mixed', 'types-first', 'types-last'],
288
289
  },
@@ -290,6 +291,12 @@ export default createRule({
290
291
  additionalProperties: false,
291
292
  },
292
293
  ],
294
+ defaultOptions: [
295
+ {
296
+ ignoreCase: false,
297
+ types: 'types-first',
298
+ },
299
+ ],
293
300
  messages: {
294
301
  order: '{{secondImport}} should occur {{order}} {{firstImport}}',
295
302
  },
@@ -337,7 +344,7 @@ export default createRule({
337
344
  return;
338
345
  }
339
346
  makeNamedOrderReport(context, node.specifiers
340
- .filter((specifier) => specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier)
347
+ .filter((specifier) => specifier.type === AST_NODE_TYPES.ImportSpecifier)
341
348
  .map((specifier) => ({
342
349
  node: specifier,
343
350
  value: getValue(specifier.imported),
@@ -349,7 +356,7 @@ export default createRule({
349
356
  })));
350
357
  },
351
358
  VariableDeclarator(node) {
352
- if (node.id.type === TSESTree.AST_NODE_TYPES.ObjectPattern &&
359
+ if (node.id.type === AST_NODE_TYPES.ObjectPattern &&
353
360
  isRequireExpression(node.init)) {
354
361
  const { properties } = node.id;
355
362
  if (!isSimpleObjectPropertyList(properties)) {
@@ -381,9 +388,9 @@ export default createRule({
381
388
  })));
382
389
  },
383
390
  AssignmentExpression(node) {
384
- if (node.parent.type === TSESTree.AST_NODE_TYPES.ExpressionStatement) {
391
+ if (node.parent.type === AST_NODE_TYPES.ExpressionStatement) {
385
392
  if (isCJSExports(context, node.left)) {
386
- if (node.right.type === TSESTree.AST_NODE_TYPES.ObjectExpression) {
393
+ if (node.right.type === AST_NODE_TYPES.ObjectExpression) {
387
394
  const { properties } = node.right;
388
395
  if (!isSimpleObjectPropertyList(properties)) {
389
396
  return;
@@ -425,9 +432,9 @@ export default createRule({
425
432
  //region utils
426
433
  function getValue(node) {
427
434
  switch (node.type) {
428
- case TSESTree.AST_NODE_TYPES.Identifier:
435
+ case AST_NODE_TYPES.Identifier:
429
436
  return node.name;
430
- case TSESTree.AST_NODE_TYPES.Literal:
437
+ case AST_NODE_TYPES.Literal:
431
438
  return node.value;
432
439
  default:
433
440
  throw new Error(`Unsupported node type: ${node.type}`);
@@ -1,4 +1,4 @@
1
- import { type TSESLint, TSESTree } from '@typescript-eslint/utils';
1
+ import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
2
2
  export declare function findRootNode(node: TSESTree.Node): TSESTree.Node;
3
3
  export declare function findEndOfLineWithComments(sourceCode: TSESLint.SourceCode, node: TSESTree.Node): number;
4
4
  export declare function findStartOfLineWithComments(sourceCode: TSESLint.SourceCode, node: TSESTree.Node): number;
package/lib/utils/ast.js CHANGED
@@ -1,4 +1,4 @@
1
- import { TSESTree } from '@typescript-eslint/utils';
1
+ import { AST_TOKEN_TYPES } from '@typescript-eslint/types';
2
2
  export function findRootNode(node) {
3
3
  let parent = node;
4
4
  while (parent.parent != null &&
@@ -83,8 +83,8 @@ export function findEndOfLineWithComments(sourceCode, node) {
83
83
  return result;
84
84
  }
85
85
  function commentOnSameLineAs(node) {
86
- return (token) => (token.type === TSESTree.AST_TOKEN_TYPES.Block ||
87
- token.type === TSESTree.AST_TOKEN_TYPES.Line) &&
86
+ return (token) => (token.type === AST_TOKEN_TYPES.Block ||
87
+ token.type === AST_TOKEN_TYPES.Line) &&
88
88
  token.loc.start.line === token.loc.end.line &&
89
89
  token.loc.end.line === node.loc.end.line;
90
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrpalmer/eslint-plugin",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Custom ESLint rules for Mike Palmer's projects",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,16 +16,22 @@
16
16
  "lib"
17
17
  ],
18
18
  "dependencies": {
19
- "@typescript-eslint/utils": "^8.29.1",
19
+ "@typescript-eslint/types": "^8.36.0",
20
20
  "get-tsconfig": "^4.10.0",
21
21
  "minimatch": "^10.0.1"
22
22
  },
23
23
  "peerDependencies": {
24
+ "@typescript-eslint/utils": "^8.0.0",
24
25
  "eslint": "^9.0.0"
25
26
  },
27
+ "peerDependenciesMeta": {
28
+ "@typescript-eslint/utils": {
29
+ "optional": true
30
+ }
31
+ },
26
32
  "engines": {
27
33
  "node": ">=20",
28
- "npm": ">=8",
34
+ "npm": ">=10",
29
35
  "yarn": ">=1"
30
36
  }
31
37
  }