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 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..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 @@ -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 (!isInTypeAnnotation(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) || isInTypeAnnotation(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 isInTypeAnnotation(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 @@ +