---
uid: application-development.code-weaving-and-generation.about-code-management-razor
description: "How to control code management for Razor files using Intent.Code.Weaving.Razor, including management modes, MoveHere and Skip instructions, and node matching."
---
# Razor Code Management

This article explains how to control [Code Management / Merging](https://docs.intentarchitect.com/docs-md/application-development/code-management/about-code-management/about-code-management.md) behaviour for `.razor` files when using the `Intent.Code.Weaving.Razor` module.

## Overview of how it works

The Razor Merger parses `.razor` files into an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) and applies code management logic on a node-by-node basis. An individual node on the _abstract syntax tree_ is referred to as a _syntax node_. _Syntax nodes_ may have one or more children which are also _syntax nodes_.

The Razor Merger compares the generated content from the template with the existing file (if there is one) on a node-by-node basis. Instructions are used by the Razor Merger for it to determine for a particular syntax node what content it should ignore, replace with content generated by the template or perhaps remove entirely.

## Code management instructions

Instructing the Razor Merger on how to treat particular syntax nodes is done using code management instructions in your source code, within Razor syntax, these are instructions like `@Intent.Ignore` above elements.

Within `@codeblock` directives, the Razor Merger is delegating to the RoslynWeaver, please refer to its [article](https://docs.intentarchitect.com/docs-md/application-development/code-management/code-management-csharp/code-management-csharp.md) for information on controlling C# Code management behaviour.

## Management modes

- **`@Intent.Fully(["<path>"])`** - Intent has full control over the particular syntax node, any deviations in the existing file's syntax node are overwritten with the content generated by the template. Descendant syntax nodes can be opted-out of being fully managed having an `@Intent.<mode>` instruction applied to them.
- **`@Intent.Merge(["<path>"])`** - Intent will add and remove Intent generated code for the syntax node but will never remove code which was manually added.
- **`@Intent.Ignore(["<path>"])`** - Intent must ignore this syntax node and not remove or overwrite it with content generated by the template. Code management instructions on descendant syntax nodes are likewise ignored, i.e. it is not possible to opt-out of being ignored as a descendant.

Each of the above can be suffixed with the following:

- **`Body`** - Override only the body mode behaviour of the syntax node, generally body refers to inner syntax nodes or the content of a syntax node.
- **`Signature`** - Override only the signature mode behaviour of the syntax node, generally this refers to aspects like HTML element / Directive attributes of a syntax node.

Each of the above can optionally have [path](#path-syntax) argument specified which like the [`MoveHere`](#intentmoveherepath) instruction can be used to move the element's location from where it was in the generated content.

The following instructions can be used to instruct the code weaver how to manage specific particular attributes on a markup element:

- **`@Intent.FullyAttributes("attribute1", ["attribute2", ...])`** - Fully manages the specified attributes.
- **`@Intent.MergeAttributes("attribute1", ["attribute2", ...])`** - Separates the value of the attribute by space and will merge them. By default `class` attributes are in merge mode.
- **`@Intent.IgnoreAttributes("attribute1", ["attribute2", ...])`** - Ignores the specified attributes.

### Management mode examples

In the below, the `class` attribute in the `<div>` will be ignored, but not the content:

```razor
@Intent.Fully()
@Intent.IgnoreAttributes("class")
<div class="content-block">
    content
</div>
```

The next example shows how management modes and their suffixes can be combined. The `<div>` will be "Fully" controlled, while its body mode is overridden to be ignored, i.e. the Razor Merger should always update the attributes to match that generated by the template, but it should never update its body ("content" in this case).

```razor
@Intent.Fully()
@Intent.IgnoreBody()
<div class="content-block">
    content
</div>
```

The following example shows how with some Razor Components, placing Razor expressions within them will cause a compilation error. In such cases the instructions can be placed in Razor comments:

```razor
@* @Intent.Fully() *@
@* @Intent.IgnoreBody() *@
<div class="content-block">
    content
</div>
```

The `@` prefix is optional for instructions inside razor comments so the following is equivalent:

```razor
@* Intent.Fully() *@
@* Intent.IgnoreBody() *@
<div class="content-block">
    content
</div>
```

### `InitialGen` instructions

These instructions are useful for having syntax which can be initially generated by a template, and then changed or even removed by users without the Software Factory trying to update or put the it back into the file.

When an `InitialGen` instruction is on a syntax node in a template, it is generated during the initial generation (creation) of a file and is then essentially treated as "Ignored" on subsequent generations. Furthermore, if the syntax node is deleted then it won't be re-generated on subsequent updates to the file.

During initial generation of a file, the instruction is removed from syntax node so this instruction will never be visible except to template authors.

The following instructions are available and are applied the same way as normal management instructions:

- **`@Intent.InitialGen()`** - All aspects of the syntax are ignored after initial generation.
- **`@Intent.InitialGenAttributes()`** - Attributes of the syntax are ignored after initial generation.
- **`@Intent.InitialGenBody()`** - The body of the syntax is ignored after initial generation.
- **`@Intent.InitialGenSignature()`** - The signature of the syntax are ignored after initial generation.

### `Intent.Skip("<path1>", ["<path2>", "<path3>", ...])`

Will skip over insertion of template content at the specified [paths](#path-syntax).

For example, you have deleted generated content and the code weaver keeps trying to bring it back:

```diff
  <PageTitle>My Page</PageTitle>
+ <h1>Page Heading</h1>
+ 
+ <div id="generated">
+   <p>Generated content</p>
+ </div>

  <div id="manually-added">
    <p>Manually added content.</p>
  </div>
```

You can add `@attribute [Intent.Skip("h1", "/div[@id='generated']")]` to the top of the file and the code weaver will then know to "skip over" insertion of items generated at those paths:

```razor
@attribute [Intent.Skip("h1", "/div[@id='generated']")]

<PageTitle>My Page</PageTitle>

<div id="manually-added">
  <p>Manually added content.</p>
</div>
```

### `Intent.MoveHere("<path>")`

Adding an `Intent.MoveHere("<path>")` instruction allows moving an element from a completely structurally different location in the generated output at the specified [path](#path-syntax).

For example, you're wanting to move the `<h1>` element in the example below to the outer scope, but the code weaver keeps trying to add it back to where it was:

```diff
  @page "/page"
  
  <h1>Heading 1</h1>
  
  <div id="main">
+   <h1>Heading 1</h1>
    <p>Generated content</p>
  </div>
```

You can add `@Intent.MoveHere("/div[@id='main']/h1")` above the `h1` element to instruct the code weaver that the element has been moved from elsewhere in the generated output:

```razor
@page "/page"

@Intent.MoveHere("/div[@id='main']/h1")
<h1>Heading 1</h1>

<div id="main">
  <p>Generated content</p>
</div>
```

### Path syntax

This section discusses the syntax for the path arguments used by [management mode](#management-modes), [Skip](#intentskippath1-path2-path3-) and [MoveHere](#intentmoveherepath) instructions.

The path supports a URL like path separated by forward-slashes (`/`), for example, `/div/div/h1` would match the `<h1>` in the following:

```razor
<div>
  <div>
    <h1>Heading 1</h1>
  </div>
</div>
```

The path syntax supports the following very small subset of [XPath](https://developer.mozilla.org/en-US/docs/Web/XML/XPath):

#### `attribute` Axis

This will match elements with attribute names prefixed with an `@` with the specified value, for example the string `/div/div[@id='additional']` will match the 2nd nested `<div>` in the following:

```razor
<div>
  <div id="main">
    Main content.
  </div>

  <div id="additional">
    Additional content.
  </div>

  <div id="footer">
    Footer content.
  </div>
</div>
```

You can also refer to the MDN documentation on the [`attribute` Axis](https://developer.mozilla.org/en-US/docs/Web/XML/XPath/Reference/Axes#attribute) for more information.

#### [`position` Function](https://developer.mozilla.org/en-US/docs/Web/XML/XPath/Reference/Functions/position)

This will match the element at the specified 1-based index position, for example the string `/div/div[position()=3]` will match the 3rd div in the following:

```razor
<div>
  <div>
    1st
  </div>

  <div>
    2nd
  </div>

  <div>
    3rd
  </div>
</div>
```

You can also refer to the MDN documentation on the [`position` Function](https://developer.mozilla.org/en-US/docs/Web/XML/XPath/Reference/Functions/position) for more information.

## Default code management behaviour

By default, templates are in `Merge` mode. This default can be changed in the [settings](https://docs.intentarchitect.com/docs-md/module-building/application-settings/application-settings.md) for your application:

![Razor Merger Settings](images/razor-merger-settings.png)

## Syntax node matching

The Razor Merger applies a heuristic to try "match" syntax nodes in your "existing" file with a corresponding syntax node generated by the template it is merging with.

### Matching by identity

There are cases where syntax nodes can't be easily differentiated and the Merger's default match may not be correct, this is particularly common with HTML Elements and Directives which appear numerous times within the same parent syntax node or root of the document. In such cases, an "identity" can be assigned to the syntax node which will force the Razor Merger to correlate the Syntax Node only with syntax nodes with a matching identity.

An "identity" can be assigned to a syntax node using any of the following ways:

- **An `id="<identity>"` HTML element attribute** - As this is a default attribute for HTML element it can be a "natural" identifier to use on elements if it's present.
- **An `intent-id="<identity>"` HTML element attribute** - This takes precedence over the `id` HTML element attribute and is useful for scenarios an HTML element's `id` is not "stable", i.e. if it's expected that the template output's `id` may change based on other factors.
- **An `@Intent.Id("<identity>")` or `@* @Intent.Id("<identity>") *@` or `@* Intent.Id("<identity>") *@` instruction above the syntax node** - This takes precedence over both of the HTML element attributes and was created with Directives in mind as trying to apply unknown attributes to them causes a compilation error.

### Matching by other attribute types

If a syntax node doesn't have an identifier, a match is performed in order by the following attributes:

- `@bind-Value`
- `@bind`
- `Value`

### Component specific attribute matching configuration

Module authors can configure matching behaviour for particular element/component tag names by using the `ConfigureRazorTagMatchingFor` extension method on any instance of `ISoftwareFactoryExecutionContext`.

> [!TIP]
>
> The `IApplication` interface and the `ExecutionContext` property on template base types are two common places which are `ISoftwareFactoryExecutionContext` and this extension method can be used.

The extension method takes an `Action<IRazorTagMatchingConfiguration>` argument which allows fluent style configuration to occur. The following methods are available:

#### AllowMatchByDescendant

The tag may be matched by a descendant at the specified path.

Consider you're trying matching MudGrid in the following existing file:

```razor
@if (Model is not null)
{
  <MudGrid>
    <MudItem>
      <MudImage id="SomeId" />
    </MudItem>
  </MudGrid>
}
```

With the one in the following generated file:

```razor
<MudGrid>
  <MudItem>
    <MudImage id="SomeId" />
  </MudItem>
</MudGrid>
```

We can specify the following in a factory extension in our module:

```csharp
protected override void OnAfterTemplateRegistrations(IApplication application)
{
    application.ConfigureRazorTagMatchingFor("MudGrid", c => c.AllowMatchByDescendant(["MudItem"]));
}
```

The Razor Weaver will then know that for a `MudGrid` that it can consider it matched with a `MudGrid` when both have at least one direct descendant under their `MudItem` with is considered a match.

#### AllowMatchByNameOnly

The tag may be matched by its name alone rather than requiring content also be matched.

```csharp
protected override void OnAfterTemplateRegistrations(IApplication application)
{
    application.ConfigureRazorTagMatchingFor("MudDialogProvider", c => c.AllowMatchByNameOnly());
}
```

#### AllowMatchByAttributes

The tag may be match by the one or more specified attribute names.

```csharp
protected override void OnAfterTemplateRegistrations(IApplication application)
{
    application.ConfigureRazorTagMatchingFor("MudDialogProvider", c => c.AddTagNameAttributeMatch("@bind-Date", "otherAttribute", ...));
}
```
