diff --git a/.changeset/serious-mayflies-yell.md b/.changeset/serious-mayflies-yell.md
new file mode 100644
index 000000000..a03e61934
--- /dev/null
+++ b/.changeset/serious-mayflies-yell.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-svelte": minor
+---
+
+feat: Add `svelte/valid-context-access` rule
diff --git a/README.md b/README.md
index a5661af1c..17599fee5 100644
--- a/README.md
+++ b/README.md
@@ -320,6 +320,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/require-store-callbacks-use-set-param](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | store callbacks must use `set` param | |
| [svelte/require-store-reactive-access](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-reactive-access/) | disallow to use of the store itself as an operand. Need to use $ prefix or get function. | :wrench: |
| [svelte/valid-compile](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | :star: |
+| [svelte/valid-context-access](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-context-access/) | context functions must be called during component initialization. | |
| [svelte/valid-prop-names-in-kit-pages](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-prop-names-in-kit-pages/) | disallow props other than data or errors in SvelteKit page components. | |
## Security Vulnerability
diff --git a/docs/rules.md b/docs/rules.md
index ef85cb467..968875980 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -33,6 +33,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/require-store-callbacks-use-set-param](./rules/require-store-callbacks-use-set-param.md) | store callbacks must use `set` param | |
| [svelte/require-store-reactive-access](./rules/require-store-reactive-access.md) | disallow to use of the store itself as an operand. Need to use $ prefix or get function. | :wrench: |
| [svelte/valid-compile](./rules/valid-compile.md) | disallow warnings when compiling. | :star: |
+| [svelte/valid-context-access](./rules/valid-context-access.md) | context functions must be called during component initialization. | |
| [svelte/valid-prop-names-in-kit-pages](./rules/valid-prop-names-in-kit-pages.md) | disallow props other than data or errors in SvelteKit page components. | |
## Security Vulnerability
diff --git a/docs/rules/valid-context-access.md b/docs/rules/valid-context-access.md
new file mode 100644
index 000000000..365b4b23e
--- /dev/null
+++ b/docs/rules/valid-context-access.md
@@ -0,0 +1,79 @@
+---
+pageClass: "rule-details"
+sidebarDepth: 0
+title: "svelte/valid-context-access"
+description: "context functions must be called during component initialization."
+---
+
+# svelte/valid-context-access
+
+> context functions must be called during component initialization.
+
+- :exclamation: **_This rule has not been released yet._**
+
+## :book: Rule Details
+
+This rule reports where context API is called except during component initialization.
+
+
+
+
+
+```svelte
+
+```
+
+
+
+- :warning: This rule only inspects Svelte files, not JS / TS files.
+
+## :wrench: Options
+
+Nothing.
+
+## :books: Further Reading
+
+- [Svelte - Docs > RUN TIME > svelte > setContext](https://svelte.dev/docs#run-time-svelte-setcontext)
+- [Svelte - Docs > RUN TIME > svelte > getContext](https://svelte.dev/docs#run-time-svelte-getContext)
+- [Svelte - Docs > RUN TIME > svelte > hasContext](https://svelte.dev/docs#run-time-svelte-hasContext)
+- [Svelte - Docs > RUN TIME > svelte > getAllContexts](https://svelte.dev/docs#run-time-svelte-getAllContexts)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/src/rules/valid-context-access.ts)
+- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/tests/src/rules/valid-context-access.ts)
diff --git a/src/rules/infinite-reactive-loop.ts b/src/rules/infinite-reactive-loop.ts
index 13ea8741a..fe0075e16 100644
--- a/src/rules/infinite-reactive-loop.ts
+++ b/src/rules/infinite-reactive-loop.ts
@@ -1,57 +1,11 @@
import type { TSESTree } from "@typescript-eslint/types"
import type { AST } from "svelte-eslint-parser"
-import { ReferenceTracker } from "@eslint-community/eslint-utils"
import { createRule } from "../utils"
import type { RuleContext } from "../types"
import { findVariable } from "../utils/ast-utils"
import { traverseNodes } from "svelte-eslint-parser"
-
-/**
- * Get usage of `tick`
- */
-function extractTickReferences(
- context: RuleContext,
-): { node: TSESTree.CallExpression; name: string }[] {
- const referenceTracker = new ReferenceTracker(
- context.getSourceCode().scopeManager.globalScope!,
- )
- const a = referenceTracker.iterateEsmReferences({
- svelte: {
- [ReferenceTracker.ESM]: true,
- tick: {
- [ReferenceTracker.CALL]: true,
- },
- },
- })
- return Array.from(a).map(({ node, path }) => {
- return {
- node: node as TSESTree.CallExpression,
- name: path[path.length - 1],
- }
- })
-}
-
-/**
- * Get usage of `setTimeout`, `setInterval`, `queueMicrotask`
- */
-function extractTaskReferences(
- context: RuleContext,
-): { node: TSESTree.CallExpression; name: string }[] {
- const referenceTracker = new ReferenceTracker(
- context.getSourceCode().scopeManager.globalScope!,
- )
- const a = referenceTracker.iterateGlobalReferences({
- setTimeout: { [ReferenceTracker.CALL]: true },
- setInterval: { [ReferenceTracker.CALL]: true },
- queueMicrotask: { [ReferenceTracker.CALL]: true },
- })
- return Array.from(a).map(({ node, path }) => {
- return {
- node: node as TSESTree.CallExpression,
- name: path[path.length - 1],
- }
- })
-}
+import { extractSvelteLifeCycleReferences } from "./reference-helpers/svelte-lifecycle"
+import { extractTaskReferences } from "./reference-helpers/microtask"
/**
* If `node` is inside of `maybeAncestorNode`, return true.
@@ -400,12 +354,14 @@ export default createRule("infinite-reactive-loop", {
type: "suggestion",
},
create(context) {
+ const tickCallExpressions = Array.from(
+ extractSvelteLifeCycleReferences(context, ["tick"]),
+ )
+ const taskReferences = Array.from(extractTaskReferences(context))
+ const reactiveVariableReferences = getReactiveVariableReferences(context)
+
return {
["SvelteReactiveStatement"]: (ast: AST.SvelteReactiveStatement) => {
- const tickCallExpressions = extractTickReferences(context)
- const taskReferences = extractTaskReferences(context)
- const reactiveVariableReferences =
- getReactiveVariableReferences(context)
const trackedVariableNodes = getTrackedVariableNodes(
reactiveVariableReferences,
ast,
diff --git a/src/rules/reference-helpers/microtask.ts b/src/rules/reference-helpers/microtask.ts
new file mode 100644
index 000000000..073b968a2
--- /dev/null
+++ b/src/rules/reference-helpers/microtask.ts
@@ -0,0 +1,37 @@
+import type { TSESTree } from "@typescript-eslint/types"
+import { ReferenceTracker } from "@eslint-community/eslint-utils"
+import type { RuleContext } from "../../types"
+
+type FunctionName = "setTimeout" | "setInterval" | "queueMicrotask"
+
+/**
+ * Get usage of `setTimeout`, `setInterval`, `queueMicrotask`
+ */
+export function* extractTaskReferences(
+ context: RuleContext,
+ functionNames: FunctionName[] = [
+ "setTimeout",
+ "setInterval",
+ "queueMicrotask",
+ ],
+): Generator<{ node: TSESTree.CallExpression; name: string }, void> {
+ const referenceTracker = new ReferenceTracker(
+ context.getSourceCode().scopeManager.globalScope!,
+ )
+ for (const { node, path } of referenceTracker.iterateGlobalReferences({
+ setTimeout: {
+ [ReferenceTracker.CALL]: functionNames.includes("setTimeout"),
+ },
+ setInterval: {
+ [ReferenceTracker.CALL]: functionNames.includes("setInterval"),
+ },
+ queueMicrotask: {
+ [ReferenceTracker.CALL]: functionNames.includes("queueMicrotask"),
+ },
+ })) {
+ yield {
+ node: node as TSESTree.CallExpression,
+ name: path[path.length - 1],
+ }
+ }
+}
diff --git a/src/rules/reference-helpers/svelte-context.ts b/src/rules/reference-helpers/svelte-context.ts
new file mode 100644
index 000000000..ebeb8f57a
--- /dev/null
+++ b/src/rules/reference-helpers/svelte-context.ts
@@ -0,0 +1,42 @@
+import type { TSESTree } from "@typescript-eslint/types"
+import { ReferenceTracker } from "@eslint-community/eslint-utils"
+import type { RuleContext } from "../../types"
+
+type ContextName = "setContext" | "getContext" | "hasContext" | "getAllContexts"
+
+/** Extract svelte's context API references */
+export function* extractContextReferences(
+ context: RuleContext,
+ contextNames: ContextName[] = [
+ "setContext",
+ "getContext",
+ "hasContext",
+ "getAllContexts",
+ ],
+): Generator<{ node: TSESTree.CallExpression; name: string }, void> {
+ const referenceTracker = new ReferenceTracker(
+ context.getSourceCode().scopeManager.globalScope!,
+ )
+ for (const { node, path } of referenceTracker.iterateEsmReferences({
+ svelte: {
+ [ReferenceTracker.ESM]: true,
+ setContext: {
+ [ReferenceTracker.CALL]: contextNames.includes("setContext"),
+ },
+ getContext: {
+ [ReferenceTracker.CALL]: contextNames.includes("getContext"),
+ },
+ hasContext: {
+ [ReferenceTracker.CALL]: contextNames.includes("hasContext"),
+ },
+ getAllContexts: {
+ [ReferenceTracker.CALL]: contextNames.includes("getAllContexts"),
+ },
+ },
+ })) {
+ yield {
+ node: node as TSESTree.CallExpression,
+ name: path[path.length - 1],
+ }
+ }
+}
diff --git a/src/rules/reference-helpers/svelte-lifecycle.ts b/src/rules/reference-helpers/svelte-lifecycle.ts
new file mode 100644
index 000000000..2b05069b7
--- /dev/null
+++ b/src/rules/reference-helpers/svelte-lifecycle.ts
@@ -0,0 +1,53 @@
+import type { TSESTree } from "@typescript-eslint/types"
+import { ReferenceTracker } from "@eslint-community/eslint-utils"
+import type { RuleContext } from "../../types"
+
+type LifeCycleName =
+ | "onMount"
+ | "beforeUpdate"
+ | "afterUpdate"
+ | "onDestroy"
+ | "tick"
+
+/**
+ * Get usage of Svelte life cycle functions.
+ */
+export function* extractSvelteLifeCycleReferences(
+ context: RuleContext,
+ fuctionName: LifeCycleName[] = [
+ "onMount",
+ "beforeUpdate",
+ "afterUpdate",
+ "onDestroy",
+ "tick",
+ ],
+): Generator<{ node: TSESTree.CallExpression; name: string }, void> {
+ const referenceTracker = new ReferenceTracker(
+ context.getSourceCode().scopeManager.globalScope!,
+ )
+ for (const { node, path } of referenceTracker.iterateEsmReferences({
+ svelte: {
+ [ReferenceTracker.ESM]: true,
+ onMount: {
+ [ReferenceTracker.CALL]: fuctionName.includes("onMount"),
+ },
+ beforeUpdate: {
+ [ReferenceTracker.CALL]: fuctionName.includes("beforeUpdate"),
+ },
+ afterUpdate: {
+ [ReferenceTracker.CALL]: fuctionName.includes("afterUpdate"),
+ },
+ onDestroy: {
+ [ReferenceTracker.CALL]: fuctionName.includes("onDestroy"),
+ },
+ tick: {
+ [ReferenceTracker.CALL]: fuctionName.includes("tick"),
+ },
+ },
+ })) {
+ yield {
+ node: node as TSESTree.CallExpression,
+ name: path[path.length - 1],
+ }
+ }
+}
diff --git a/src/rules/valid-context-access.ts b/src/rules/valid-context-access.ts
new file mode 100644
index 000000000..cd8490f1e
--- /dev/null
+++ b/src/rules/valid-context-access.ts
@@ -0,0 +1,223 @@
+import { createRule } from "../utils"
+import { extractContextReferences } from "./reference-helpers/svelte-context"
+import { extractSvelteLifeCycleReferences } from "./reference-helpers/svelte-lifecycle"
+import { extractTaskReferences } from "./reference-helpers/microtask"
+import { isInsideOfPromiseThenOrCatch } from "../utils/promise"
+import type { AST } from "svelte-eslint-parser"
+import type { TSESTree } from "@typescript-eslint/types"
+
+export default createRule("valid-context-access", {
+ meta: {
+ docs: {
+ description:
+ "context functions must be called during component initialization.",
+ category: "Possible Errors",
+ recommended: false,
+ },
+ schema: [],
+ messages: {
+ unexpected:
+ "Do not call {{function}} except during component initialization.",
+ },
+ type: "problem",
+ },
+ create(context) {
+ // // This rule doesn't check other than Svelte files.
+ if (!context.parserServices.isSvelte) {
+ return {}
+ }
+
+ const sourceCode = context.getSourceCode()
+ const lifeCycleReferences = Array.from(
+ extractSvelteLifeCycleReferences(context),
+ ).map((r) => r.node)
+ const taskReferences = Array.from(extractTaskReferences(context))
+
+ // Extract
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case02-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case02-errors.yaml
new file mode 100644
index 000000000..f33732b66
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case02-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 5
+ column: 5
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case02-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case02-input.svelte
new file mode 100644
index 000000000..b0af74395
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case02-input.svelte
@@ -0,0 +1,7 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case03-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case03-errors.yaml
new file mode 100644
index 000000000..96c6f1b93
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case03-errors.yaml
@@ -0,0 +1,4 @@
+- message: Do not call setContext except during component initialization.
+ line: 4
+ column: 5
+ suggestions: null
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case03-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case03-input.svelte
new file mode 100644
index 000000000..2df88bc18
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case03-input.svelte
@@ -0,0 +1,8 @@
+
+
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case04-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case04-errors.yaml
new file mode 100644
index 000000000..96c6f1b93
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case04-errors.yaml
@@ -0,0 +1,4 @@
+- message: Do not call setContext except during component initialization.
+ line: 4
+ column: 5
+ suggestions: null
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case04-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case04-input.svelte
new file mode 100644
index 000000000..4b62a8d4e
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case04-input.svelte
@@ -0,0 +1,13 @@
+
+
+{#if true}
+ {@const foo = something()}
+
+{/if}
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case05-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case05-errors.yaml
new file mode 100644
index 000000000..96c6f1b93
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case05-errors.yaml
@@ -0,0 +1,4 @@
+- message: Do not call setContext except during component initialization.
+ line: 4
+ column: 5
+ suggestions: null
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case05-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case05-input.svelte
new file mode 100644
index 000000000..b21f3b9b8
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case05-input.svelte
@@ -0,0 +1,12 @@
+
+
+{#if something()}
+
+{/if}
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case06-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case06-errors.yaml
new file mode 100644
index 000000000..9d0ec949e
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case06-errors.yaml
@@ -0,0 +1,4 @@
+- message: Do not call setContext except during component initialization.
+ line: 5
+ column: 7
+ suggestions: null
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case06-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case06-input.svelte
new file mode 100644
index 000000000..310840bb8
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case06-input.svelte
@@ -0,0 +1,15 @@
+
+
+{#if something()}
+
+{/if}
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case07-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case07-errors.yaml
new file mode 100644
index 000000000..5702a7bed
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case07-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call hasContext except during component initialization.
+ line: 5
+ column: 9
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case07-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case07-input.svelte
new file mode 100644
index 000000000..5484f2dc9
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case07-input.svelte
@@ -0,0 +1,9 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case08-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case08-errors.yaml
new file mode 100644
index 000000000..6e01eaa01
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case08-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 6
+ column: 5
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case08-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case08-input.svelte
new file mode 100644
index 000000000..574c3b3ab
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case08-input.svelte
@@ -0,0 +1,9 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case09-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case09-errors.yaml
new file mode 100644
index 000000000..8a807194f
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case09-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 3
+ column: 3
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case09-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case09-input.svelte
new file mode 100644
index 000000000..0017cf865
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case09-input.svelte
@@ -0,0 +1,4 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case10-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case10-errors.yaml
new file mode 100644
index 000000000..f33732b66
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case10-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 5
+ column: 5
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case10-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case10-input.svelte
new file mode 100644
index 000000000..0d504f5ff
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case10-input.svelte
@@ -0,0 +1,7 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case11-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case11-errors.yaml
new file mode 100644
index 000000000..0897a75a9
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case11-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 6
+ column: 7
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case11-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case11-input.svelte
new file mode 100644
index 000000000..dc9f3571b
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case11-input.svelte
@@ -0,0 +1,11 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case12-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case12-errors.yaml
new file mode 100644
index 000000000..28b8f23b8
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case12-errors.yaml
@@ -0,0 +1,12 @@
+- message: Do not call setContext except during component initialization.
+ line: 5
+ column: 5
+- message: Do not call setContext except during component initialization.
+ line: 9
+ column: 5
+- message: Do not call setContext except during component initialization.
+ line: 13
+ column: 5
+- message: Do not call setContext except during component initialization.
+ line: 17
+ column: 5
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case12-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case12-input.svelte
new file mode 100644
index 000000000..c170ecc49
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case12-input.svelte
@@ -0,0 +1,19 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case13-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case13-errors.yaml
new file mode 100644
index 000000000..f33732b66
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case13-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 5
+ column: 5
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case13-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case13-input.svelte
new file mode 100644
index 000000000..80ddb16c4
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case13-input.svelte
@@ -0,0 +1,7 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case14-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case14-errors.yaml
new file mode 100644
index 000000000..4055b4a9a
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case14-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 4
+ column: 5
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case14-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case14-input.svelte
new file mode 100644
index 000000000..e8a9b151e
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case14-input.svelte
@@ -0,0 +1,10 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case15-errors.yaml b/tests/fixtures/rules/valid-context-access/invalid/case15-errors.yaml
new file mode 100644
index 000000000..4055b4a9a
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case15-errors.yaml
@@ -0,0 +1,3 @@
+- message: Do not call setContext except during component initialization.
+ line: 4
+ column: 5
diff --git a/tests/fixtures/rules/valid-context-access/invalid/case15-input.svelte b/tests/fixtures/rules/valid-context-access/invalid/case15-input.svelte
new file mode 100644
index 000000000..f0df9c344
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/invalid/case15-input.svelte
@@ -0,0 +1,11 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case01-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case01-input.svelte
new file mode 100644
index 000000000..3ec7fa441
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case01-input.svelte
@@ -0,0 +1,8 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case02-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case02-input.svelte
new file mode 100644
index 000000000..bab6b283a
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case02-input.svelte
@@ -0,0 +1,6 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case03-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case03-input.svelte
new file mode 100644
index 000000000..461a5f1f3
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case03-input.svelte
@@ -0,0 +1,8 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case04-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case04-input.svelte
new file mode 100644
index 000000000..852518424
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case04-input.svelte
@@ -0,0 +1,15 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case05-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case05-input.svelte
new file mode 100644
index 000000000..49cce3bc7
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case05-input.svelte
@@ -0,0 +1,6 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case06-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case06-input.svelte
new file mode 100644
index 000000000..17e2ae7e2
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case06-input.svelte
@@ -0,0 +1,15 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case07-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case07-input.svelte
new file mode 100644
index 000000000..24c5ae0a4
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case07-input.svelte
@@ -0,0 +1,12 @@
+
+
+{#if something}
+
+{/if}
diff --git a/tests/fixtures/rules/valid-context-access/valid/case08-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case08-input.svelte
new file mode 100644
index 000000000..c0b2b1d8b
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case08-input.svelte
@@ -0,0 +1,22 @@
+
diff --git a/tests/fixtures/rules/valid-context-access/valid/case09-input.js b/tests/fixtures/rules/valid-context-access/valid/case09-input.js
new file mode 100644
index 000000000..4d3f8fe4c
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case09-input.js
@@ -0,0 +1,17 @@
+import { setContext } from "svelte"
+
+const something = () => {
+ setContext("answer", 42)
+}
+
+const something2 = async () => {
+ await Promise.resolve()
+ setContext("answer", 42)
+}
+
+const aaa = (fn) => {
+ fn()
+}
+
+aaa(() => something())
+something2()
diff --git a/tests/fixtures/rules/valid-context-access/valid/case10-input.svelte b/tests/fixtures/rules/valid-context-access/valid/case10-input.svelte
new file mode 100644
index 000000000..fac4aafc3
--- /dev/null
+++ b/tests/fixtures/rules/valid-context-access/valid/case10-input.svelte
@@ -0,0 +1,6 @@
+
diff --git a/tests/src/rules/valid-context-access.ts b/tests/src/rules/valid-context-access.ts
new file mode 100644
index 000000000..f40dafd6d
--- /dev/null
+++ b/tests/src/rules/valid-context-access.ts
@@ -0,0 +1,20 @@
+import { RuleTester } from "eslint"
+import rule from "../../../src/rules/valid-context-access"
+import { loadTestCases } from "../../utils/utils"
+
+const tester = new RuleTester({
+ parserOptions: {
+ ecmaVersion: 2020,
+ sourceType: "module",
+ },
+ env: {
+ browser: true,
+ es2017: true,
+ },
+})
+
+tester.run(
+ "valid-context-access",
+ rule as any,
+ loadTestCases("valid-context-access"),
+)