Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 65 additions & 2 deletions concepts/analyzers/typescript-sveltekit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,71 @@ also reads literal SvelteKit `kit.alias` values. When a required alias is dynami
Fensu fails with a configuration diagnostic rather than guessing. A missing
generated `.svelte-kit/tsconfig.json` is accepted on a fresh checkout.

Python custom rules and `fensu map` remain Python analyzer features. Web targets
use the shipped native `typescript` or `sveltekit` catalogue.
## Custom web rules

Python-authored custom rules can extend a TypeScript or Svelte target without
changing its CLI, configuration, selectors, or policy model. Declare analyzer
applicability on the normal `@rule` decorator:

```python
from fensu import AnalyzerId, Family, Fault, File, RuleContext, rule


@rule(
code="XWEB001",
family=Family.CUSTOM,
slug="resolved-import-boundary",
message="Import crosses the configured boundary",
analyzers=(AnalyzerId.TYPESCRIPT,),
cacheable=True,
)
def resolved_import_boundary(*, file: File, ctx: RuleContext) -> list[Fault]:
facts = ctx.web.file(file)
if facts is None:
return []
return [
ctx.fault_at(location=edge.location)
for edge in ctx.graph.imports(file)
if edge.target is not None and edge.target.role == "_state"
]
```

Configure it like any other custom rule:

```toml
[targets.web]
analyzer = "typescript"
roots = ["src"]
tests = ["tests"]
tooling = []
rule_paths = ["rules/web.py"]
select = ["FPTS", "XWEB001"]
```

`ctx.web` exposes immutable Fensu-owned facts for TypeScript, JavaScript, and
Svelte sources. These include source kinds, resolved import targets, functions,
classes, models, bindings, calls, resources, exports, source locations, and stable
text handles. `ctx.graph` exposes the same resolved imports through the common
architecture graph, including `tsconfig.json`, `jsconfig.json`, `$lib`, and
literal SvelteKit alias resolution.

Svelte files add `SvelteFileFacts` for component markup, route identity, script
contexts, and runes. Svelte state modules such as `session.svelte.ts` are marked
separately and expose only recognized top-level initializer runes; nested calls
are not promoted to module-owned state.

File rules run once per selected source. A typed `Project` callback runs once for
the target and can query `ctx.web.files` and `ctx.project.tree`. Use focused
`ctx.web.file(...)`, tree, or graph queries when unrelated edits should preserve a
cached result. Every query records its actual answer for cache replay.

Web parsing and built-in rules always remain native and Node-free. Fensu starts a
bounded Python host only when configured custom sources and an active `X` selector
require hosted resolution. Native-only, unselected, and custom selections whose
selector prefixes are wholly covered by ignore prefixes remain Python-free. Actual
rule applicability is resolved inside the host. Custom diagnostics then pass
through the normal warnings, ignores, exceptions, rendering, and exit-code
handling. `fensu map` remains a Python analyzer feature.

## Gradual adoption

Expand Down
66 changes: 60 additions & 6 deletions reference/rule-context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,11 @@ unsupported path objects. `FilePosition` includes `path`, `analyzer`, `source_ki

## `ctx.graph`

For Python targets, an immutable architecture graph resolved from static imports
and authoritative discovered modules. Unresolved imports remain explicit and
dynamic imports are not represented.
For Python, TypeScript, and Svelte targets, an immutable architecture graph
resolved from static imports and authoritative discovered modules. Unresolved
imports remain explicit and dynamic imports are not represented. Web graph
resolution reuses the native analyzer's static TypeScript, JavaScript, SvelteKit,
and configured alias resolution.

| Call | Returns | Purpose |
| --- | --- | --- |
Expand Down Expand Up @@ -139,6 +141,38 @@ Each broad or focused call records its answer for subject-aware cache replay. Us
focused `file()` or `crate()` lookup when unrelated source or Cargo changes should
not invalidate a cached result.

## `ctx.web`

For TypeScript and Svelte targets, a versioned immutable fact view transferred from
the native analyzers. It contains no parser-library nodes and does not require
Node.

| Call | Returns | Purpose |
| --- | --- | --- |
| `files` | `tuple[WebFileFacts, ...]` | All discovered direct, support, excluded, and generated web source facts. |
| `file(file_or_path)` | `WebFileFacts \| None` | One focused file lookup by `File` or `ProjectPath`. |

`WebFileFacts` exposes its analyzer, `WebSourceKind`, `WebSourcePurpose`, module,
source root, scope, authored source, optional parse error, and immutable imports,
functions, classes, models, bindings, calls, resources, re-exports, and export
counts. `WebImportFact.target` is a `File` only when the native analyzer proves a
project-local destination. Use `ctx.graph` for resolved dependency and dependent
queries.

`syntax_handles` contains stable Fensu-owned `WebSyntaxHandle` byte ranges for
imports, declarations, calls, resources, re-exports, Svelte scripts, and runes.
Pass one to `WebFileFacts.text(handle)` to retrieve its authored text without
receiving an analyzer AST.

On Svelte targets, `WebFileFacts.svelte` is a `SvelteFileFacts` extension when the
file is a component or state module. It records script contexts, recognized
top-level runes, component markup, route identity, and state-module identity.
TypeScript-only targets do not require this extension.

Broad `files` and focused `file()` calls record their exact answers for
subject-aware cache replay. Tree and graph calls made during the same invocation
record their own query-specific dependencies.

## `ctx.text`, `ctx.syntax`, `ctx.relations`

Source text, opaque syntax identities, and syntax relationships for the current
Expand All @@ -160,9 +194,11 @@ The zone protocols are `FactAnalysis`, `ProjectAnalysis`, `TextAnalysis`,
`SyntaxAnalysis`, and `RelationAnalysis`, all exported from `fensu`.

The table above describes the Python analysis zones. Serialized Rust rules use
`ctx.rust`, `ctx.project.tree`, `ctx.source`, and stable locations. `ctx.graph`,
`ctx.syntax`, and `ctx.relations` are unavailable because parser implementation
objects are not part of the Rust authoring contract.
`ctx.rust`, `ctx.project.tree`, `ctx.source`, and stable locations. Serialized web
rules use `ctx.web`, `ctx.graph`, `ctx.project.tree`, `ctx.source`, and
`WebSyntaxHandle`. The generic `ctx.syntax` and `ctx.relations` zones are
unavailable because parser implementation objects are not part of native-analyzer
authoring contracts.

## Fault construction

Expand Down Expand Up @@ -328,6 +364,24 @@ are frozen dataclasses; inspect exact fields with your editor's type information
| `RustItemFact` | Function, struct, enum, trait, implementation or module declaration. |
| `RustUseFact` | Authored `use` path and explicit resolution evidence. |

**Web facts**

| Model | Describes |
| --- | --- |
| `WebWorkspaceFacts` | Versioned TypeScript or Svelte target facts. |
| `WebFileFacts` | One discovered web source, its semantic facts, source, and parse result. |
| `WebImportFact` | Authored import bindings, flags, location, and optional resolved target. |
| `WebFunctionFact` | Function ownership, annotations, return type, and structural metrics. |
| `WebClassFact` | Class identity, export status, and error-class classification. |
| `WebModelFact` | Interface or type-literal model shape and readonly evidence. |
| `WebBindingFact` | Top-level binding and optional initializer call. |
| `WebCallFact` | Named call, lexical function owner, ancestors, and cleanup evidence. |
| `WebResourceFact` | Statically recognized resource family, binding, and call ancestry. |
| `WebSyntaxHandle` | Fensu-owned kind, name, location, and stable source byte range. |
| `SvelteFileFacts` | Component, route, state-module, script, and rune extensions. |
| `SvelteScriptFact` | One module or instance script block. |
| `SvelteRuneFact` | One recognized module-owned rune and source location. |

**Test facts**

| Model | Describes |
Expand Down
Loading