eslint-rule-forge 0.3.2 → 0.5.0

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 (51) hide show
  1. package/README.md +47 -40
  2. package/dist/bindings.d.mts +4 -5
  3. package/dist/bindings.d.mts.map +1 -1
  4. package/dist/bindings.mjs +0 -1
  5. package/dist/bindings.mjs.map +1 -1
  6. package/dist/comments.d.mts +10 -0
  7. package/dist/comments.d.mts.map +1 -0
  8. package/dist/comments.mjs +11 -0
  9. package/dist/comments.mjs.map +1 -0
  10. package/dist/imports.d.mts +68 -8
  11. package/dist/imports.d.mts.map +1 -1
  12. package/dist/imports.mjs +202 -6
  13. package/dist/imports.mjs.map +1 -1
  14. package/dist/index.d.mts +2 -0
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +2 -0
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/negation.d.mts +8 -9
  19. package/dist/negation.d.mts.map +1 -1
  20. package/dist/negation.mjs +18 -18
  21. package/dist/negation.mjs.map +1 -1
  22. package/dist/rules/prefer-array-is-array.d.mts.map +1 -1
  23. package/dist/rules/prefer-array-is-array.mjs +13 -19
  24. package/dist/rules/prefer-array-is-array.mjs.map +1 -1
  25. package/dist/rules/prefer-is-non-null-object.d.mts.map +1 -1
  26. package/dist/rules/prefer-is-non-null-object.mjs +75 -76
  27. package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
  28. package/dist/rules/prefer-is-record-and-has-key.d.mts.map +1 -1
  29. package/dist/rules/prefer-is-record-and-has-key.mjs +32 -44
  30. package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
  31. package/dist/rules/prefer-safe-parse.d.mts +10 -7
  32. package/dist/rules/prefer-safe-parse.d.mts.map +1 -1
  33. package/dist/rules/prefer-safe-parse.mjs +50 -34
  34. package/dist/rules/prefer-safe-parse.mjs.map +1 -1
  35. package/dist/statements.d.mts +12 -0
  36. package/dist/statements.d.mts.map +1 -0
  37. package/dist/statements.mjs +39 -0
  38. package/dist/statements.mjs.map +1 -0
  39. package/dist/type-wrappers.d.mts +3 -3
  40. package/package.json +5 -5
  41. package/src/bindings.mts +4 -5
  42. package/src/comments.mts +23 -0
  43. package/src/imports.mts +363 -19
  44. package/src/index.mts +2 -0
  45. package/src/negation.mts +36 -37
  46. package/src/rules/prefer-array-is-array.mts +23 -36
  47. package/src/rules/prefer-is-non-null-object.mts +107 -112
  48. package/src/rules/prefer-is-record-and-has-key.mts +47 -71
  49. package/src/rules/prefer-safe-parse.mts +92 -77
  50. package/src/statements.mts +57 -0
  51. package/src/type-wrappers.mts +3 -3
@@ -1,6 +1,7 @@
1
1
  import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
2
2
  import * as ts from 'typescript';
3
- import { buildNamedImportFix, getImportDeclarations, getNamedImports, } from '../imports.mjs';
3
+ import { hasForeignBinding } from '../bindings.mjs';
4
+ import { bindValueImports } from '../imports.mjs';
4
5
  import { getArgumentText } from '../parentheses.mjs';
5
6
  import { isIdentifierNamed, skipTypeWrappers, typeHoldsAtEveryLayer, } from '../type-wrappers.mjs';
6
7
 
@@ -11,6 +12,7 @@ import { isIdentifierNamed, skipTypeWrappers, typeHoldsAtEveryLayer, } from '../
11
12
 
12
13
 
13
14
 
15
+
14
16
  export const createPreferSafeParseInt = (config) => createSafeParseRule(config, 'useSafeParseInt', {
15
17
  messages: { useSafeParseInt: messageText(config) },
16
18
  description: `Replace \`parseInt(x)\` or \`Number.parseInt(x, 10)\` with \`Result.unwrapOkOr(${config.namespace}.${config.method}(x), Number.NaN)\` from ${config.moduleName}.`,
@@ -33,6 +35,8 @@ export const createPreferSafeParseInt = (config) => createSafeParseRule(config,
33
35
 
34
36
 
35
37
 
38
+
39
+
36
40
  export const createPreferSafeParseFloat = (config) => createSafeParseRule(config, 'useSafeParseFloat', {
37
41
  messages: { useSafeParseFloat: messageText(config) },
38
42
  description: `Replace \`parseFloat(x)\`, \`Number.parseFloat(x)\`, or \`Number(x)\` (when x is a string) with \`Result.unwrapOkOr(${config.namespace}.${config.method}(x), Number.NaN)\` from ${config.moduleName}.`,
@@ -43,24 +47,34 @@ export const createPreferSafeParseFloat = (config) => createSafeParseRule(config
43
47
  isGlobalCall(callee, 'Number'),
44
48
  });
45
49
 
50
+
51
+
52
+
53
+
54
+
55
+ const isStringType = (type) => {
56
+ const parts = type.isUnion() ? type.types : [type];
57
+ return (parts.length > 0 &&
58
+ parts.every((t) => (t.flags & ts.TypeFlags.StringLike) !== 0));
59
+ };
46
60
  const createSafeParseRule = ({ moduleName, namespace, method }, messageId, { messages, description, isTarget, }) => {
47
- const parseFunction = `${namespace}.${method}`;
48
61
 
49
62
  const requiredImports = [namespace, 'Result'].toSorted();
50
63
  return {
51
64
  meta: {
52
65
  type: 'suggestion',
53
66
  docs: { description },
54
- fixable: 'code',
67
+ hasSuggestions: true,
55
68
  schema: [],
56
- messages,
69
+ messages: {
70
+ ...messages,
71
+ replaceWithSafeParse: `Replace with \`Result.unwrapOkOr(${namespace}.${method}({{argName}}), Number.NaN)\`.`,
72
+ },
57
73
  defaultOptions: [],
58
74
  },
59
75
  create: (context) => {
60
76
  const sourceCode = context.sourceCode;
61
- const program = sourceCode.ast;
62
- const moduleImports = getImportDeclarations(program, moduleName);
63
- const mut_nodesToFix = [];
77
+ const mut_reports = [];
64
78
  return {
65
79
  CallExpression: (node) => {
66
80
  if (!isTarget(skipTypeWrappers(node.callee), node.arguments)) {
@@ -68,7 +82,6 @@ const createSafeParseRule = ({ moduleName, namespace, method }, messageId, { mes
68
82
  }
69
83
  const firstArg = node.arguments[0];
70
84
 
71
-
72
85
  if (firstArg === undefined ||
73
86
  firstArg.type === AST_NODE_TYPES.SpreadElement) {
74
87
  return;
@@ -83,30 +96,43 @@ const createSafeParseRule = ({ moduleName, namespace, method }, messageId, { mes
83
96
  if (!typeHoldsAtEveryLayer(sourceCode, firstArg, isStringType)) {
84
97
  return;
85
98
  }
86
- mut_nodesToFix.push({ node, argExpression: firstArg });
99
+ mut_reports.push({ node, argExpression: firstArg });
87
100
  },
88
101
  'Program:exit': () => {
89
- const namedImports = getNamedImports(moduleImports);
90
- const missingImports = requiredImports.filter((name) => !namedImports.includes(name));
102
+ const binding = bindValueImports(sourceCode, moduleName, requiredImports);
103
+ const localNameOf = (name) => binding?.localNames[requiredImports.indexOf(name)];
104
+ const namespaceName = localNameOf(namespace);
105
+ const resultName = localNameOf('Result');
106
+
91
107
 
92
108
 
93
109
 
94
- for (const [index, { node, argExpression },] of mut_nodesToFix.entries()) {
110
+
111
+ for (const { node, argExpression } of mut_reports) {
95
112
  const argText = getArgumentText(sourceCode, argExpression);
113
+ const data = {
114
+ original: sourceCode.getText(node),
115
+ argName: argText,
116
+ };
96
117
  context.report({
97
118
  node,
98
119
  messageId,
99
- data: {
100
- original: sourceCode.getText(node),
101
- argName: argText,
102
- },
103
- fix: (fixer) => {
104
- const core = `Result.unwrapOkOr(${parseFunction}(${argText}), Number.NaN)`;
105
- const importFixes = index === 0 && missingImports.length > 0
106
- ? buildNamedImportFix(fixer, program, moduleName, missingImports)
107
- : [];
108
- return [...importFixes, fixer.replaceText(node, core)];
109
- },
120
+ data,
121
+ suggest: binding === undefined ||
122
+ namespaceName === undefined ||
123
+ resultName === undefined ||
124
+ [namespaceName, resultName].some((name) => hasForeignBinding(sourceCode, node, name, moduleName))
125
+ ? []
126
+ : [
127
+ {
128
+ messageId: 'replaceWithSafeParse',
129
+ data,
130
+ fix: (fixer) => [
131
+ ...binding.edits(fixer),
132
+ fixer.replaceText(node, `${resultName}.unwrapOkOr(${namespaceName}.${method}(${argText}), Number.NaN)`),
133
+ ],
134
+ },
135
+ ],
110
136
  });
111
137
  }
112
138
  },
@@ -114,7 +140,7 @@ const createSafeParseRule = ({ moduleName, namespace, method }, messageId, { mes
114
140
  },
115
141
  };
116
142
  };
117
- const messageText = ({ moduleName, namespace, method, }) => `Replace \`{{original}}\` with \`Result.unwrapOkOr(${namespace}.${method}({{argName}}), Number.NaN)\` from ${moduleName}.`;
143
+ const messageText = ({ moduleName, namespace, method, }) => `Replace \`{{original}}\` with \`Result.unwrapOkOr(${namespace}.${method}({{argName}}), Number.NaN)\` from ${moduleName}. It parses some strings differently from the call it replaces, so check the input before applying it.`;
118
144
 
119
145
  const isGlobalCall = (callee, name) => callee.type === AST_NODE_TYPES.Identifier && callee.name === name;
120
146
 
@@ -126,14 +152,4 @@ const isNumberMethod = (callee, name) => callee.type === AST_NODE_TYPES.MemberEx
126
152
  isIdentifierNamed(callee.object, 'Number') &&
127
153
  callee.property.type === AST_NODE_TYPES.Identifier &&
128
154
  callee.property.name === name;
129
-
130
-
131
-
132
-
133
-
134
- const isStringType = (type) => {
135
- const parts = type.isUnion() ? type.types : [type];
136
- return (parts.length > 0 &&
137
- parts.every((t) => (t.flags & ts.TypeFlags.StringLike) !== 0));
138
- };
139
155
  //# sourceMappingURL=prefer-safe-parse.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-safe-parse.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-parse.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAiB9B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,MAA2B,EAC0B,EAAE,CACvD,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,EAAE;IAC7C,QAAQ,EAAE,EAAE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE;IAClD,WAAW,EAAE,kFAAkF,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,2BAA2B,MAAM,CAAC,UAAU,GAAG;IAC/K,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACzB,IACE,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC;YACjC,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,EACnC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,oEAAoE;QACpE,kEAAkE;QAClE,MAAM,KAAK,GACT,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,OAAO,CACL,KAAK,KAAK,SAAS;YACnB,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC,CAC9D,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEL;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,MAA2B,EAC4B,EAAE,CACzD,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,EAAE;IAC/C,QAAQ,EAAE,EAAE,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE;IACpD,WAAW,EAAE,uHAAuH,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,2BAA2B,MAAM,CAAC,UAAU,GAAG;IACpN,kEAAkE;IAClE,iDAAiD;IACjD,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CACnB,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC;QAClC,cAAc,CAAC,MAAM,EAAE,YAAY,CAAC;QACpC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;CACjC,CAAC,CAAC;AAEL,uEAAuE;AAEvE,MAAM,mBAAmB,GAAG,CAC1B,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAuB,EACtD,SAAoB,EACpB,EACE,QAAQ,EACR,WAAW,EACX,QAAQ,GAcR,EAC2C,EAAE;IAC/C,MAAM,aAAa,GAAG,GAAG,SAAS,IAAI,MAAM,EAAW,CAAC;IAExD,gDAAgD;IAChD,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEzD,OAAO;QACL,IAAI,EAAE;YACJ,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,EAAE,WAAW,EAAE;YACrB,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,EAAE;YACV,QAAQ;YACR,cAAc,EAAE,EAAE;SACnB;QAED,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;YAClB,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;YAEtC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC;YAE/B,MAAM,aAAa,GAAG,qBAAqB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAEjE,MAAM,cAAc,GAGd,EAAE,CAAC;YAET,OAAO;gBACL,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE;oBACvB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC7D,OAAO;oBACT,CAAC;oBAED,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAEnC,8DAA8D;oBAC9D,UAAU;oBACV,IACE,QAAQ,KAAK,SAAS;wBACtB,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,aAAa,EAC9C,CAAC;wBACD,OAAO;oBACT,CAAC;oBAED,8DAA8D;oBAC9D,kEAAkE;oBAClE,gEAAgE;oBAChE,oEAAoE;oBACpE,iEAAiE;oBACjE,kEAAkE;oBAClE,0BAA0B;oBAC1B,IAAI,CAAC,qBAAqB,CAAC,UAAU,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC;wBAC/D,OAAO;oBACT,CAAC;oBAED,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACzD,CAAC;gBACD,cAAc,EAAE,GAAG,EAAE;oBACnB,MAAM,YAAY,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;oBAEpD,MAAM,cAAc,GAAG,eAAe,CAAC,MAAM,CAC3C,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CACvC,CAAC;oBAEF,iDAAiD;oBACjD,6DAA6D;oBAC7D,uDAAuD;oBACvD,KAAK,MAAM,CACT,KAAK,EACL,EAAE,IAAI,EAAE,aAAa,EAAE,EACxB,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC;wBAC9B,MAAM,OAAO,GAAG,eAAe,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;wBAE3D,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI;4BACJ,SAAS;4BACT,IAAI,EAAE;gCACJ,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;gCAClC,OAAO,EAAE,OAAO;6BACjB;4BACD,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE;gCACb,MAAM,IAAI,GACR,qBAAqB,aAAa,IAAI,OAAO,gBAAyB,CAAC;gCAEzE,MAAM,WAAW,GACf,KAAK,KAAK,CAAC,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;oCACtC,CAAC,CAAC,mBAAmB,CACjB,KAAK,EACL,OAAO,EACP,UAAU,EACV,cAAc,CACf;oCACH,CAAC,CAAE,EAAY,CAAC;gCAEpB,OAAO,CAAC,GAAG,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;4BACzD,CAAC;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;aACF,CAAC;QACJ,CAAC;KACO,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,EACnB,UAAU,EACV,SAAS,EACT,MAAM,GACc,EAAU,EAAE,CAChC,qDAAqD,SAAS,IAAI,MAAM,qCAAqC,UAAU,GAAY,CAAC;AAEtI,6EAA6E;AAC7E,MAAM,YAAY,GAAG,CAAC,MAA2B,EAAE,IAAY,EAAW,EAAE,CAC1E,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC;AAEpE;;;GAGG;AACH,MAAM,cAAc,GAAG,CAAC,MAA2B,EAAE,IAAY,EAAW,EAAE,CAC5E,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB;IAC/C,CAAC,MAAM,CAAC,QAAQ;IAChB,iBAAiB,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1C,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU;IAClD,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC;AAEhC;;;;GAIG;AACH,MAAM,YAAY,GAAG,CAAC,IAAa,EAAW,EAAE;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,CAAW,CAAC;IAE9D,OAAO,CACL,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAC9D,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"prefer-safe-parse.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-parse.mts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type TSESTree } from '@typescript-eslint/utils';
2
+ import type { DeepReadonly } from 'ts-type-forge';
3
+ /**
4
+ * The statement next to `node` (`offset` 1) or before it (-1) in the statement
5
+ * list `node` is one of: the program's, a block's, a class static block's, a
6
+ * namespace's or a `case`'s. What an `export` declares (or, for
7
+ * `export default`, the expression it exports) is read as the `export`
8
+ * statement. `undefined` when there is none, or when `node` is not in a
9
+ * statement list (an arrow function's expression body, a `for` initializer).
10
+ */
11
+ export declare const siblingOf: (node: DeepReadonly<TSESTree.Node>, offset: 1 | -1) => DeepReadonly<TSESTree.Node> | undefined;
12
+ //# sourceMappingURL=statements.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statements.d.mts","sourceRoot":"","sources":["../src/statements.mts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,SACd,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,UACzB,CAAC,GAAG,CAAC,CAAC,KACb,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,SAmBhC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+ export const siblingOf = (node, offset) => {
11
+ const { parent } = node;
12
+ const statement = (parent?.type === AST_NODE_TYPES.ExportNamedDeclaration ||
13
+ parent?.type === AST_NODE_TYPES.ExportDefaultDeclaration) &&
14
+ parent.declaration === node
15
+ ? parent
16
+ : node;
17
+ const list = statementListOf(statement);
18
+ if (list === undefined) {
19
+ return undefined;
20
+ }
21
+ const index = list.indexOf(statement);
22
+ return index === -1 ? undefined : list[index + offset];
23
+ };
24
+ const statementListOf = (node) => {
25
+ const { parent } = node;
26
+ if (parent === undefined) {
27
+ return undefined;
28
+ }
29
+ if (parent.type === AST_NODE_TYPES.Program ||
30
+ parent.type === AST_NODE_TYPES.BlockStatement ||
31
+ parent.type === AST_NODE_TYPES.StaticBlock ||
32
+ parent.type === AST_NODE_TYPES.TSModuleBlock) {
33
+ return parent.body;
34
+ }
35
+ return parent.type === AST_NODE_TYPES.SwitchCase
36
+ ? parent.consequent
37
+ : undefined;
38
+ };
39
+ //# sourceMappingURL=statements.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statements.mjs","sourceRoot":"","sources":["../src/statements.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAiB,MAAM,0BAA0B,CAAC;AAGzE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAiC,EACjC,MAAc,EAC2B,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAExB,MAAM,SAAS,GACb,CAAC,MAAM,EAAE,IAAI,KAAK,cAAc,CAAC,sBAAsB;QACrD,MAAM,EAAE,IAAI,KAAK,cAAc,CAAC,wBAAwB,CAAC;QAC3D,MAAM,CAAC,WAAW,KAAK,IAAI;QACzB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,IAAI,CAAC;IAEX,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAExC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEtC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;AACzD,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CACtB,IAAiC,EACmB,EAAE;IACtD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAExB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IACE,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO;QACtC,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,cAAc;QAC7C,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,WAAW;QAC1C,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,aAAa,EAC5C,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU;QAC9C,CAAC,CAAC,MAAM,CAAC,UAAU;QACnB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC,CAAC"}
@@ -51,9 +51,9 @@ export declare const isIdentifierNamed: (node: DeepReadonly<TSESTree.Node>, name
51
51
  * Whether `holds` is true of the type of every layer of type wrappers around
52
52
  * `node` (see {@link typeWrapperLayers}), outermost to innermost; `false`
53
53
  * without type information. A widening cast (`s as string | number`) is the
54
- * author saying the value may be more than it is, and is respected; a
55
- * narrowing one (`s!`, `v as unknown as string`) cannot vouch for what the
56
- * value's own type does not, and the fix, which keeps the wrapper, has to
54
+ * author saying the value may be more than it is, and is respected; a narrowing
55
+ * one (`s!`, `v as unknown as string`) cannot vouch for what the value's own
56
+ * type does not, and the fix, which keeps the wrapper, has to
57
57
  * type-check at every layer too.
58
58
  */
59
59
  export declare const typeHoldsAtEveryLayer: (sourceCode: TSESLint.SourceCode, node: TSESTree.Node, holds: (type: ts.Type, typeChecker: ts.TypeChecker) => boolean) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-rule-forge",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "description": "Helpers for writing typescript-eslint rules that see through type wrappers and parentheses, and resolve what a file imports.",
6
6
  "keywords": [
@@ -41,13 +41,13 @@
41
41
  "@typescript-eslint/rule-tester": "8.72.0",
42
42
  "dedent": "1.7.2",
43
43
  "eslint": "10.13.0",
44
- "eslint-config-typed": "5.20.1",
45
- "eslint-plugin-ts-fortress": "1.3.9",
46
- "eslint-plugin-ts-type-forge": "0.8.14",
44
+ "eslint-config-typed": "7.3.0",
45
+ "eslint-plugin-ts-fortress": "1.3.12",
46
+ "eslint-plugin-ts-type-forge": "0.8.17",
47
47
  "prettier": "3.9.10",
48
48
  "prettier-plugin-organize-imports": "4.3.0",
49
49
  "prettier-plugin-packagejson": "3.0.2",
50
- "ts-data-forge": "14.10.0",
50
+ "ts-data-forge": "14.10.1",
51
51
  "ts-repo-utils": "10.7.1"
52
52
  },
53
53
  "peerDependencies": {
package/src/bindings.mts CHANGED
@@ -8,8 +8,8 @@ import {
8
8
  /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
9
9
 
10
10
  /**
11
- * Whether `name`, read at `node`, resolves to something this file writes down
12
- * — a declaration, a parameter, an import — rather than to a global or a
11
+ * Whether `name`, read at `node`, resolves to something this file writes down —
12
+ * a declaration, a parameter, an import — rather than to a global or a
13
13
  * standard-library type of the same name.
14
14
  *
15
15
  * The scope manager makes an implicit variable for every reference it cannot
@@ -29,9 +29,8 @@ export const isLocallyBound = (
29
29
  /**
30
30
  * Whether `name`, read at `node`, resolves to a binding that is not an import
31
31
  * from `moduleName` — a declaration, a parameter, or an import from another
32
- * module. A fix that makes code at `node` refer to `moduleName`'s export
33
- * `name` has to give up then, because the name would refer to that binding
34
- * instead.
32
+ * module. A fix that makes code at `node` refer to `moduleName`'s export `name`
33
+ * has to give up then, because the name would refer to that binding instead.
35
34
  *
36
35
  * The innermost binding decides: an import from `moduleName` at the top of the
37
36
  * file does not help a name a function shadows around `node`.
@@ -0,0 +1,23 @@
1
+ import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
2
+ import type { DeepReadonly } from 'ts-type-forge';
3
+
4
+ /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
5
+
6
+ /**
7
+ * Whether a comment inside `node` lies within one of `ranges`, which a fix
8
+ * would delete along with it. Such a fix is dropped instead of the comment.
9
+ * Only comments inside `node` are looked at, so each range has to lie within
10
+ * it.
11
+ */
12
+ export const hasCommentWithin = (
13
+ sourceCode: TSESLint.SourceCode,
14
+ node: TSESTree.Node,
15
+ ranges: DeepReadonly<TSESTree.Range[]>,
16
+ ): boolean =>
17
+ sourceCode
18
+ .getCommentsInside(node)
19
+ .some((comment) =>
20
+ ranges.some(
21
+ ([start, end]) => start <= comment.range[0] && comment.range[1] <= end,
22
+ ),
23
+ );