;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // value, MyComponent
+ expect(scope.references).to.have.length(2); // value def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // value def, value use
+ expect(scope.through).to.have.length(0); // attr should not be a reference
+
+ const valueRef = scope.references[0];
+
+ expect(valueRef.identifier.name).to.equal("value");
+ expect(valueRef.isWrite()).to.be.true;
+ expect(valueRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle JSX attributes as references with JSX disabled", () => {
+ const ast = espree(`
+ const value = "test";
+ const MyComponent = () =>
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: false });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // value, MyComponent
+ expect(scope.references).to.have.length(2); // value def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // value def, value use
+ expect(scope.through).to.have.length(0); // attr should not be a reference
+
+ const valueRef = scope.references[0];
+
+ expect(valueRef.identifier.name).to.equal("value");
+ expect(valueRef.isWrite()).to.be.true;
+ expect(valueRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle identifiers in child JSX expression containers with JSX enabled", () => {
+ const ast = espree(`
+ const value = "test";
+ const MyComponent = () =>
{value}
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // value, MyComponent
+ expect(scope.references).to.have.length(2); // value def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // value def, value use
+ expect(scope.through).to.have.length(0);
+
+ const valueRef = scope.references[0];
+
+ expect(valueRef.identifier.name).to.equal("value");
+ expect(valueRef.isWrite()).to.be.true;
+ expect(valueRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle identifiers in child JSX expression containers with JSX disabled", () => {
+ const ast = espree(`
+ const value = "test";
+ const MyComponent = () =>
{value}
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: false });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // value, MyComponent
+ expect(scope.references).to.have.length(2); // value def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // value def, value use
+ expect(scope.through).to.have.length(0);
+
+ const valueRef = scope.references[0];
+
+ expect(valueRef.identifier.name).to.equal("value");
+ expect(valueRef.isWrite()).to.be.true;
+ expect(valueRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle nested JSX component references", () => {
+ const ast = espree(`
+ const Child = () =>
;
+ const Parent = () => (
+
+
+
+
+ );
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // Child, Parent
+ expect(scope.references).to.have.length(2); // Child, Parent
+ expect(scope.variables[0].references).to.have.length(3); // Child def, Child use x2
+
+ const childRefs = scope.references.filter(ref => ref.identifier.name === "Child");
+
+ expect(childRefs).to.have.length(1); // 1 def
+ expect(childRefs[0].isWrite()).to.be.true;
+ expect(childRefs[0].resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle JSX fragment references", () => {
+ const ast = espree(`
+ const MyComponent = () => (
+ <>
+
+
+ >
+ );
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(1); // MyComponent
+ expect(scope.references).to.have.length(1); // MyComponent
+ });
+
+ it("should handle JSX fragments with component children", () => {
+ const ast = espree(`
+ const Child = () =>
;
+ const Parent = () => (
+ <>
+
+
+ >
+ );
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // Child, Parent
+ expect(scope.references).to.have.length(2); // Child, Parent
+ expect(scope.variables[0].references).to.have.length(3); // Child def, Child use x2
+
+ const childRefs = scope.references.filter(ref => ref.identifier.name === "Child");
+
+ expect(childRefs).to.have.length(1); // 1 def
+ expect(childRefs[0].isWrite()).to.be.true;
+ expect(childRefs[0].resolved).to.equal(scope.variables[0]);
+ });
+
+ it("no JSX equivalent: should handle JSX fragments with component children", () => {
+ const ast = espree(`
+ const Child = () =>
;
+ const Parent = () => (
+ [
+ Child,
+ Child
+ ]
+ );
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6 });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // Child, Parent
+ expect(scope.references).to.have.length(2); // Child, Parent
+ expect(scope.variables[0].references).to.have.length(3); // Child def, Child use x2
+
+ const childRefs = scope.references.filter(ref => ref.identifier.name === "Child");
+
+ expect(childRefs).to.have.length(1); // 1 def
+ expect(childRefs[0].isWrite()).to.be.true;
+ expect(childRefs[0].resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle JSX spread attributes", () => {
+ const ast = espree(`
+ const props = { attr: "value" };
+ const MyComponent = () =>
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // props, MyComponent
+ expect(scope.references).to.have.length(2); // props def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // props def, props use
+
+ const propsRef = scope.references[0];
+
+ expect(propsRef.identifier.name).to.equal("props");
+ expect(propsRef.isWrite()).to.be.true;
+ expect(propsRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("no JSX equivalent: should handle JSX spread attributes", () => {
+ const ast = espree(`
+ const props = { attr: "value" };
+ const MyComponent = () => [...props];
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6 });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // props, MyComponent
+ expect(scope.references).to.have.length(2); // props def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // props def, props use
+
+ const propsRef = scope.references[0];
+
+ expect(propsRef.identifier.name).to.equal("props");
+ expect(propsRef.isWrite()).to.be.true;
+ expect(propsRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle JSX spread attributes with destructuring", () => {
+ const ast = espree(`
+ const props = { attr: "value" };
+ const MyComponent = ({ attr }) =>
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // props, MyComponent
+ expect(scope.references).to.have.length(2); // props def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // props def, props use
+
+ const propsRef = scope.references[0];
+
+ expect(propsRef.identifier.name).to.equal("props");
+ expect(propsRef.isWrite()).to.be.true;
+ expect(propsRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("no JSX equivalent: should handle JSX spread attributes with destructuring", () => {
+ const ast = espree(`
+ const props = { attr: "value" };
+ const MyComponent = ({ attr }) => [...props];
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6 });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // props, MyComponent
+ expect(scope.references).to.have.length(2); // props def, MyComponent def
+ expect(scope.variables[0].references).to.have.length(2); // props def, props use
+
+ const propsRef = scope.references[0];
+
+ expect(propsRef.identifier.name).to.equal("props");
+ expect(propsRef.isWrite()).to.be.true;
+ expect(propsRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle JSX
syntax", () => {
+ const ast = espree(`
+ const obj = { prop: () =>
};
+ const element =
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // obj, element
+ expect(scope.references).to.have.length(3); // obj def, element def, obj.prop use
+
+ const objRef = scope.references[2];
+
+ expect(objRef.identifier.name).to.equal("obj");
+ expect(objRef.isRead()).to.be.true;
+ expect(objRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("no JSX equivalent: should handle JSX
syntax", () => {
+ const ast = espree(`
+ const obj = { prop: () =>
};
+ const element = obj.prop;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6 });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // obj, element
+ expect(scope.references).to.have.length(3); // obj def, element def, obj.prop use
+
+ const objRef = scope.references[2];
+
+ expect(objRef.identifier.name).to.equal("obj");
+ expect(objRef.isRead()).to.be.true;
+ expect(objRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should handle JSX elements with a namespace", () => {
+ const ast = espree(`
+ const MyNamespace = {};
+ MyNamespace.MyComponent = () =>
;
+ const element =
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // MyNamespace, element
+ expect(scope.references).to.have.length(4); // MyNamespace def, MyComponent def, element def, MyNamespace.MyComponent use
+
+ const myNamespaceRef = scope.references[3];
+
+ expect(myNamespaceRef.identifier.name).to.equal("MyNamespace");
+ expect(myNamespaceRef.isRead()).to.be.true;
+ expect(myNamespaceRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should ignore JSX namespaced names", () => {
+ const ast = espree(`
+ const MyNamespace = {};
+ const element =
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(2); // MyNamespace, element
+ expect(scope.references).to.have.length(2); // MyNamespace def, element def
+
+ const myNamespaceRef = scope.references[0];
+
+ expect(myNamespaceRef.identifier.name).to.equal("MyNamespace");
+ expect(myNamespaceRef.isWrite()).to.be.true;
+ expect(myNamespaceRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("should not treat any JSX identifiers as references with JSX disabled", () => {
+ const ast = espree(`
+
;
+
;
+
;
+
;
+
;
+
;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: false });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.variables).to.have.length(0);
+ expect(scope.references).to.have.length(0);
+ });
+
+ it("should not treat 'this' as a reference when used in a JSX tagname", () => {
+
+ const ast = espree(`
+ this.MyComponent = () => ;
+ const element = ;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6, jsx: true });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.references.length).to.equal(1);
+ expect(scope.variables.length).to.equal(1);
+
+ const elementRef = scope.references[0];
+
+ expect(elementRef.identifier.name).to.equal("element");
+ expect(elementRef.isWrite()).to.be.true;
+ expect(elementRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ it("no JSX equivalent: should not treat 'this' as a reference when used in a JSX tagname", () => {
+
+ const ast = espree(`
+ this.MyComponent = () => ;
+ const element = this.MyComponent;
+ `, "script", true);
+
+ const scopeManager = analyze(ast, { ecmaVersion: 6 });
+ const scope = scopeManager.scopes[0];
+
+ expect(scope.references.length).to.equal(1);
+ expect(scope.variables.length).to.equal(1);
+
+ const elementRef = scope.references[0];
+
+ expect(elementRef.identifier.name).to.equal("element");
+ expect(elementRef.isWrite()).to.be.true;
+ expect(elementRef.resolved).to.equal(scope.variables[0]);
+ });
+
+ });
+
+
+});
diff --git a/packages/eslint-scope/tests/util/espree.js b/packages/eslint-scope/tests/util/espree.js
index 3e3de7a0..d005eb1f 100644
--- a/packages/eslint-scope/tests/util/espree.js
+++ b/packages/eslint-scope/tests/util/espree.js
@@ -28,13 +28,17 @@ import * as espree from "espree";
* Parse into Espree AST.
* @param {string} code The code
* @param {"module"|"script"} [sourceType="module"] The source type
+ * @param {boolean} [jsx=false] The flag to enable JSX parsing
* @returns {Object} The parsed Espree AST
*/
-export default function(code, sourceType = "module") {
+export default function(code, sourceType = "module", jsx = false) {
return espree.parse(code, {
range: true,
ecmaVersion: 7,
- sourceType
+ sourceType,
+ ecmaFeatures: {
+ jsx
+ }
});
}
diff --git a/packages/eslint-visitor-keys/README.md b/packages/eslint-visitor-keys/README.md
index 3cbbdd39..3bb0e93b 100644
--- a/packages/eslint-visitor-keys/README.md
+++ b/packages/eslint-visitor-keys/README.md
@@ -111,9 +111,9 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors
-
Silver Sponsors
-

Bronze Sponsors
-

+

Silver Sponsors
+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-extends-type-reference.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/bad-extends-type-reference.d.ts
deleted file mode 100644
index 1457d679..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-extends-type-reference.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface Something extends BadSomething {
- type: "Something";
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-parameters.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-parameters.d.ts
deleted file mode 100644
index 0095c9c2..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-parameters.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface Statement {}
-
-export interface StaticBlock extends BadTypeParam {
- type: "StaticBlock";
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-reference.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-reference.d.ts
deleted file mode 100644
index 9c226f18..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-reference.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface StaticBlock extends Omit {
- type: "StaticBlock";
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-value.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-value.d.ts
deleted file mode 100644
index 973aa2bb..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type-value.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-interface BadExpression {
- type: undefined;
-}
-
-export interface NewFangledExpression {
- type: "NewFangledExpression";
- right: BadExpression;
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type.d.ts
deleted file mode 100644
index ce4b9830..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/bad-type.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface SomeExpression {
- type: "SomeExpression";
- someProperty: any;
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-bad.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-bad.d.ts
deleted file mode 100644
index 99389eac..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-bad.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface NewFangledExpression {
- type: "NewFangledExpression";
- right: BadExpression;
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old-order-switched.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old-order-switched.d.ts
deleted file mode 100644
index dc0141da..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old-order-switched.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export type AssignmentOperator = "=";
-interface Pattern {
- type: "Pattern"
-};
-interface MemberExpression {
- type: "MemberExpression"
-};
-interface Expression {
- type: "Expression"
-};
-
-export interface AssignmentExpression {
- type: "AssignmentExpression";
- operator: AssignmentOperator;
- down: Expression;
- up: Expression;
- left: Pattern | MemberExpression;
- right: Expression;
- nontraversable: RegExp;
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old-other-order.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old-other-order.d.ts
deleted file mode 100644
index 3f9d5d34..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old-other-order.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export type AssignmentOperator = "=";
-interface Pattern {
- type: "Pattern"
-};
-interface MemberExpression {
- type: "MemberExpression"
-};
-interface Expression {
- type: "Expression"
-};
-
-export interface AssignmentExpression {
- type: "AssignmentExpression";
- operator: AssignmentOperator;
- up: Expression;
- left: Pattern | MemberExpression;
- down: Expression;
- right: Expression;
- nontraversable: RegExp;
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old.d.ts
deleted file mode 100644
index 1ac742c0..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys-on-old.d.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-export type AssignmentOperator = "=";
-
-interface IgnoreBase {
- type: "Line";
-}
-
-type AnotherIgnore = IgnoreBase;
-
-interface BasePattern {
- type: "Pattern"
-};
-interface IgnoreChild extends Omit {
-};
-
-interface Pattern {
- type: "Pattern"
-};
-interface MemberExpression {
- type: "MemberExpression"
-};
-interface Expression {
- type: "Expression"
-};
-
-export interface AssignmentExpression {
- type: "AssignmentExpression";
- ignore: IgnoreChild;
- anotherIgnore: AnotherIgnore;
- operator: AssignmentOperator;
- up: Expression;
- down: Expression;
- left: Pattern | MemberExpression;
- right: Expression;
- nontraversable: RegExp;
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys.d.ts
deleted file mode 100644
index 6ff0aa89..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/new-keys.d.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export type AssignmentOperator = "=";
-interface Pattern {
- type: "Pattern"
-};
-interface MemberExpression {
- type: "MemberExpression"
-};
-interface Expression {
- type: "Expression"
-};
-
-export interface NewFangledExpression {
- type: "NewFangledExpression";
- operator: AssignmentOperator;
- up: Expression;
- down: Expression;
- left: Pattern | MemberExpression;
- right: Expression;
-}
diff --git a/packages/eslint-visitor-keys/tests/lib/fixtures/union-omit.d.ts b/packages/eslint-visitor-keys/tests/lib/fixtures/union-omit.d.ts
deleted file mode 100644
index d6088df3..00000000
--- a/packages/eslint-visitor-keys/tests/lib/fixtures/union-omit.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export interface IgnoredStatement {
- type: "IgnoredStatement"
-}
-export interface AnotherStatement {
- type: "AnotherStatement";
- anotherToIgnore: IgnoredStatement;
-}
-
-export interface StaticBlock extends Omit {
- type: "StaticBlock";
-}
diff --git a/packages/espree/README.md b/packages/espree/README.md
index b971ea5a..22e3c7e8 100644
--- a/packages/espree/README.md
+++ b/packages/espree/README.md
@@ -236,6 +236,8 @@ Espree supports all ECMAScript 2024 features and partially supports ECMAScript 2
Because ECMAScript 2025 is still under development, we are implementing features as they are finalized. Currently, Espree supports:
* [RegExp Duplicate named capturing groups](https://github.com/tc39/proposal-duplicate-named-capturing-groups)
+* [RegExp Pattern modifiers](https://github.com/tc39/proposal-regexp-modifiers)
+* [Import Attributes](https://github.com/tc39/proposal-import-attributes)
See [finished-proposals.md](https://github.com/tc39/proposals/blob/master/finished-proposals.md) to know what features are finalized.
@@ -252,9 +254,9 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors
-
Silver Sponsors
-

Bronze Sponsors
-

+

Silver Sponsors
+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy