@grafana/react-detect 0.6.1 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # v0.6.2 (Wed Apr 01 2026)
2
+
3
+ #### 🐛 Bug Fix
4
+
5
+ - fix: reduce false positives in findStringRefs [#2551](https://github.com/grafana/plugin-tools/pull/2551) ([@jackw](https://github.com/jackw))
6
+
7
+ #### Authors: 1
8
+
9
+ - Jack Westbrook ([@jackw](https://github.com/jackw))
10
+
11
+ ---
12
+
1
13
  # v0.6.1 (Tue Feb 17 2026)
2
14
 
3
15
  #### 🐛 Bug Fix
@@ -74,8 +74,13 @@ function findJsxRuntimeImports(ast, code) {
74
74
  }
75
75
  function findStringRefs(ast, code) {
76
76
  const matches = [];
77
+ const imports = trackImportsFromPackage(ast, "react");
78
+ const hasReactImport = imports.defaultImports.size > 0 || imports.namedImports.size > 0;
79
+ if (!hasReactImport) {
80
+ return matches;
81
+ }
77
82
  walk(ast, (node) => {
78
- if (node && node.type === "MemberExpression" && node.object.type === "ThisExpression" && node.property.type === "Identifier" && node.property.name === "refs") {
83
+ if (node && node.type === "MemberExpression" && node.object?.type === "MemberExpression" && node.object.object?.type === "ThisExpression" && node.object.property?.type === "Identifier" && node.object.property.name === "refs") {
79
84
  matches.push(createPatternMatch(node, "stringRefs", code));
80
85
  }
81
86
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@grafana/react-detect",
3
3
  "description": "Run various checks to detect if a Grafana plugin is compatible with React.",
4
- "version": "0.6.1",
4
+ "version": "0.6.2",
5
5
  "repository": {
6
6
  "directory": "packages/react-detect",
7
7
  "url": "https://github.com/grafana/plugin-tools"
@@ -41,5 +41,5 @@
41
41
  "engines": {
42
42
  "node": ">=20"
43
43
  },
44
- "gitHead": "9a39d4b614fef1f11a7dff646dd417603e3e2ad7"
44
+ "gitHead": "def49813c11febf54299c9541b0eeb243fb4e495"
45
45
  }
@@ -92,6 +92,7 @@ describe('matcher', () => {
92
92
  describe('findStringRefs', () => {
93
93
  it('should find stringRefs assignments in source code', () => {
94
94
  const code = `
95
+ import React from 'react';
95
96
  class MyComponent extends React.Component {
96
97
  componentDidMount() {
97
98
  this.refs.input.focus();
@@ -111,6 +112,7 @@ describe('matcher', () => {
111
112
 
112
113
  it('should find bracket notation refs access', () => {
113
114
  const code = `
115
+ import React from 'react';
114
116
  class MyComponent extends React.Component {
115
117
  componentDidMount() {
116
118
  this.refs['input'].focus();
@@ -127,6 +129,35 @@ describe('matcher', () => {
127
129
  expect(matches[0].pattern).toBe('stringRefs');
128
130
  expect(matches[0].matched).toContain('this.refs');
129
131
  });
132
+
133
+ it('should not match this.refs in files without a React import', () => {
134
+ const code = `
135
+ class ComponentRegistry {
136
+ getRef() {
137
+ return this.refs.primary;
138
+ }
139
+ }
140
+ `;
141
+ const ast = parseFile(code, 'test.js');
142
+ const matches = findStringRefs(ast, code);
143
+
144
+ expect(matches).toHaveLength(0);
145
+ });
146
+
147
+ it('should not match bare this.refs access without property access', () => {
148
+ const code = `
149
+ import React from 'react';
150
+ class MyComponent extends React.Component {
151
+ getAllRefs() {
152
+ return this.refs;
153
+ }
154
+ }
155
+ `;
156
+ const ast = parseFile(code, 'test.js');
157
+ const matches = findStringRefs(ast, code);
158
+
159
+ expect(matches).toHaveLength(0);
160
+ });
130
161
  });
131
162
 
132
163
  describe('findFindDOMNode', () => {
@@ -102,14 +102,21 @@ export function findJsxRuntimeImports(ast: TSESTree.Program, code: string): Patt
102
102
 
103
103
  export function findStringRefs(ast: TSESTree.Program, code: string): PatternMatch[] {
104
104
  const matches: PatternMatch[] = [];
105
+ const imports = trackImportsFromPackage(ast, 'react');
106
+
107
+ const hasReactImport = imports.defaultImports.size > 0 || imports.namedImports.size > 0;
108
+ if (!hasReactImport) {
109
+ return matches;
110
+ }
105
111
 
106
112
  walk(ast, (node) => {
107
113
  if (
108
114
  node &&
109
115
  node.type === 'MemberExpression' &&
110
- node.object.type === 'ThisExpression' &&
111
- node.property.type === 'Identifier' &&
112
- node.property.name === 'refs'
116
+ node.object?.type === 'MemberExpression' &&
117
+ node.object.object?.type === 'ThisExpression' &&
118
+ node.object.property?.type === 'Identifier' &&
119
+ node.object.property.name === 'refs'
113
120
  ) {
114
121
  matches.push(createPatternMatch(node, 'stringRefs', code));
115
122
  }