@blumintinc/eslint-plugin-blumint 1.20.134 → 1.20.136

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.
@@ -42,6 +42,33 @@ const getEnclosingClass = (node) => {
42
42
  * cannot be resolved through scope analysis, the fix is withheld whenever the
43
43
  * name occurs anywhere in the class other than at its declaration.
44
44
  */
45
+ /**
46
+ * The member name a `this.<x>` access reads, whatever its spelling.
47
+ *
48
+ * Keying the check on the dot spelling alone left `this['settings']` invisible,
49
+ * so the rename shipped and stranded it — the class no longer had the member the
50
+ * getter reads (#1882, the sibling of #1881). A computed access with a static
51
+ * string is the SAME member as the dot form, and the fixer cannot rewrite it
52
+ * either, so it has to count. `null` marks a genuinely dynamic key, which names
53
+ * no member statically and therefore strands nothing.
54
+ */
55
+ const staticMemberName = (node) => {
56
+ if (!node.computed) {
57
+ return node.property.type === utils_1.AST_NODE_TYPES.Identifier
58
+ ? node.property.name
59
+ : null;
60
+ }
61
+ if (node.property.type === utils_1.AST_NODE_TYPES.Literal &&
62
+ typeof node.property.value === 'string') {
63
+ return node.property.value;
64
+ }
65
+ if (node.property.type === utils_1.AST_NODE_TYPES.TemplateLiteral &&
66
+ node.property.expressions.length === 0 &&
67
+ node.property.quasis.length === 1) {
68
+ return node.property.quasis[0].value.cooked;
69
+ }
70
+ return null;
71
+ };
45
72
  const parameterPropertyRenameIsUnsafe = (classNode, name, declarationId) => {
46
73
  let unsafe = false;
47
74
  const visit = (node) => {
@@ -50,8 +77,7 @@ const parameterPropertyRenameIsUnsafe = (classNode, name, declarationId) => {
50
77
  }
51
78
  if (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
52
79
  node.object.type === utils_1.AST_NODE_TYPES.ThisExpression &&
53
- node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
54
- node.property.name === name) {
80
+ staticMemberName(node) === name) {
55
81
  unsafe = true;
56
82
  return;
57
83
  }
@@ -414,17 +414,20 @@ exports.noInlineComponentProp = (0, createRule_1.createRule)({
414
414
  if (!definition)
415
415
  return;
416
416
  const defNode = definition.node;
417
- if (!defNode ||
418
- defNode.type !== utils_1.AST_NODE_TYPES.VariableDeclarator ||
419
- !defNode.init ||
420
- defNode.init.type !== utils_1.AST_NODE_TYPES.ObjectExpression) {
417
+ if (!defNode || defNode.type !== utils_1.AST_NODE_TYPES.VariableDeclarator) {
418
+ return;
419
+ }
420
+ // `global-const-style` autofixes a module-scope object literal to
421
+ // `as const`, so reading `init` raw lets one fixer silence this rule.
422
+ const holder = unwrapExpression(defNode.init);
423
+ if (!holder || holder.type !== utils_1.AST_NODE_TYPES.ObjectExpression) {
421
424
  return;
422
425
  }
423
426
  if (resolvedOptions.allowModuleScopeFactories &&
424
427
  isStableForConsumer(defNode, consumerFunction)) {
425
428
  return;
426
429
  }
427
- const fnNode = findObjectPropertyFunction(defNode.init, member.property.name);
430
+ const fnNode = findObjectPropertyFunction(holder, member.property.name);
428
431
  if (fnNode &&
429
432
  isComponentLikeFunction(fnNode, context, member.property.name)) {
430
433
  report(member, propName, member.property.name);
@@ -68,18 +68,33 @@ exports.noObjectValuesOnStrings = (0, createRule_1.createRule)({
68
68
  node.callee.property.name === 'values' &&
69
69
  node.arguments.length > 0);
70
70
  }
71
+ /**
72
+ * `a?.b()` parses as a ChainExpression wrapping the call. The wrapper is
73
+ * ESTree-only, so it has no TypeScript node: leaving it in place defeats
74
+ * both the syntactic tests below and `getTypeAtLocation`, and a nullable
75
+ * receiver is exactly where `?.` gets written.
76
+ */
77
+ function unwrapChain(node) {
78
+ let current = node;
79
+ while (current.type === utils_1.AST_NODE_TYPES.ChainExpression) {
80
+ current = current.expression;
81
+ }
82
+ return current;
83
+ }
71
84
  /**
72
85
  * Checks if a node is a string literal or template literal
73
86
  */
74
87
  function isStringLiteral(node) {
75
- return ((node.type === utils_1.AST_NODE_TYPES.Literal &&
76
- typeof node.value === 'string') ||
77
- node.type === utils_1.AST_NODE_TYPES.TemplateLiteral);
88
+ const inner = unwrapChain(node);
89
+ return ((inner.type === utils_1.AST_NODE_TYPES.Literal &&
90
+ typeof inner.value === 'string') ||
91
+ inner.type === utils_1.AST_NODE_TYPES.TemplateLiteral);
78
92
  }
79
93
  /**
80
94
  * Checks if a node is likely to produce a string value based on AST patterns
81
95
  */
82
- function isLikelyStringExpression(node) {
96
+ function isLikelyStringExpression(maybeChained) {
97
+ const node = unwrapChain(maybeChained);
83
98
  // Check for string concatenation
84
99
  if (node.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
85
100
  node.operator === '+' &&
@@ -190,8 +205,10 @@ exports.noObjectValuesOnStrings = (0, createRule_1.createRule)({
190
205
  CallExpression(node) {
191
206
  // Check if the call is Object.values()
192
207
  if (isObjectValuesCall(node)) {
193
- const argument = node.arguments[0];
194
- const argumentText = sourceCode.getText(argument);
208
+ // The message quotes what the author wrote, so text comes from the
209
+ // original node while every test below reads through the chain.
210
+ const argumentText = sourceCode.getText(node.arguments[0]);
211
+ const argument = unwrapChain(node.arguments[0]);
195
212
  // Quick check for string literals and template literals
196
213
  if (isStringLiteral(argument)) {
197
214
  context.report({
@@ -421,8 +421,16 @@ exports.noPassthroughGetters = (0, createRule_1.createRule)({
421
421
  if (node.type === 'ConditionalExpression') {
422
422
  return true;
423
423
  }
424
- // Check for optional chaining like this.settings?.property
425
- if (node.type === 'MemberExpression' && node.optional) {
424
+ // Check for optional chaining like this.settings?.property. `a?.b` parses
425
+ // as a ChainExpression wrapping the member access, so the wrapper has to
426
+ // be stripped here or this arm never fires — the shape stays silent only
427
+ // because the member walker cannot follow it, which would reverse the
428
+ // moment that walker learns to.
429
+ let unchained = node;
430
+ while (unchained.type === 'ChainExpression') {
431
+ unchained = unchained.expression;
432
+ }
433
+ if (unchained.type === 'MemberExpression' && unchained.optional) {
426
434
  return true;
427
435
  }
428
436
  // The nullish coalescing check is already covered by the LogicalExpression check above