From caf09553e16474ad825238e073511cf9e50b7502 Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Sat, 17 May 2025 21:27:05 +0900 Subject: [PATCH 1/3] fix(no-top-level-browser-globals): false positives for type annotations --- .../src/rules/no-top-level-browser-globals.ts | 23 ++++++++++++++++++- .../valid/ts01-input.svelte | 3 +++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 packages/eslint-plugin-svelte/tests/fixtures/rules/no-top-level-browser-globals/valid/ts01-input.svelte diff --git a/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts b/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts index a3a94e6bc..c320d98a4 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts @@ -37,6 +37,7 @@ export default createRule('no-top-level-browser-globals', { const maybeGuards: MaybeGuard[] = []; const functions: TSESTree.FunctionLike[] = []; + const typeAnnotations: (TSESTree.TypeNode | TSESTree.TSTypeAnnotation)[] = []; function enterFunction(node: TSESTree.FunctionLike) { if (isTopLevelLocation(node)) { @@ -44,6 +45,12 @@ export default createRule('no-top-level-browser-globals', { } } + function enterTypeAnnotation(node: TSESTree.TypeNode | TSESTree.TSTypeAnnotation) { + if (!isTypeAnnotation(node)) { + typeAnnotations.push(node); + } + } + function enterMetaProperty(node: TSESTree.MetaProperty) { if (node.meta.name !== 'import' || node.property.name !== 'meta') return; for (const ref of referenceTracker.iteratePropertyReferences(node, { @@ -84,7 +91,7 @@ export default createRule('no-top-level-browser-globals', { // Collects references to global variables. for (const ref of iterateBrowserGlobalReferences()) { - if (!isTopLevelLocation(ref.node)) continue; + if (!isTopLevelLocation(ref.node) || isTypeAnnotation(ref.node)) continue; const guardChecker = getGuardCheckerFromReference(ref.node); if (guardChecker) { const name = ref.path.join('.'); @@ -113,6 +120,7 @@ export default createRule('no-top-level-browser-globals', { return { ':function': enterFunction, + '*.typeAnnotation': enterTypeAnnotation, MetaProperty: enterMetaProperty, 'Program:exit': verifyGlobalReferences }; @@ -145,6 +153,19 @@ export default createRule('no-top-level-browser-globals', { return true; } + /** + * Checks whether the node is in type annotation. + * @returns `true` if the node is in type annotation. + */ + function isTypeAnnotation(node: TSESTree.Node) { + for (const typeAnnotation of typeAnnotations) { + if (typeAnnotation.range[0] <= node.range[0] && node.range[1] <= typeAnnotation.range[1]) { + return true; + } + } + return false; + } + /** * Iterate over the references of modules that can check the browser environment. */ diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-top-level-browser-globals/valid/ts01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-top-level-browser-globals/valid/ts01-input.svelte new file mode 100644 index 000000000..93b8f55b9 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-top-level-browser-globals/valid/ts01-input.svelte @@ -0,0 +1,3 @@ + From 340b0d260a1c6722dc3f82dccb847c1b0a24791a Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Sat, 17 May 2025 21:28:25 +0900 Subject: [PATCH 2/3] rename function --- .../src/rules/no-top-level-browser-globals.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts b/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts index c320d98a4..1a997eca3 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-top-level-browser-globals.ts @@ -46,7 +46,7 @@ export default createRule('no-top-level-browser-globals', { } function enterTypeAnnotation(node: TSESTree.TypeNode | TSESTree.TSTypeAnnotation) { - if (!isTypeAnnotation(node)) { + if (!isInTypeAnnotation(node)) { typeAnnotations.push(node); } } @@ -91,7 +91,7 @@ export default createRule('no-top-level-browser-globals', { // Collects references to global variables. for (const ref of iterateBrowserGlobalReferences()) { - if (!isTopLevelLocation(ref.node) || isTypeAnnotation(ref.node)) continue; + if (!isTopLevelLocation(ref.node) || isInTypeAnnotation(ref.node)) continue; const guardChecker = getGuardCheckerFromReference(ref.node); if (guardChecker) { const name = ref.path.join('.'); @@ -157,7 +157,7 @@ export default createRule('no-top-level-browser-globals', { * Checks whether the node is in type annotation. * @returns `true` if the node is in type annotation. */ - function isTypeAnnotation(node: TSESTree.Node) { + function isInTypeAnnotation(node: TSESTree.Node) { for (const typeAnnotation of typeAnnotations) { if (typeAnnotation.range[0] <= node.range[0] && node.range[1] <= typeAnnotation.range[1]) { return true; From b0410b015433bb4d96310d750f8800c64b52cc26 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Sat, 17 May 2025 21:28:37 +0900 Subject: [PATCH 3/3] Create happy-weeks-argue.md --- .changeset/happy-weeks-argue.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/happy-weeks-argue.md diff --git a/.changeset/happy-weeks-argue.md b/.changeset/happy-weeks-argue.md new file mode 100644 index 000000000..8a798dc39 --- /dev/null +++ b/.changeset/happy-weeks-argue.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-svelte": patch +--- + +fix(no-top-level-browser-globals): false positives for type annotations