# Generator Rules

All generator rules are optional and can be set at the project level, next to component HTML files, or in both places.
Generation parameters from the component-level rules override the rules defined at the project level.

Any runner or JSON generation parameter can be overridden at the source code level. See [Override generated content](/docs/platform/utam/guide/generator-override-content.md).

Runner parameters are explained in [Generation runner parameters](/docs/platform/utam/guide/generator-get-started.md#generation-runner-parameters).

The next sections explain the configuration parameters responsible for how the generator interprets HTML and affects the generated JSON.

:::warning
The supported parameters were updated in version 2.1.0. Do not use earlier versions.
:::

Each string value set in the configuration for elements can be a regular string (for a full match) or a regular expression for a partial match.

## Public basic, container, and frame elements

A public [basic element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#basic-elements), [container](/docs/platform/utam/references/utam-grammar/page-object-elements.md#container-elements) or [frame](/docs/platform/utam/references/utam-grammar/page-object-elements.md#frame-elements) is generated from an HTML tag if it has a certain tag name, a `class` attribute with a given value, a `type` attribute with a given value, or if an element has one of the listed attributes.

To ignore something that is configured to be included, use the optional `excludeElements` parameter.

Configuration parameter: **`publicElements`**

- Type: `object`
- Default:

````js
publicElements: {
        withTags: {
            input: ['actionable', 'clickable', 'editable'],
            button: ['actionable', 'clickable'],
            a: ['actionable', 'clickable'],
            area: ['actionable', 'clickable'],
            li: ['actionable', 'clickable'],
            option: ['actionable', 'clickable'],
            menuItem: ['actionable', 'clickable'],
            textarea: ['actionable', 'clickable', 'editable'],
            select: ['actionable', 'clickable', 'editable'],
            iframe: 'frame',
            td: [],
            th: [],
            title: [],
            slot: 'container',
        },
        withType: {
            button: ['actionable', 'clickable'],
            checkbox: ['actionable', 'clickable'],
            radio: ['actionable', 'clickable'],
            reset: ['actionable', 'clickable'],
            submit: ['actionable', 'clickable'],
        },
        withAttributes: {
            onclick: ['actionable', 'clickable'],
            ondblclick: ['actionable', 'clickable', 'editable'],
            onkeydown: ['actionable', 'editable'],
            onkeypress: ['actionable', 'editable'],
            onchange: ['actionable'],
        },
    }
``

For example for the following HTML:

```html
<div>
    <button type="button">Click Me!</button>
    <div onchange={handle}>test events</div>
</div>
````

The generator produces the following public elements:

```json
"elements" : [
    {
        "public": true,
        "name": "button",
        "type": ["actionable", "clickable"],
        "selector": { "css": "button" }
    },
    {
        "public": true,
        "name": "div",
        "type": ["actionable"],
        "selector": { "css": "div" }
    },
]
```

## Container element

According to default rules for public elements, a public [container element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#container-elements) is generated from a `<slot>` HTML element.

```html
<template if:false="{computedShowOutputField}">
  <span class="test-id__field-value slds-size_1-of-1">
    <slot name="inputField"></slot>
    <slot></slot>
  </span>
</template>
```

The generator produces the following public container element:

```json
{
  "public": true,
  "name": "inputField",
  "type": "container",
  "selector": { "css": "[slot='inputField']" }
}
```

Configuration parameter: **`containerSelector`**

- Type: `string`
- Default: `:scope > *:first-child`

If the slot doesn't have a `name` attribute, it's the default slot, so the generated selector depends on the `containerSelector` parameter.
The content of the slot isn't processed further because a container can't have child elements.

```json
{
  "public": true,
  "name": "slot",
  "type": "container",
  "selector": { "css": ":scope > *:first-child" }
}
```

## Frame element

According to default rules for public elements, a [frame element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#frame-elements) is generated from an `<iframe>` HTML element.

```html
<div class="frame">
  <iframe src="https://www.w3schools.com" title="W3Schools Free Online Web Tutorials"></iframe>
</div>
```

The generator produces the following public frame element:

```json
{
  "public": true,
  "name": "iframe",
  "type": "frame",
  "selector": { "css": "iframe" }
}
```

## Custom elements

A [custom element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#custom-elements) is generated from a custom HTML element. An HTML element is considered custom if its tag isn't part of the HTML5 standard and contains "-"; for example, `<custom-element>`.

```html
<template>
  <my-custom-element>Custom content</my-custom-element>
</template>
```

The generator produces the following public custom element:

```json
{
  "public": true,
  "name": "customElement",
  "type": "my-namespace/pageObjects/customElement",
  "selector": { "css": "my-custom-element" }
}
```

A generated element requires a `type`, so the generator splits a custom HTML tag by "-" and considers the first part a namespace (in our example, it's `my`). Then, the generator tries to find a proper type prefix for the given namespace looking at the following configuration parameters.

### `namespaces`

- Type: `map`
- Default: `empty or {}`

First, the generator tries to find a match in the namespaces map. Let's say our config looks like this:

```json
{
  "namespaces": {
    "my": "my-namespace/pageObjects",
    "lightning": "salesforce/lightning/pageObjects"
  }
}
```

Since the generator can find a map entry for our namespace prefix `my`, it picks the type and adds the name, so the type is `my-namespace/pageObjects/component2`.

### `defaultNamespace`

- Type: `string`
- Default: `"utam/pageObjects/"`

If the `namespaces` map is empty or doesn't have a proper entry, the generator uses the preconfigured default namespace.

If there isn't a matching namespace, a custom element's type is `utam/pageObjects/customElement`.

## Traverse content of a custom element

### `generateCustomContent`

- Type: `boolean`
- Default: `false`

When the generator processes a custom HTML tag such as `my-custom-tag`, it can be treated as a separate HTML source to generate another UTAM page object. If this parameter is set to `true` and `myComponent1.html` contains a custom HTML tag such as `<my-component2>some HTML here</my-component2>`, the generator treats the content of the custom tag as another HTML source for generation and creates a `component2.utam.json` file.

```
<inputRootDir>
├── utam-generator.config.json
├── src/
   └── modules/
      ├── component1/
         └── component1.html
         └── __utam__/
            └── component1.utam.json
            └── component2.utam.json
```

### `ignoreCustomTags`

- Type: `string array`
- Default: `[]`

For custom HTML elements with tags such as `my-custom-tag`, the default behavior is to generate a custom element and not traverse the body of the custom HTML element because it's considered a different component and a different page object.

Use `ignoreCustomTags` if you prefer to avoid a custom element and generate JSON for the body of a custom HTML element instead.

```html
<div>
  <my-generated-component>
    <button id="number"></button>
  </my-generated-component>
</div>
```

By default, the generated JSON would be:

```json
{
  "elements": [
    {
      "public": true,
      "name": "generatedComponent",
      "selector": {
        "css": "my-generated-component"
      },
      "type": "utam/pageObjects/generatedComponent"
    }
  ]
}
```

But if a configuration file includes `"ignoreCustomTags" : ["my-generated-component"]`, the HTML content in the body of `my-generated-component` is traversed and an element is generated for the button. Here's the output:

```json
{
  "elements": [
    {
      "public": true,
      "name": "generatedComponent",
      "selector": {
        "css": "my-generated-component"
      },
      "shadow": {
        "elements": [
          {
            "public": true,
            "name": "customTest",
            "type": "clickable",
            "selector": {
              "css": "button#number"
            }
          }
        ]
      }
    }
  ]
}
```

## Scope elements

Some HTML elements are used to scope other elements. When an element is configured to be a scope element, the generator creates a private element.

### `scopeElements`

- Type: `object`
- Default:

```js
scopeElements: {
        withTags: ['footer', 'form', 'header', 'label', 'section', 'table', 'tr', 'ul', 'ol', 'menu'],
        withClasses: [],
        withAttributes: ['id', 'name', 'slot'],
    },
```

Consider this HTML:

```html
<table>
  <tr>
    <td>table cell</td>
  </tr>
</table>
```

The generator produces the following JSON, creating private scope elements for `table` and `tr` as configured. `td` isn't defined as a scope element so the generator creates a public `tableCell` element.

```json
{
  "elements": [
    {
      "name": "table",
      "type": [],
      "selector": {
        "css": "table"
      },
      "elements": [
        {
          "name": "tableRow",
          "type": [],
          "selector": {
            "css": "tr"
          },
          "elements": [
            {
              "public": true,
              "name": "tableCell",
              "type": [],
              "selector": {
                "css": "td"
              }
            }
          ]
        }
      ]
    }
  ]
}
```

## Exclude elements from generated JSON

The `excludeElements` parameter is responsible for ignoring HTML elements for any type, basic, custom, or scope. It overrides `publicElements` and `scopeElements`.

### `excludeElements`

- Type: `object`
- Default:

```js
excludeElements: {
        withTags: ['meta', 'script', 'head', 'tbody'],
        withClasses: [],
        withAttributes: []
    }
```

## List elements

### `loopElements`

- Type: `object`
- Default:

```js
loopElements: {
        withAttributes: ['for:each', 'for:item', 'for:iterator'],
        withTags: [],
        withClasses: []
    }
```

If an HTML element is located inside a loop element, it's marked as a list (the generated selector has `returnAll: true`).

```html
<template for:each="{filteredTodos}" for:item="todo">
  <todo-item onupdate="{handleTodoUpdate}"></todo-item>
</template>
```

The generator produces the following public list element with `"returnAll": true`:

```json
{
  "public": true,
  "name": "items",
  "type": "utam/pageObjects/item",
  "selector": { "css": "todo-item", "returnAll": true }
}
```

In addition, the generator adds a public element with an indexed selector:

```json
{
  "public": true,
  "name": "itemByIndex",
  "type": "utam/pageObjects/item",
  "selector": {
    "css": "todo-item:nth-of-type(%d)",
    "args": [{ "name": "index", "type": "number" }]
  }
}
```

Some HTML elements with siblings that have the same HTML tag are also considered a list.

For example, repeated options in a `select` tag.

```html
<select>
  <option>one</option>
  <option>two</option>
</select>
```

The generator produces the following output:

```json
{
  "public": true,
  "name": "select",
  "type": ["actionable", "clickable", "editable"],
  "selector": { "css": "select" },
  "elements": [
    {
      "public": true,
      "name": "options",
      "type": ["actionable", "clickable"],
      "selector": { "css": "option", "returnAll": true }
    }
  ]
}
```

The content of the list elements isn't processed further because a list can't have child elements.

## Marking page object as a root

### `rootSelectors`

- Type: `string array`
- Default: `['form', 'html', 'body']`

The generated JSON can be marked as a [root](/grammar/root) if the root HTML element is one of: `<html>, <form>, <body>`. The root selector is the same as the root HTML element:

```html
<html>
  <body>
    <!-- content -->
  </body>
</html>
```

Generated JSON:

```json
{
  "root": true,
  "selector": {
    "css": "html"
  },
  "elements": []
}
```

## Traverse frame content

### `traverseFrameContent`

- Type: `boolean`
- Default: `false`

If parameter is set to true, generator will traverse content of the frame and create a separate JSON file for the content. For example for the given HTML file 'my-html' with two nested frames:

```html
<div class="content iframe-parent">
    <iframe id="outer">
        <html>
            <body>
                <custom-tag>something</custom-tag>
                <form>
                    <input>Outer frame</input>
                </form>
                <iframe id="inner">
                    <html>
                        <body>
                            <input>Inner frame</input>
                        </body>
                    </html>
                </iframe>
            </body>
        </html>
    </iframe>
</div>
```

If configuration parameter is set to `true`, the generator produces three files:

```
├── __utam__/
   └── my-html.utam.json
   └── my-html_irame.utam.json // for iframe with id="outer"
   └── my-html_irame_iframe.utam.json // for iframe with id="inner"
```
