@venizia/dev-configs 0.4.8-2 → 0.4.8-4

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 (48) hide show
  1. package/README.md +4 -3
  2. package/dist/cli/codemod/async-style.d.ts +2 -2
  3. package/dist/cli/codemod/async-style.js +4 -2
  4. package/dist/cli/codemod/async-style.js.map +1 -1
  5. package/dist/cli/codemod/namespace-functions/rewriter.js +1 -1
  6. package/dist/cli/codemod/namespace-functions/rewriter.js.map +1 -1
  7. package/dist/linters/eslint.js +6 -1
  8. package/dist/linters/eslint.js.map +1 -1
  9. package/dist/linters/house/async-rules.d.ts +1 -1
  10. package/dist/linters/house/async-rules.js +3 -1
  11. package/dist/linters/house/async-rules.js.map +1 -1
  12. package/dist/linters/house/await-support.js +45 -38
  13. package/dist/linters/house/await-support.js.map +1 -1
  14. package/dist/linters/house/common.d.ts +43 -0
  15. package/dist/linters/house/common.js +43 -0
  16. package/dist/linters/house/common.js.map +1 -1
  17. package/dist/linters/house/const-class-values.rule.js +9 -8
  18. package/dist/linters/house/const-class-values.rule.js.map +1 -1
  19. package/dist/linters/house/hook-support.js +11 -7
  20. package/dist/linters/house/hook-support.js.map +1 -1
  21. package/dist/linters/house/index.d.ts +1 -0
  22. package/dist/linters/house/index.js +1 -0
  23. package/dist/linters/house/index.js.map +1 -1
  24. package/dist/linters/house/max-params-own.rule.js +12 -11
  25. package/dist/linters/house/max-params-own.rule.js.map +1 -1
  26. package/dist/linters/house/no-await-new-chain.rule.d.ts +37 -0
  27. package/dist/linters/house/no-await-new-chain.rule.js +179 -0
  28. package/dist/linters/house/no-await-new-chain.rule.js.map +1 -0
  29. package/dist/linters/house/no-await-promise-chain.rule.js +23 -22
  30. package/dist/linters/house/no-await-promise-chain.rule.js.map +1 -1
  31. package/dist/linters/house/no-inline-await.rule.js +4 -3
  32. package/dist/linters/house/no-inline-await.rule.js.map +1 -1
  33. package/dist/linters/house/no-leaked-render.rule.js +3 -3
  34. package/dist/linters/house/no-leaked-render.rule.js.map +1 -1
  35. package/dist/linters/house/no-new-error.rule.js +1 -1
  36. package/dist/linters/house/no-new-error.rule.js.map +1 -1
  37. package/dist/linters/house/no-return-await.rule.js +5 -4
  38. package/dist/linters/house/no-return-await.rule.js.map +1 -1
  39. package/dist/linters/house/no-silent-catch.rule.js +4 -3
  40. package/dist/linters/house/no-silent-catch.rule.js.map +1 -1
  41. package/dist/linters/house/plugin.js +2 -0
  42. package/dist/linters/house/plugin.js.map +1 -1
  43. package/dist/linters/house/promise-chain-support.js +25 -25
  44. package/dist/linters/house/promise-chain-support.js.map +1 -1
  45. package/dist/linters/oxlint.d.ts +6 -5
  46. package/dist/linters/oxlint.js +8 -3
  47. package/dist/linters/oxlint.js.map +1 -1
  48. package/package.json +1 -1
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MaxParamsOwnRule = void 0;
4
4
  const common_1 = require("./common");
5
5
  const HOOK_NAME = /^use[A-Z]/;
6
- const CALL_TYPES = new Set(['CallExpression', 'NewExpression']);
6
+ const CALL_TYPES = new Set([common_1.AstNodeTypes.CALL_EXPRESSION, common_1.AstNodeTypes.NEW_EXPRESSION]);
7
7
  const isArrayContaining = (opts) => Array.isArray(opts.list) && opts.list.includes(opts.item);
8
8
  /** `useX(...)`: a hook's callback is ours, so it counts. */
9
9
  const isHookCall = (call) => {
10
10
  const callee = common_1.AstNode.readField({ node: call, key: 'callee' });
11
11
  const name = common_1.AstNode.readField({ node: callee, key: 'name' });
12
- return (common_1.AstNode.getType({ node: callee }) === 'Identifier' &&
12
+ return (common_1.AstNode.getType({ node: callee }) === common_1.AstNodeTypes.IDENTIFIER &&
13
13
  typeof name === 'string' &&
14
14
  HOOK_NAME.test(name));
15
15
  };
@@ -29,17 +29,18 @@ const hasDeclaredShape = (object) => {
29
29
  while (current) {
30
30
  const parent = common_1.AstNode.readField({ node: current, key: 'parent' });
31
31
  const parentType = common_1.AstNode.getType({ node: parent });
32
- const isTypedVariable = parentType === 'VariableDeclarator' &&
32
+ const isTypedVariable = parentType === common_1.AstNodeTypes.VARIABLE_DECLARATOR &&
33
33
  Boolean(common_1.AstNode.readField({
34
34
  node: common_1.AstNode.readField({ node: parent, key: 'id' }),
35
35
  key: 'typeAnnotation',
36
36
  }));
37
37
  if (isTypedVariable ||
38
- parentType === 'TSSatisfiesExpression' ||
38
+ parentType === common_1.AstNodeTypes.SATISFIES_EXPRESSION ||
39
39
  isLibraryArgument({ node: current, parent })) {
40
40
  return true;
41
41
  }
42
- const isNestedValue = parentType === 'Property' && common_1.AstNode.readField({ node: parent, key: 'value' }) === current;
42
+ const isNestedValue = parentType === common_1.AstNodeTypes.PROPERTY &&
43
+ common_1.AstNode.readField({ node: parent, key: 'value' }) === current;
43
44
  current = isNestedValue ? common_1.AstNode.readField({ node: parent, key: 'parent' }) : undefined;
44
45
  }
45
46
  return false;
@@ -66,9 +67,9 @@ class MaxParamsOwnRule {
66
67
  const max = typeof context.options[0] === 'number' ? context.options[0] : MaxParamsOwnRule.DEFAULT_MAX;
67
68
  const isCallback = (node) => {
68
69
  const parent = node.parent;
69
- const isJsxProp = common_1.AstNode.getType({ node: parent }) === 'JSXExpressionContainer' &&
70
+ const isJsxProp = common_1.AstNode.getType({ node: parent }) === common_1.AstNodeTypes.JSX_EXPRESSION_CONTAINER &&
70
71
  common_1.AstNode.getType({ node: common_1.AstNode.readField({ node: parent, key: 'parent' }) }) ===
71
- 'JSXAttribute';
72
+ common_1.AstNodeTypes.JSX_ATTRIBUTE;
72
73
  return isJsxProp || isLibraryArgument({ node, parent });
73
74
  };
74
75
  const isInjectedConstructor = (opts) => {
@@ -82,23 +83,23 @@ class MaxParamsOwnRule {
82
83
  return ((Array.isArray(own) && own.length > 0) ||
83
84
  (Array.isArray(property) && property.length > 0));
84
85
  };
85
- return (common_1.AstNode.getType({ node: parent }) === 'MethodDefinition' &&
86
+ return (common_1.AstNode.getType({ node: parent }) === common_1.AstNodeTypes.METHOD_DEFINITION &&
86
87
  common_1.AstNode.readField({ node: parent, key: 'kind' }) === 'constructor' &&
87
88
  opts.params.every(isDecorated));
88
89
  };
89
90
  const isTypedByContext = (node) => {
90
91
  const parent = node.parent;
91
92
  const parentType = common_1.AstNode.getType({ node: parent });
92
- const isTypedInit = parentType === 'VariableDeclarator' &&
93
+ const isTypedInit = parentType === common_1.AstNodeTypes.VARIABLE_DECLARATOR &&
93
94
  common_1.AstNode.readField({ node: parent, key: 'init' }) === node &&
94
95
  Boolean(common_1.AstNode.readField({
95
96
  node: common_1.AstNode.readField({ node: parent, key: 'id' }),
96
97
  key: 'typeAnnotation',
97
98
  }));
98
99
  const grandParent = common_1.AstNode.readField({ node: parent, key: 'parent' });
99
- const isMember = parentType === 'Property' &&
100
+ const isMember = parentType === common_1.AstNodeTypes.PROPERTY &&
100
101
  common_1.AstNode.readField({ node: parent, key: 'value' }) === node &&
101
- common_1.AstNode.getType({ node: grandParent }) === 'ObjectExpression';
102
+ common_1.AstNode.getType({ node: grandParent }) === common_1.AstNodeTypes.OBJECT_EXPRESSION;
102
103
  return isTypedInit || (isMember && hasDeclaredShape(grandParent));
103
104
  };
104
105
  const check = (node) => {
@@ -1 +1 @@
1
- {"version":3,"file":"max-params-own.rule.js","sourceRoot":"","sources":["../../../src/linters/house/max-params-own.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Linter, Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst CALL_TYPES = new Set(['CallExpression', 'NewExpression']);\n\nconst isArrayContaining = (opts: { list: unknown; item: unknown }) =>\n Array.isArray(opts.list) && opts.list.includes(opts.item);\n\n/** `useX(...)`: a hook's callback is ours, so it counts. */\nconst isHookCall = (call: unknown) => {\n const callee = AstNode.readField({ node: call, key: 'callee' });\n const name = AstNode.readField({ node: callee, key: 'name' });\n\n return (\n AstNode.getType({ node: callee }) === 'Identifier' &&\n typeof name === 'string' &&\n HOOK_NAME.test(name)\n );\n};\n\n/** `node` is an argument of a call or `new` that is not a hook. */\nconst isLibraryArgument = (opts: { node: unknown; parent: unknown }) =>\n CALL_TYPES.has(AstNode.getType({ node: opts.parent }) ?? '') &&\n isArrayContaining({\n list: AstNode.readField({ node: opts.parent, key: 'arguments' }),\n item: opts.node,\n }) &&\n !isHookCall(opts.parent);\n\n/**\n * An object literal whose shape something else declares: a typed variable, `satisfies`, or an argument\n * of a non-hook call (a library option bag). A nested literal inherits it.\n */\nconst hasDeclaredShape = (object: unknown): boolean => {\n let current = object;\n\n while (current) {\n const parent = AstNode.readField({ node: current, key: 'parent' });\n const parentType = AstNode.getType({ node: parent });\n const isTypedVariable =\n parentType === 'VariableDeclarator' &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n\n if (\n isTypedVariable ||\n parentType === 'TSSatisfiesExpression' ||\n isLibraryArgument({ node: current, parent })\n ) {\n return true;\n }\n\n const isNestedValue =\n parentType === 'Property' && AstNode.readField({ node: parent, key: 'value' }) === current;\n current = isNestedValue ? AstNode.readField({ node: parent, key: 'parent' }) : undefined;\n }\n\n return false;\n};\n\n/**\n * `venizia/max-params-own`. A function we write takes at most `max` positional parameters;\n * beyond that it takes one options object. A signature that belongs to someone else is not counted: an\n * inline callback handed to a call (map, reduce, sort, a library handler) or to a JSX prop, a function a\n * declared type fixes (`const x: TFn = (...)`, a member of a typed or `satisfies` object), and a\n * constructor whose every parameter is injected (`@inject`). A hook's callback (`useCallback(...)`) is ours.\n */\nexport class MaxParamsOwnRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/max-params-own`;\n\n static readonly DEFAULT_MAX = 5;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n schema: [{ type: 'integer', minimum: 0 }],\n messages: {\n tooMany:\n 'A function we write takes up to {{max}} positional parameters, not {{count}}: take one options object.',\n },\n },\n create: (context) => {\n const max =\n typeof context.options[0] === 'number' ? context.options[0] : MaxParamsOwnRule.DEFAULT_MAX;\n\n const isCallback = (node: Rule.Node) => {\n const parent = node.parent;\n const isJsxProp =\n AstNode.getType({ node: parent }) === 'JSXExpressionContainer' &&\n AstNode.getType({ node: AstNode.readField({ node: parent, key: 'parent' }) }) ===\n 'JSXAttribute';\n\n return isJsxProp || isLibraryArgument({ node, parent });\n };\n\n const isInjectedConstructor = (opts: { node: Rule.Node; params: unknown[] }) => {\n const parent = opts.node.parent;\n\n const isDecorated = (param: unknown) => {\n const own = AstNode.readField({ node: param, key: 'decorators' });\n const property = AstNode.readField({\n node: AstNode.readField({ node: param, key: 'parameter' }),\n key: 'decorators',\n });\n\n return (\n (Array.isArray(own) && own.length > 0) ||\n (Array.isArray(property) && property.length > 0)\n );\n };\n\n return (\n AstNode.getType({ node: parent }) === 'MethodDefinition' &&\n AstNode.readField({ node: parent, key: 'kind' }) === 'constructor' &&\n opts.params.every(isDecorated)\n );\n };\n\n const isTypedByContext = (node: Rule.Node) => {\n const parent = node.parent;\n const parentType = AstNode.getType({ node: parent });\n const isTypedInit =\n parentType === 'VariableDeclarator' &&\n AstNode.readField({ node: parent, key: 'init' }) === node &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n const grandParent = AstNode.readField({ node: parent, key: 'parent' });\n const isMember =\n parentType === 'Property' &&\n AstNode.readField({ node: parent, key: 'value' }) === node &&\n AstNode.getType({ node: grandParent }) === 'ObjectExpression';\n\n return isTypedInit || (isMember && hasDeclaredShape(grandParent));\n };\n\n const check = (node: Rule.Node) => {\n const params = AstNode.readField({ node, key: 'params' });\n\n if (!Array.isArray(params) || params.length <= max) {\n return;\n }\n\n if (isCallback(node) || isInjectedConstructor({ node, params }) || isTypedByContext(node)) {\n return;\n }\n\n context.report({\n node,\n messageId: 'tooMany',\n data: { count: String(params.length), max: String(max) },\n });\n };\n\n return {\n [AstNodeTypes.FUNCTION_DECLARATION]: check,\n [AstNodeTypes.FUNCTION_EXPRESSION]: check,\n [AstNodeTypes.ARROW_FUNCTION_EXPRESSION]: check,\n };\n },\n };\n\n static build(\n opts: {\n /** @default 'error' */\n severity?: TRuleSeverity;\n /** @default 5 */\n max?: number;\n } = {},\n ): Linter.RuleEntry {\n const { severity = 'error', max = MaxParamsOwnRule.DEFAULT_MAX } = opts;\n\n return [severity, max];\n }\n}\n"]}
1
+ {"version":3,"file":"max-params-own.rule.js","sourceRoot":"","sources":["../../../src/linters/house/max-params-own.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Linter, Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst CALL_TYPES = new Set([AstNodeTypes.CALL_EXPRESSION, AstNodeTypes.NEW_EXPRESSION]);\n\nconst isArrayContaining = (opts: { list: unknown; item: unknown }) =>\n Array.isArray(opts.list) && opts.list.includes(opts.item);\n\n/** `useX(...)`: a hook's callback is ours, so it counts. */\nconst isHookCall = (call: unknown) => {\n const callee = AstNode.readField({ node: call, key: 'callee' });\n const name = AstNode.readField({ node: callee, key: 'name' });\n\n return (\n AstNode.getType({ node: callee }) === AstNodeTypes.IDENTIFIER &&\n typeof name === 'string' &&\n HOOK_NAME.test(name)\n );\n};\n\n/** `node` is an argument of a call or `new` that is not a hook. */\nconst isLibraryArgument = (opts: { node: unknown; parent: unknown }) =>\n CALL_TYPES.has(AstNode.getType({ node: opts.parent }) ?? '') &&\n isArrayContaining({\n list: AstNode.readField({ node: opts.parent, key: 'arguments' }),\n item: opts.node,\n }) &&\n !isHookCall(opts.parent);\n\n/**\n * An object literal whose shape something else declares: a typed variable, `satisfies`, or an argument\n * of a non-hook call (a library option bag). A nested literal inherits it.\n */\nconst hasDeclaredShape = (object: unknown): boolean => {\n let current = object;\n\n while (current) {\n const parent = AstNode.readField({ node: current, key: 'parent' });\n const parentType = AstNode.getType({ node: parent });\n const isTypedVariable =\n parentType === AstNodeTypes.VARIABLE_DECLARATOR &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n\n if (\n isTypedVariable ||\n parentType === AstNodeTypes.SATISFIES_EXPRESSION ||\n isLibraryArgument({ node: current, parent })\n ) {\n return true;\n }\n\n const isNestedValue =\n parentType === AstNodeTypes.PROPERTY &&\n AstNode.readField({ node: parent, key: 'value' }) === current;\n current = isNestedValue ? AstNode.readField({ node: parent, key: 'parent' }) : undefined;\n }\n\n return false;\n};\n\n/**\n * `venizia/max-params-own`. A function we write takes at most `max` positional parameters;\n * beyond that it takes one options object. A signature that belongs to someone else is not counted: an\n * inline callback handed to a call (map, reduce, sort, a library handler) or to a JSX prop, a function a\n * declared type fixes (`const x: TFn = (...)`, a member of a typed or `satisfies` object), and a\n * constructor whose every parameter is injected (`@inject`). A hook's callback (`useCallback(...)`) is ours.\n */\nexport class MaxParamsOwnRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/max-params-own`;\n\n static readonly DEFAULT_MAX = 5;\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n schema: [{ type: 'integer', minimum: 0 }],\n messages: {\n tooMany:\n 'A function we write takes up to {{max}} positional parameters, not {{count}}: take one options object.',\n },\n },\n create: (context) => {\n const max =\n typeof context.options[0] === 'number' ? context.options[0] : MaxParamsOwnRule.DEFAULT_MAX;\n\n const isCallback = (node: Rule.Node) => {\n const parent = node.parent;\n const isJsxProp =\n AstNode.getType({ node: parent }) === AstNodeTypes.JSX_EXPRESSION_CONTAINER &&\n AstNode.getType({ node: AstNode.readField({ node: parent, key: 'parent' }) }) ===\n AstNodeTypes.JSX_ATTRIBUTE;\n\n return isJsxProp || isLibraryArgument({ node, parent });\n };\n\n const isInjectedConstructor = (opts: { node: Rule.Node; params: unknown[] }) => {\n const parent = opts.node.parent;\n\n const isDecorated = (param: unknown) => {\n const own = AstNode.readField({ node: param, key: 'decorators' });\n const property = AstNode.readField({\n node: AstNode.readField({ node: param, key: 'parameter' }),\n key: 'decorators',\n });\n\n return (\n (Array.isArray(own) && own.length > 0) ||\n (Array.isArray(property) && property.length > 0)\n );\n };\n\n return (\n AstNode.getType({ node: parent }) === AstNodeTypes.METHOD_DEFINITION &&\n AstNode.readField({ node: parent, key: 'kind' }) === 'constructor' &&\n opts.params.every(isDecorated)\n );\n };\n\n const isTypedByContext = (node: Rule.Node) => {\n const parent = node.parent;\n const parentType = AstNode.getType({ node: parent });\n const isTypedInit =\n parentType === AstNodeTypes.VARIABLE_DECLARATOR &&\n AstNode.readField({ node: parent, key: 'init' }) === node &&\n Boolean(\n AstNode.readField({\n node: AstNode.readField({ node: parent, key: 'id' }),\n key: 'typeAnnotation',\n }),\n );\n const grandParent = AstNode.readField({ node: parent, key: 'parent' });\n const isMember =\n parentType === AstNodeTypes.PROPERTY &&\n AstNode.readField({ node: parent, key: 'value' }) === node &&\n AstNode.getType({ node: grandParent }) === AstNodeTypes.OBJECT_EXPRESSION;\n\n return isTypedInit || (isMember && hasDeclaredShape(grandParent));\n };\n\n const check = (node: Rule.Node) => {\n const params = AstNode.readField({ node, key: 'params' });\n\n if (!Array.isArray(params) || params.length <= max) {\n return;\n }\n\n if (isCallback(node) || isInjectedConstructor({ node, params }) || isTypedByContext(node)) {\n return;\n }\n\n context.report({\n node,\n messageId: 'tooMany',\n data: { count: String(params.length), max: String(max) },\n });\n };\n\n return {\n [AstNodeTypes.FUNCTION_DECLARATION]: check,\n [AstNodeTypes.FUNCTION_EXPRESSION]: check,\n [AstNodeTypes.ARROW_FUNCTION_EXPRESSION]: check,\n };\n },\n };\n\n static build(\n opts: {\n /** @default 'error' */\n severity?: TRuleSeverity;\n /** @default 5 */\n max?: number;\n } = {},\n ): Linter.RuleEntry {\n const { severity = 'error', max = MaxParamsOwnRule.DEFAULT_MAX } = opts;\n\n return [severity, max];\n }\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { TRuleSeverity } from '../rules/common';
3
+ /**
4
+ * `venizia/no-await-new-chain`. A method is never called on a fresh instance inside an `await`:
5
+ * `await new Runner({ ... }).run(...)` and `const text = await new Response(body).text()` declare the instance first,
6
+ * then await on its own line (`const runner = new Runner({ ... }); await runner.run(...);`). A builder chain
7
+ * (`await new SignJWT(claims).setIssuer(iss).sign(key)`) declares the builder, then awaits its last call.
8
+ *
9
+ * `await new Promise(...)` calls no method and is allowed. `await new X().prop` is not a call and is allowed.
10
+ *
11
+ * The fix moves the instance, or the chain up to the last call, into a `const` in front of the statement. It is made
12
+ * only when nothing that does more than read a value runs before the `await` inside the statement; otherwise the
13
+ * finding is reported and left alone.
14
+ */
15
+ export declare class NoAwaitNewChainRule {
16
+ static readonly NAME = "venizia/no-await-new-chain";
17
+ /** The expression under any transparent wrapper. */
18
+ private static unwrap;
19
+ /**
20
+ * The receiver of the last call when the awaited value is a method call on a `new` (directly or through a chain of
21
+ * calls and member reads), else `undefined`.
22
+ */
23
+ private static receiverOf;
24
+ /**
25
+ * Whether the `await` is the whole statement (`await f();`) or the whole initializer of a declaration with one
26
+ * declarator (`const { a } = await f();`). Nothing runs before it there: a binding pattern and its defaults are
27
+ * evaluated after the initializer.
28
+ */
29
+ private static isFirstToRun;
30
+ /** `Response` becomes `response`, `ns.SignJWT` becomes `signJWT`; anything else is `instance`. */
31
+ private static nameOf;
32
+ static readonly RULE: Rule.RuleModule;
33
+ static build(opts?: {
34
+ severity?: TRuleSeverity;
35
+ }): TRuleSeverity;
36
+ }
37
+ //# sourceMappingURL=no-await-new-chain.rule.d.ts.map
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoAwaitNewChainRule = void 0;
4
+ const await_support_1 = require("./await-support");
5
+ const common_1 = require("./common");
6
+ /** Wrappers that carry no meaning of their own around the call or the instance: `(await new X().m()) as Y`, `new X()!.m()`, `new X()?.m()`. */
7
+ const TRANSPARENT_TYPES = new Set([
8
+ common_1.AstNodeTypes.CHAIN_EXPRESSION,
9
+ common_1.AstNodeTypes.AS_EXPRESSION,
10
+ common_1.AstNodeTypes.SATISFIES_EXPRESSION,
11
+ common_1.AstNodeTypes.NON_NULL_EXPRESSION,
12
+ ]);
13
+ /** The classes whose `new` is awaited on its own account: `await new Promise(...)` calls no method, and `.then` on it is `no-await-promise-chain`'s. */
14
+ const EXEMPT_CLASSES = new Set(['Promise']);
15
+ /**
16
+ * `venizia/no-await-new-chain`. A method is never called on a fresh instance inside an `await`:
17
+ * `await new Runner({ ... }).run(...)` and `const text = await new Response(body).text()` declare the instance first,
18
+ * then await on its own line (`const runner = new Runner({ ... }); await runner.run(...);`). A builder chain
19
+ * (`await new SignJWT(claims).setIssuer(iss).sign(key)`) declares the builder, then awaits its last call.
20
+ *
21
+ * `await new Promise(...)` calls no method and is allowed. `await new X().prop` is not a call and is allowed.
22
+ *
23
+ * The fix moves the instance, or the chain up to the last call, into a `const` in front of the statement. It is made
24
+ * only when nothing that does more than read a value runs before the `await` inside the statement; otherwise the
25
+ * finding is reported and left alone.
26
+ */
27
+ class NoAwaitNewChainRule {
28
+ static { this.NAME = `${common_1.HOUSE_PLUGIN_NAMESPACE}/no-await-new-chain`; }
29
+ /** The expression under any transparent wrapper. */
30
+ static unwrap(opts) {
31
+ let current = opts.node;
32
+ while (TRANSPARENT_TYPES.has(common_1.AstNode.getType({ node: current }) ?? '')) {
33
+ current = common_1.AstNode.readField({ node: current, key: 'expression' });
34
+ }
35
+ return current;
36
+ }
37
+ /**
38
+ * The receiver of the last call when the awaited value is a method call on a `new` (directly or through a chain of
39
+ * calls and member reads), else `undefined`.
40
+ */
41
+ static receiverOf(opts) {
42
+ const operand = NoAwaitNewChainRule.unwrap({
43
+ node: common_1.AstNode.readField({ node: opts.awaitNode, key: 'argument' }),
44
+ });
45
+ if (common_1.AstNode.getType({ node: operand }) !== common_1.AstNodeTypes.CALL_EXPRESSION) {
46
+ return undefined;
47
+ }
48
+ const callee = NoAwaitNewChainRule.unwrap({
49
+ node: common_1.AstNode.readField({ node: operand, key: 'callee' }),
50
+ });
51
+ if (common_1.AstNode.getType({ node: callee }) !== common_1.AstNodeTypes.MEMBER_EXPRESSION) {
52
+ return undefined;
53
+ }
54
+ const receiver = common_1.AstNode.readField({ node: callee, key: 'object' });
55
+ let current = NoAwaitNewChainRule.unwrap({ node: receiver });
56
+ // Down the chain: `new X().a().b` is a call of a member of a call of a member of the `new`.
57
+ for (;;) {
58
+ const type = common_1.AstNode.getType({ node: current });
59
+ if (type === common_1.AstNodeTypes.CALL_EXPRESSION) {
60
+ current = NoAwaitNewChainRule.unwrap({
61
+ node: common_1.AstNode.readField({ node: current, key: 'callee' }),
62
+ });
63
+ }
64
+ else if (type === common_1.AstNodeTypes.MEMBER_EXPRESSION) {
65
+ current = NoAwaitNewChainRule.unwrap({
66
+ node: common_1.AstNode.readField({ node: current, key: 'object' }),
67
+ });
68
+ }
69
+ else {
70
+ break;
71
+ }
72
+ }
73
+ if (common_1.AstNode.getType({ node: current }) !== common_1.AstNodeTypes.NEW_EXPRESSION) {
74
+ return undefined;
75
+ }
76
+ const constructed = common_1.AstNode.readField({ node: current, key: 'callee' });
77
+ if (common_1.AstNode.getType({ node: constructed }) === common_1.AstNodeTypes.IDENTIFIER &&
78
+ EXEMPT_CLASSES.has(String(common_1.AstNode.readField({ node: constructed, key: 'name' })))) {
79
+ return undefined;
80
+ }
81
+ return await_support_1.AwaitSupport.isNode(receiver) ? receiver : undefined;
82
+ }
83
+ /**
84
+ * Whether the `await` is the whole statement (`await f();`) or the whole initializer of a declaration with one
85
+ * declarator (`const { a } = await f();`). Nothing runs before it there: a binding pattern and its defaults are
86
+ * evaluated after the initializer.
87
+ */
88
+ static isFirstToRun(opts) {
89
+ const { awaitNode, statement } = opts;
90
+ const type = common_1.AstNode.getType({ node: statement });
91
+ if (type === common_1.AstNodeTypes.EXPRESSION_STATEMENT) {
92
+ return common_1.AstNode.readField({ node: statement, key: 'expression' }) === awaitNode;
93
+ }
94
+ if (type !== common_1.AstNodeTypes.VARIABLE_DECLARATION) {
95
+ return false;
96
+ }
97
+ const declarations = common_1.AstNode.readField({ node: statement, key: 'declarations' });
98
+ return (Array.isArray(declarations) &&
99
+ declarations.length === 1 &&
100
+ common_1.AstNode.readField({ node: declarations[0], key: 'init' }) === awaitNode);
101
+ }
102
+ /** `Response` becomes `response`, `ns.SignJWT` becomes `signJWT`; anything else is `instance`. */
103
+ static nameOf(opts) {
104
+ let current = NoAwaitNewChainRule.unwrap({ node: opts.receiver });
105
+ while (common_1.AstNode.getType({ node: current }) === common_1.AstNodeTypes.CALL_EXPRESSION ||
106
+ common_1.AstNode.getType({ node: current }) === common_1.AstNodeTypes.MEMBER_EXPRESSION) {
107
+ current = NoAwaitNewChainRule.unwrap({
108
+ node: common_1.AstNode.readField({
109
+ node: current,
110
+ key: common_1.AstNode.getType({ node: current }) === common_1.AstNodeTypes.MEMBER_EXPRESSION
111
+ ? 'object'
112
+ : 'callee',
113
+ }),
114
+ });
115
+ }
116
+ const constructed = common_1.AstNode.readField({ node: current, key: 'callee' });
117
+ const word = common_1.AstNode.getType({ node: constructed }) === common_1.AstNodeTypes.IDENTIFIER
118
+ ? common_1.AstNode.readField({ node: constructed, key: 'name' })
119
+ : common_1.AstNode.getType({ node: constructed }) === common_1.AstNodeTypes.MEMBER_EXPRESSION
120
+ ? common_1.AstNode.readField({
121
+ node: common_1.AstNode.readField({ node: constructed, key: 'property' }),
122
+ key: 'name',
123
+ })
124
+ : undefined;
125
+ return typeof word === 'string' && /^[A-Za-z_$][\w$]*$/.test(word)
126
+ ? `${word[0]?.toLowerCase()}${word.slice(1)}`
127
+ : 'instance';
128
+ }
129
+ static { this.RULE = {
130
+ meta: {
131
+ type: 'suggestion',
132
+ fixable: 'code',
133
+ schema: [],
134
+ messages: {
135
+ chain: 'Do not call a method on a new instance inside an `await`: declare the instance first (`const runner = new Runner(options);`), then `await runner.run();` on its own line.',
136
+ },
137
+ },
138
+ create: (context) => {
139
+ const { sourceCode } = context;
140
+ return {
141
+ [common_1.AstNodeTypes.AWAIT_EXPRESSION]: (node) => {
142
+ const receiver = NoAwaitNewChainRule.receiverOf({ awaitNode: node });
143
+ if (receiver === undefined) {
144
+ return;
145
+ }
146
+ const statement = await_support_1.AwaitSupport.hoistTarget({ awaitNode: node });
147
+ const range = await_support_1.AwaitSupport.rangeOf({ node: receiver });
148
+ const canFix = statement !== undefined &&
149
+ range !== undefined &&
150
+ (NoAwaitNewChainRule.isFirstToRun({ awaitNode: node, statement }) ||
151
+ !await_support_1.AwaitSupport.hasEffectBefore({ statement, awaitNode: node, sourceCode }));
152
+ context.report({
153
+ node,
154
+ messageId: 'chain',
155
+ fix: canFix && range !== undefined
156
+ ? (fixer) => {
157
+ const name = await_support_1.AwaitSupport.freshName({
158
+ node,
159
+ base: NoAwaitNewChainRule.nameOf({ receiver }),
160
+ sourceCode,
161
+ });
162
+ const indent = await_support_1.AwaitSupport.indentOf({ node: statement, sourceCode });
163
+ return [
164
+ fixer.insertTextBefore(statement, `const ${name} = ${sourceCode.getText(receiver)};\n${indent}`),
165
+ fixer.replaceTextRange(range, name),
166
+ ];
167
+ }
168
+ : null,
169
+ });
170
+ },
171
+ };
172
+ },
173
+ }; }
174
+ static build(opts = {}) {
175
+ return opts.severity ?? 'error';
176
+ }
177
+ }
178
+ exports.NoAwaitNewChainRule = NoAwaitNewChainRule;
179
+ //# sourceMappingURL=no-await-new-chain.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-await-new-chain.rule.js","sourceRoot":"","sources":["../../../src/linters/house/no-await-new-chain.rule.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Rule } from 'eslint';\nimport type { TRuleSeverity } from '../rules/common';\nimport { AwaitSupport } from './await-support';\nimport { AstNode, AstNodeTypes, HOUSE_PLUGIN_NAMESPACE } from './common';\n\n/** Wrappers that carry no meaning of their own around the call or the instance: `(await new X().m()) as Y`, `new X()!.m()`, `new X()?.m()`. */\nconst TRANSPARENT_TYPES = new Set([\n AstNodeTypes.CHAIN_EXPRESSION,\n AstNodeTypes.AS_EXPRESSION,\n AstNodeTypes.SATISFIES_EXPRESSION,\n AstNodeTypes.NON_NULL_EXPRESSION,\n]);\n\n/** The classes whose `new` is awaited on its own account: `await new Promise(...)` calls no method, and `.then` on it is `no-await-promise-chain`'s. */\nconst EXEMPT_CLASSES = new Set(['Promise']);\n\n/**\n * `venizia/no-await-new-chain`. A method is never called on a fresh instance inside an `await`:\n * `await new Runner({ ... }).run(...)` and `const text = await new Response(body).text()` declare the instance first,\n * then await on its own line (`const runner = new Runner({ ... }); await runner.run(...);`). A builder chain\n * (`await new SignJWT(claims).setIssuer(iss).sign(key)`) declares the builder, then awaits its last call.\n *\n * `await new Promise(...)` calls no method and is allowed. `await new X().prop` is not a call and is allowed.\n *\n * The fix moves the instance, or the chain up to the last call, into a `const` in front of the statement. It is made\n * only when nothing that does more than read a value runs before the `await` inside the statement; otherwise the\n * finding is reported and left alone.\n */\nexport class NoAwaitNewChainRule {\n static readonly NAME = `${HOUSE_PLUGIN_NAMESPACE}/no-await-new-chain`;\n\n /** The expression under any transparent wrapper. */\n private static unwrap(opts: { node: unknown }): unknown {\n let current = opts.node;\n\n while (TRANSPARENT_TYPES.has(AstNode.getType({ node: current }) ?? '')) {\n current = AstNode.readField({ node: current, key: 'expression' });\n }\n\n return current;\n }\n\n /**\n * The receiver of the last call when the awaited value is a method call on a `new` (directly or through a chain of\n * calls and member reads), else `undefined`.\n */\n private static receiverOf(opts: { awaitNode: unknown }): Rule.Node | undefined {\n const operand = NoAwaitNewChainRule.unwrap({\n node: AstNode.readField({ node: opts.awaitNode, key: 'argument' }),\n });\n\n if (AstNode.getType({ node: operand }) !== AstNodeTypes.CALL_EXPRESSION) {\n return undefined;\n }\n\n const callee = NoAwaitNewChainRule.unwrap({\n node: AstNode.readField({ node: operand, key: 'callee' }),\n });\n\n if (AstNode.getType({ node: callee }) !== AstNodeTypes.MEMBER_EXPRESSION) {\n return undefined;\n }\n\n const receiver = AstNode.readField({ node: callee, key: 'object' });\n let current = NoAwaitNewChainRule.unwrap({ node: receiver });\n\n // Down the chain: `new X().a().b` is a call of a member of a call of a member of the `new`.\n for (;;) {\n const type = AstNode.getType({ node: current });\n\n if (type === AstNodeTypes.CALL_EXPRESSION) {\n current = NoAwaitNewChainRule.unwrap({\n node: AstNode.readField({ node: current, key: 'callee' }),\n });\n } else if (type === AstNodeTypes.MEMBER_EXPRESSION) {\n current = NoAwaitNewChainRule.unwrap({\n node: AstNode.readField({ node: current, key: 'object' }),\n });\n } else {\n break;\n }\n }\n\n if (AstNode.getType({ node: current }) !== AstNodeTypes.NEW_EXPRESSION) {\n return undefined;\n }\n\n const constructed = AstNode.readField({ node: current, key: 'callee' });\n\n if (\n AstNode.getType({ node: constructed }) === AstNodeTypes.IDENTIFIER &&\n EXEMPT_CLASSES.has(String(AstNode.readField({ node: constructed, key: 'name' })))\n ) {\n return undefined;\n }\n\n return AwaitSupport.isNode(receiver) ? receiver : undefined;\n }\n\n /**\n * Whether the `await` is the whole statement (`await f();`) or the whole initializer of a declaration with one\n * declarator (`const { a } = await f();`). Nothing runs before it there: a binding pattern and its defaults are\n * evaluated after the initializer.\n */\n private static isFirstToRun(opts: { awaitNode: unknown; statement: unknown }): boolean {\n const { awaitNode, statement } = opts;\n const type = AstNode.getType({ node: statement });\n\n if (type === AstNodeTypes.EXPRESSION_STATEMENT) {\n return AstNode.readField({ node: statement, key: 'expression' }) === awaitNode;\n }\n\n if (type !== AstNodeTypes.VARIABLE_DECLARATION) {\n return false;\n }\n\n const declarations = AstNode.readField({ node: statement, key: 'declarations' });\n\n return (\n Array.isArray(declarations) &&\n declarations.length === 1 &&\n AstNode.readField({ node: declarations[0], key: 'init' }) === awaitNode\n );\n }\n\n /** `Response` becomes `response`, `ns.SignJWT` becomes `signJWT`; anything else is `instance`. */\n private static nameOf(opts: { receiver: unknown }): string {\n let current = NoAwaitNewChainRule.unwrap({ node: opts.receiver });\n\n while (\n AstNode.getType({ node: current }) === AstNodeTypes.CALL_EXPRESSION ||\n AstNode.getType({ node: current }) === AstNodeTypes.MEMBER_EXPRESSION\n ) {\n current = NoAwaitNewChainRule.unwrap({\n node: AstNode.readField({\n node: current,\n key:\n AstNode.getType({ node: current }) === AstNodeTypes.MEMBER_EXPRESSION\n ? 'object'\n : 'callee',\n }),\n });\n }\n\n const constructed = AstNode.readField({ node: current, key: 'callee' });\n const word =\n AstNode.getType({ node: constructed }) === AstNodeTypes.IDENTIFIER\n ? AstNode.readField({ node: constructed, key: 'name' })\n : AstNode.getType({ node: constructed }) === AstNodeTypes.MEMBER_EXPRESSION\n ? AstNode.readField({\n node: AstNode.readField({ node: constructed, key: 'property' }),\n key: 'name',\n })\n : undefined;\n\n return typeof word === 'string' && /^[A-Za-z_$][\\w$]*$/.test(word)\n ? `${word[0]?.toLowerCase()}${word.slice(1)}`\n : 'instance';\n }\n\n static readonly RULE: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n schema: [],\n messages: {\n chain:\n 'Do not call a method on a new instance inside an `await`: declare the instance first (`const runner = new Runner(options);`), then `await runner.run();` on its own line.',\n },\n },\n create: (context) => {\n const { sourceCode } = context;\n\n return {\n [AstNodeTypes.AWAIT_EXPRESSION]: (node: Rule.Node) => {\n const receiver = NoAwaitNewChainRule.receiverOf({ awaitNode: node });\n\n if (receiver === undefined) {\n return;\n }\n\n const statement = AwaitSupport.hoistTarget({ awaitNode: node });\n const range = AwaitSupport.rangeOf({ node: receiver });\n const canFix =\n statement !== undefined &&\n range !== undefined &&\n (NoAwaitNewChainRule.isFirstToRun({ awaitNode: node, statement }) ||\n !AwaitSupport.hasEffectBefore({ statement, awaitNode: node, sourceCode }));\n\n context.report({\n node,\n messageId: 'chain',\n fix:\n canFix && range !== undefined\n ? (fixer) => {\n const name = AwaitSupport.freshName({\n node,\n base: NoAwaitNewChainRule.nameOf({ receiver }),\n sourceCode,\n });\n const indent = AwaitSupport.indentOf({ node: statement, sourceCode });\n\n return [\n fixer.insertTextBefore(\n statement,\n `const ${name} = ${sourceCode.getText(receiver)};\\n${indent}`,\n ),\n fixer.replaceTextRange(range, name),\n ];\n }\n : null,\n });\n },\n };\n },\n };\n\n static build(opts: { severity?: TRuleSeverity } = {}): TRuleSeverity {\n return opts.severity ?? 'error';\n }\n}\n"]}
@@ -12,40 +12,41 @@ const collectValue = (opts) => {
12
12
  const type = common_1.AstNode.getType({ node }) ?? '';
13
13
  const value = (child) => collectValue({ node: child, parameter, identifiers });
14
14
  switch (type) {
15
- case 'Literal': {
15
+ case common_1.AstNodeTypes.LITERAL: {
16
16
  return true;
17
17
  }
18
- case 'Identifier': {
18
+ case common_1.AstNodeTypes.IDENTIFIER: {
19
19
  identifiers.push(node);
20
20
  return true;
21
21
  }
22
- case 'TemplateLiteral': {
22
+ case common_1.AstNodeTypes.TEMPLATE_LITERAL: {
23
23
  return promise_chain_support_1.PromiseChainSupport.isConstant({ node });
24
24
  }
25
- case 'UnaryExpression': {
25
+ case common_1.AstNodeTypes.UNARY_EXPRESSION: {
26
26
  return promise_chain_support_1.PromiseChainSupport.isConstant({ node });
27
27
  }
28
- case 'ChainExpression': {
28
+ case common_1.AstNodeTypes.CHAIN_EXPRESSION: {
29
29
  return value(common_1.AstNode.readField({ node, key: 'expression' }));
30
30
  }
31
- case 'MemberExpression': {
31
+ case common_1.AstNodeTypes.MEMBER_EXPRESSION: {
32
32
  // Only a read of the error itself: `error.message`, `error?.response.status`.
33
33
  const object = common_1.AstNode.readField({ node, key: 'object' });
34
34
  const isRead = common_1.AstNode.readField({ node, key: 'computed' }) !== true ||
35
- common_1.AstNode.getType({ node: common_1.AstNode.readField({ node, key: 'property' }) }) === 'Literal';
36
- const isRooted = common_1.AstNode.getType({ node: object }) === 'MemberExpression' ||
37
- (common_1.AstNode.getType({ node: object }) === 'Identifier' &&
35
+ common_1.AstNode.getType({ node: common_1.AstNode.readField({ node, key: 'property' }) }) ===
36
+ common_1.AstNodeTypes.LITERAL;
37
+ const isRooted = common_1.AstNode.getType({ node: object }) === common_1.AstNodeTypes.MEMBER_EXPRESSION ||
38
+ (common_1.AstNode.getType({ node: object }) === common_1.AstNodeTypes.IDENTIFIER &&
38
39
  common_1.AstNode.readField({ node: object, key: 'name' }) === parameter);
39
40
  return isRead && isRooted && parameter !== undefined && value(object);
40
41
  }
41
- case 'ArrayExpression': {
42
+ case common_1.AstNodeTypes.ARRAY_EXPRESSION: {
42
43
  const elements = common_1.AstNode.readField({ node, key: 'elements' });
43
44
  return (Array.isArray(elements) && elements.every((element) => element === null || value(element)));
44
45
  }
45
- case 'ObjectExpression': {
46
+ case common_1.AstNodeTypes.OBJECT_EXPRESSION: {
46
47
  const properties = common_1.AstNode.readField({ node, key: 'properties' });
47
48
  return (Array.isArray(properties) &&
48
- properties.every((property) => common_1.AstNode.getType({ node: property }) === 'Property' &&
49
+ properties.every((property) => common_1.AstNode.getType({ node: property }) === common_1.AstNodeTypes.PROPERTY &&
49
50
  common_1.AstNode.readField({ node: property, key: 'computed' }) !== true &&
50
51
  common_1.AstNode.readField({ node: property, key: 'method' }) !== true &&
51
52
  common_1.AstNode.readField({ node: property, key: 'kind' }) === 'init' &&
@@ -78,9 +79,9 @@ const planFix = (opts) => {
78
79
  const call = common_1.AstNode.readField({ node: awaitNode, key: 'argument' });
79
80
  const callee = common_1.AstNode.readField({ node: call, key: 'callee' });
80
81
  const args = common_1.AstNode.readField({ node: call, key: 'arguments' });
81
- if (common_1.AstNode.getType({ node: call }) !== 'CallExpression' ||
82
+ if (common_1.AstNode.getType({ node: call }) !== common_1.AstNodeTypes.CALL_EXPRESSION ||
82
83
  common_1.AstNode.readField({ node: call, key: 'optional' }) === true ||
83
- common_1.AstNode.getType({ node: callee }) !== 'MemberExpression' ||
84
+ common_1.AstNode.getType({ node: callee }) !== common_1.AstNodeTypes.MEMBER_EXPRESSION ||
84
85
  common_1.AstNode.readField({ node: callee, key: 'computed' }) === true ||
85
86
  common_1.AstNode.readField({ node: callee, key: 'optional' }) === true ||
86
87
  promise_chain_support_1.PromiseChainSupport.memberName({ member: callee }) !== 'catch' ||
@@ -92,7 +93,7 @@ const planFix = (opts) => {
92
93
  const params = common_1.AstNode.readField({ node: handler, key: 'params' });
93
94
  const body = common_1.AstNode.readField({ node: handler, key: 'body' });
94
95
  const parameter = Array.isArray(params) ? params[0] : undefined;
95
- if (common_1.AstNode.getType({ node: handler }) !== 'ArrowFunctionExpression' ||
96
+ if (common_1.AstNode.getType({ node: handler }) !== common_1.AstNodeTypes.ARROW_FUNCTION_EXPRESSION ||
96
97
  common_1.AstNode.readField({ node: handler, key: 'async' }) === true ||
97
98
  common_1.AstNode.getType({ node: body }) === common_1.AstNodeTypes.BLOCK_STATEMENT ||
98
99
  common_1.AstNode.readField({ node: handler, key: 'returnType' }) ||
@@ -100,7 +101,7 @@ const planFix = (opts) => {
100
101
  !Array.isArray(params) ||
101
102
  params.length > 1 ||
102
103
  (parameter !== undefined &&
103
- (common_1.AstNode.getType({ node: parameter }) !== 'Identifier' ||
104
+ (common_1.AstNode.getType({ node: parameter }) !== common_1.AstNodeTypes.IDENTIFIER ||
104
105
  common_1.AstNode.readField({ node: parameter, key: 'typeAnnotation' }) ||
105
106
  common_1.AstNode.readField({ node: parameter, key: 'optional' }) === true))) {
106
107
  return undefined;
@@ -118,10 +119,10 @@ const planFix = (opts) => {
118
119
  const id = common_1.AstNode.readField({ node: declarator, key: 'id' });
119
120
  const declarations = common_1.AstNode.readField({ node: declaration, key: 'declarations' });
120
121
  const kind = String(common_1.AstNode.readField({ node: declaration, key: 'kind' }));
121
- if (common_1.AstNode.getType({ node: declarator }) !== 'VariableDeclarator' ||
122
+ if (common_1.AstNode.getType({ node: declarator }) !== common_1.AstNodeTypes.VARIABLE_DECLARATOR ||
122
123
  common_1.AstNode.readField({ node: declarator, key: 'init' }) !== awaitNode ||
123
124
  common_1.AstNode.readField({ node: declarator, key: 'definite' }) === true ||
124
- common_1.AstNode.getType({ node: id }) !== 'Identifier' ||
125
+ common_1.AstNode.getType({ node: id }) !== common_1.AstNodeTypes.IDENTIFIER ||
125
126
  !await_support_1.AwaitSupport.isNode(declarator) ||
126
127
  !await_support_1.AwaitSupport.isNode(declaration) ||
127
128
  !Array.isArray(declarations) ||
@@ -149,8 +150,8 @@ const planFix = (opts) => {
149
150
  if (reference.isWrite() ||
150
151
  (annotation === '' &&
151
152
  (reference.from.variableScope !== variable.scope.variableScope ||
152
- parentType === 'ExportSpecifier' ||
153
- parentType === 'TSTypeQuery'))) {
153
+ parentType === common_1.AstNodeTypes.EXPORT_SPECIFIER ||
154
+ parentType === common_1.AstNodeTypes.TYPE_QUERY))) {
154
155
  return undefined;
155
156
  }
156
157
  }
@@ -164,7 +165,7 @@ const planFix = (opts) => {
164
165
  // `x = []` on a `let x;` with no annotation makes an evolving `any[]`, looser than the `never[]` it was.
165
166
  const elements = common_1.AstNode.readField({ node: body, key: 'elements' });
166
167
  if (annotation === '' &&
167
- common_1.AstNode.getType({ node: body }) === 'ArrayExpression' &&
168
+ common_1.AstNode.getType({ node: body }) === common_1.AstNodeTypes.ARRAY_EXPRESSION &&
168
169
  Array.isArray(elements) &&
169
170
  elements.length === 0) {
170
171
  return undefined;
@@ -201,7 +202,7 @@ const planFix = (opts) => {
201
202
  .filter(await_support_1.AwaitSupport.isNode)
202
203
  .map((identifier) => {
203
204
  const parent = await_support_1.AwaitSupport.parentOf({ node: identifier });
204
- const isShorthand = common_1.AstNode.getType({ node: parent }) === 'Property' &&
205
+ const isShorthand = common_1.AstNode.getType({ node: parent }) === common_1.AstNodeTypes.PROPERTY &&
205
206
  common_1.AstNode.readField({ node: parent, key: 'shorthand' }) === true;
206
207
  return {
207
208
  range: identifier.range ?? [0, 0],