Generator User Guide
This document explains how to configure the UTAM generator and generate UTAM JSON page objects from HTML files.
Runner setup
Project Dependencies
The package.json
file configures the dependencies for a JavaScript project.
Add a development dependency for the UTAM generator by running one of these commands:
yarn add utam --dev
npm install utam --save-dev
These commands are equivalent and add utam
to the devDependencies
property in package.json
, where x.y.z
represents the installed version and is the latest version by default.
{
"devDependencies": {
"utam": "x.y.z"
}
}
Set Up Generate Step in package.json
The package.json
file has a script that runs the utam-generate
generation CLI command. utam
is installed locally in your project because you added it to the devDependencies
in package.json
.
{
"scripts": {
"build": "yarn generate:utam",
"generate:utam": "utam-generate -c utam-generator.config.json"
},
"devDependencies": {
"utam": "x.y.z"
}
}
Use a generator configuration file
You can specify options in the generator configuration file.
Use the -c
flag of the utam-generate
CLI to point at the configuration file. In this example, we use utam-generator.config.json
.
utam-generate -c utam-generator.config.json
Use the -p
flag of the utam-generate
CLI to point the generator at multiple configuration files. This approach is useful if you have a repo where you need different configuration options in different subprojects. In most scenarios, the -c
flag suffices and you don't need to use the -p
flag.
utam-generate -p 'path/to/project1/utam.config.json' 'path/to/project2/utam.config.json'
Note: Pass a list of whitespace-separated utam compiler configuration file paths.
The generator configuration options are explained in the next section.
Generator configuration
You don't have to explicitly declare any options for the generator because all options have default values. If your project structure follows the default convention, the compiler works out of the box. In that case, set the generator configuration file to be an empty object, {}.
This section lists all the options supported by the generator runner. For each option, we describe its JSON type, its default value, and what it does.
There are other configuration parameters responsible for how the generator interprets HTML. Those parameters are explained in the Generator rules section.
{
"inputRootDir" : "./", // config file directory name
"ignore": ["**/node_modules/**"],
"inputFileMask" : ["**/*.html"],
"outputDir" : "__utam__",
"outputFileExtension" : ".utam.json",
"overrideExisting" : true,
"relativeOutputDir" : false,
"rulesFileMask": "**/*.rules.json"
}
inputRootDir
- Type:
string
- Default:
path.dirname(configFilePath)
The relative path from the configuration file's directory that represents the root directory path. The generator looks recursively in the root directory for HTML files.
Defaults to the configuration file's directory if not specified. For instance, if your utam-generator.config.json
configuration file is at the package root (the same level as the package.json
file), the page object root directory defaults to the package root directory.
ignore
- Type:
string[]
- Default:
["**/node_modules/**"]
You can specify which folders and files should be ignored and not traversed by the generator.
Defaults to ignore only **/node_modules/**
.
inputFileMask
- Type:
string[]
- Default:
["**/*.html"]
The file mask pattern used by the generator to find HTML input files. It tells the generator
where to start scanning for the source files relative to inputRootDir
. Declare the file mask as a list of glob patterns.
outputDir
- Type:
string
- Default:
"__utam__"
The relative path from the inputRootDir
directory to the target directory for generated UTAM JSON files. The generator writes the JSON page objects to this directory.
<inputRootDir>
├── utam-generator.config.json
├── __utam__
├── component1.utam.json
├── src/
└── modules/
├── component1/
└── component1.html
relativeOutputDir
- Type:
string
- Default:
""
If set to a non-empty string, the output is generated under the same folder as the source file. The path is relative to the source folder. For example, if it's set to __utam__
, here's where the output is generated:
<inputRootDir>
├── utam-generator.config.json
├── src/
└── modules/
├── component1/
└── component1.html
└── __utam__/
└── component1.utam.json
outputFileExtension
- Type:
string
- Default:
".utam.json"
The generated output file has the same name as the source file with .html
removed and with the outputFileExtension
added as a suffix. For example, a myComponent.html
source file generates myComponent.utam.json
.
overrideExisting
- Type:
boolean
- Default:
true
If set to true, the generator overrides an existing file with the same name.
By default if myComponent.utam.json
already exists, it is overridden.
rulesFileMask
- Type:
string
- Default:
"**/*.rules.json"
File mask for individual generation rules.
Generation rules
This section lists all the configuration parameters responsible for how the generator interprets HTML and affects the generated JSON.
The parameters are optional and can be set in the generator configuration file.
Starting with version 1.3.x, you can set individual generation rules per HTML file. If the generator finds a rules file in the same directory as an HTML source file whose name matches the pattern in therulesFileMask
option, the generation parameters from the rules file override the default rules and rules defined in a generator configuration file.
<inputRootDir>
├── src/
└── modules/
├── component1/
└── component1.html
└── component1.rules.json
Rules for Namespaces
When the generator processes a custom HTML tag such as:
<my-component2>some HTML here</my-component2>
It generates a custom element that requires type
to be set to something like my-namespace/pageObjects/component2
.
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:
{
"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.
For our example, a custom element's type is then utam/pageObjects/component2
.
Rules for Basic Еlements
When the generator parses HTML, it only creates a JSON element if the HTML element has a preconfigured tag name, attribute, or class value. It's defined by the following parameters.
includeTags
- Type:
string array
- Default:
[ 'a', 'body', 'button', 'footer', 'form', 'header', 'iframe', 'input', 'label', 'li', 'menu', 'menuItem', 'ol', 'ul', 'option', 'section', 'select', 'slot', 'table', 'td', 'textarea', 'th', 'tr', 'title', ]
The values in this array determine which tags are processed and added to JSON. Other HTML elements are ignored except for elements that match includeAttributes
or includeClasses
.
When this parameter is set in the config, the value is added to the default list. The value doesn't override the default list.
For example if a configuration file has "includeTags" : ["div", "span"]
, it means that the div
and span
tags are processed in addition to the default tag list.
Note: Custom HTML tags, such as
my-custom-tag
, included in this option are ignored because they have different processing rules.
includeAttributes
- Type:
string array
- Default:
['id', 'data-aura-class', 'data-element-id', 'name', 'slot']
If an HTML element with any tag name has an attribute defined in this array, the element is processed and added to JSON.
For example, if a configuration file has "includeAttributes" : ["my-data"]
, the following element is no longer ignored even though <p>
isn't part of the includeTags
.
<p my-data="something">
<!-- content -->
</p>
When this parameter is set in the config, the value is added to the default list. The value doesn't override the default list.
includeClasses
- Type:
string array
- Default:
[]
If an HTML element's class has a partial match for one of the values in the array, the element is processed and added to JSON.
For example, if a configuration file has "includeClasses" : ["forceLookup"]
, the following element is no longer ignored even though <p>
isn't part of the includeTags
and doesn't have attributes from includeAttributes
.
<p class="forceLookup something else">
<!-- content -->
</p>
Rules for Custom Еlements
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.
<div>
<my-generated-component>
<button id='number'></button>
</my-generated-component>
</div>
By default, the generated JSON would be:
{
"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:
{
"elements": [
{
"public": true,
"name": "generatedComponent",
"selector": {
"css": "my-generated-component"
},
"shadow": {
"elements": [
{
"public": true,
"name": "customTest",
"type": "clickable",
"selector": {
"css": "button#number"
}
}
]
}
}
]
}
Rules for Elements and Methods names
The generated elements and methods are named based on the HTML tags and don't reflect the business function. The following configuration parameters enable you to rename elements and methods by configuring key-value pairs where the key is the automatically generated name and the value is the replacement value for the generator.
elementNames
- Type:
key-value pairs
- Default: undefined
methodNames
- Type:
key-value pairs
- Default: undefined
Here's an example of rules:
{
"elementNames": {
"span": "activateInlineEdit"
},
"methodNames": {
"getSpanText": "getRecordFieldLabel"
}
}
These rules produce the following names in the generated JSON:
{
"elements": [
{
// instead of "name" : "span"
"name": "activateInlineEdit"
}
],
"methods" : [
{
// instead of "name" : "getSpanText"
"name" : "getRecordFieldLabel",
"compose" : []
}
]
}
Rules for Root Description
Each generated JSON begins with a description
object that includes the author
and text
properties set from the values in the config.
descriptionAuthor
- Type:
string
- Default:
UTAM Generator
rootDescription
- Type:
string
- Default: undefined
If descriptionAuthor
is set to "my team" and rootDescription
is set to "my custom root description", this is the generated JSON:
{
"description": {
"author": "my team",
"text": ["Page Object: <name of page object>", "my custom root description"]
}
}
Rules for Methods Description
addMethodDescription
- Type:
boolean
- Default:
true
If set to true
, a generated compose method has the default description with the method name:
{
"methods": [
{
"description": {
"text": ["method getOptionByIndexText"]
},
"name": "getOptionByIndexText",
"compose": []
}
]
}
methodDescriptions
- Type:
key-value pairs
- Default: undefined
To make method descriptions more meaningful, you can configure a map where the key is the generated name and the value is the replacement description to put in the generated JSON. Here's an example configuration:
{
"methodDescriptions": {
"getFieldLabelText": "get text for record field label"
}
}
This configuration results in the following JSON:
{
"methods": [
{
"description": {
"text": ["get text for record field label"]
},
"name": "getFieldLabelText",
"compose": []
}
]
}
Rules for Elements Selectors
createScopeElement
- Type:
boolean
- Default:
true
This parameter affects chaining selectors versus using scope elements. Let's take the following HTML:
<table>
<tr>
<td>first</td>
<td>second</td>
</tr>
</table>
If the createScopeElement
parameter is set to true, the generator creates a table
scope element:
{
"elements": [
{
"name": "table",
"type": [],
"selector": {
"css": "table"
},
"elements": [
{
"public": true,
"name": "tableRows",
"type": [],
"selector": { "css": "tr", "returnAll": true }
}
]
}
]
}
If the parameter is set to false, the generator uses a chain selector table > tr
:
{
"elements": [
{
"public": true,
"name": "tableRows",
"type": [],
"selector": {
"css": "table > tr"
}
}
]
}
elementSelectors
- Type:
key-value pairs
- Default: undefined
The generator can replace the generated selector for a given element based on the configuration. The key in this rule is an element name, and the value is a replacement selector to use.
Here's an example configuration:
{
"elementSelectors": {
"elementName": ".computedLabel"
}
}
This configuration produces the following JSON:
{
"elements": [
{
"name": "elementName",
"selector": {
// instead of the automatically generated "div > span"
"css": ".computedLabel"
}
}
]
}
Rules for Root Selector
rootSelectors
- Type:
string array
- Default:
['form', 'html', 'body']
If the root tag of the HTML file is the same as one of the strings configured in rootSelectors
, the JSON page object is marked as a root element. For example:
<html>
<!-- content -->
</html>
The generated JSON contains "root": true
.
{
"root": true,
"selector": {
"css": "html"
}
}
rootSelector
- Type:
string
- Default:
undefined
This rule only makes sense for an individual HTML file. If the value is set, the generated page object will be marked as root and given the configured selector.
Here's an example configuration:
{
"rootSelector" : "my-root"
}
This configuration produces the following JSON:
{
"root": true,
"selector": {
"css": "my-root"
}
}
Rule for Container Selector
containerSelector
- Type:
string
- Default:
slot > *
This parameter defines the CSS selector that's used for a container element generated from a default slot <slot></slot>
.
{
"public": true,
"name": "rootContainer",
"type": "container",
"selector": { "css": "slot > *" }
}