7 Get Started Writing Custom Audit Rules

You use an Oracle JET application that you want to audit as the project for creating and testing custom audit rules. You can configure the application to run Oracle JAF and test the custom rules against the files of the target application. You can zip the application folder containing the implemented custom audit rules for use by other developers to audit their JET applications as a custom rule pack.

Set up the Custom Audit Rules Test Project

Writing custom audit rules is an iterative development process that ideally starts with an existing Oracle JET application project that you can use to test your custom audit rules against.

Before you start writing custom audit rules, choose an Oracle JET application that contains the actual files that you intend your custom rules to audit. This application will become a kind of development environment for writing and testing of the custom rules. You can then implement custom rules as JavaScript files within a folder that you add to the root of the test application. Once you configure the test application to run Oracle JAF and invoke the audit rules in your custom rules folder, you can easily iterate over the target file set of the test application in a test/debug audit cycle.

Tip:

By default, Oracle JAF audits the application files located in the src folder of the JET application. To avoid auditing the source code of your custom audit rules, create the custom rules folder at the root level of your test application.

The custom rules folder that you add to the test application will have the following contents, including the JavaScript (.js) files that implement your custom audit rules:

rule-1.js        }
rule-2.js         }  these are your custom rule files
. . .            }
rules.json           mandatory file describing the rule properties
msgid.json           optional file associating rules with message ID's

The rules.json file is a single rules definition file that you must define within the custom rules folder to describe the properties of your custom audit rules. The rules definition file can include comments and has the following structure.

/*-----------------------------------------------------------*/
/*  Test 'rulePack' definition                               */
/*-----------------------------------------------------------*/
{
  "title" :  "A descriptive title for the rule pack",
  "prefix" : "ABCD",                     <--  the prefix prepended to message ids
  "version" : "1.1.0",                   <--  the rule pack version
  "rules" : {
               "rule-1" :  {
                  // Standard rule options
                  "severity": "major",
                    // Additional optional user rule options
                      "customOpts": {
                         "maxLevel": 3
                       }
                      },
               "rule-2" :  { ... },
                . . .
            }
}

The prefix property identifies custom rules as belonging to a common rule set. At runtime, Oracle JAF will prepend the prefix you specify to the message IDs of emitted diagnostic messages. The prefix you specify helps users to identify the invoked audit rules.

Before You Begin:

  • Choose an Oracle JET application that you can use to test your custom audit rules against. This application will serve as the project where you will implement custom audit rules.

  • Install Oracle JAF from npm. For details, see Install the Oracle JET Audit Framework.

To set up the custom audit rules project:
  1. Open a Command Prompt window and run the JAF initialize command from the application root.
    ojaf --init

    When you run the command, the tooling will scaffold a default JAF configuration file named oraclejafconfig.json at the application root. You will edit this file to configure JAF to run the custom audit rules during testing.

  2. In the root of your custom audit rules project, create a folder to contain the custom rules and rule definition file. The folder name can be any name that you choose.
  3. Edit the generated oraclejafconfig.json file at the root of the application and configure the rulePacks property value to point to the custom rules folder.
    "rulePacks" : [
                    {
                      "path" : "path/to/my/customrulepack/folder",
                      "enabled" : true 
                      "status" : "all" 
                    }
                  ]

    The enabled and status properties are optional and provide the ability to easily disable a complete rule pack or to report only rules of a particular status. If omitted, the default enables and reports all rules in the rule pack.

  4. Optionally, disable audit reporting for the built-in JET rule set. Edit the generated oraclejafconfig.json file and set the builtinJetRules property value to false.
    "builtinJetRules" : false

    When you want to test only custom audit rules, the builtinJetRules property is a convenience property that obviates having to individually disable built-in JET rules to prevent them from running during your test/debug audit cycle.

  5. Create the mandatory rule definition file rules.json in the custom rules folder that you added to the JET application.
    {
      "title" :  "My Custom Audit Rules",
      "prefix" : "CUSTOM", 
      "version" : "1.0.0",
      ...
    }

    The prefix you assign will be prefixed to the audit diagnostic messages to help you identify diagnostics that result from your custom audit rules. The title and version are arbitrary and help you identify a rule pack version.

  6. In the rule definition file, add the rules property with the list of custom audit rules that you will implement in this project and any standard or user-defined property values that you want to pass in the case of configurable audit rules.
    {
      "title" :  "My Custom Audit Rules",
      "prefix" : "CUSTOM", 
      "version" : "1.0.0",
      "rules": {
        "custom-check-heading-levels-1" : {},
        "custom-check-heading-levels-2" : {},
        "custom-check-heading-levels-3": {
             "filetype": "html",
             "customOpts": {
                     "maxLevel": 4
                   }
             }
      }
    }

    The rules.json file defines the rule pack and identifies the audit rules and optionally their configurable properties that JAF will load at runtime for the registered rule pack. By convention, rule names include the rule pack prefix.

    In this sample, the rule name prefix custom helps to identify the rules as belonging to the same rule pack. The first two rules declare no runtime properties and the third rule declares a default property value that can be optionally configured by the user in the oraclejafconfig.json file of the target application. Additionally, for the list of system properties that you can optionally define for individual audit rules, see Define the Runtime Properties of Custom Audit Rules.

  7. Optionally, designate a rule that must not be disabled at runtime by setting the $required property to true.
    {
      "title" :  "My Custom Audit Rules",
      "prefix" : "CUSTOM", 
      "version" : "1.0.0",
      "rules": {
        "custom-check-heading-levels-1" : {},
        "custom-check-heading-levels-2" : {},
        "custom-check-heading-levels-3": {
             "$required": "true",
             "filetype": "html",
             "customOpts": {
                     "maxLevel": 4
                   }
             }
      }
    }

    The ruleMods configuration property (see Configure Audit Rule Runtime Properties) or, indirectly, the ruleName property can disable rules from running. You typically use the $required property for rules that perform rulepack setup or other non-audit related functions and whose execution is mandatory. It also ensures that these rules are loaded/registered before all other rules, in the order they are specified.

  8. Optionally, create a rule message ID file msgsid.json in the custom rules folder that you added to the JET application.
    {
        "custom-check-heading-levels-1" : "1234",
        "custom-check-heading-levels-2" : "1235",
        "custom-check-heading-levels-3" : "1236"
    }

    When JAF reports an issue, it includes a unique message ID of the format prefix-nnnn, where prefix is the prefix of the rule pack and nnnn is a message number defined for the rule. Alternatively, you can hardcode the message ID in your custom audit rule, as described in Define the Message ID of Custom Audit Rules.

  9. You are now ready to begin writing rules that you implement as .js files added to the custom rules folder, as described in Implement the Custom Audit Rules.

    Tip:

    To quickly scaffold a skeleton audit rule, in the current directory run the ojaf command with the --initrule command line flag.
    ojaf --initrule myRuleName

    For an introduction to audit rule JavaScript, see Understand the Structure of Custom Audit Rules.

As you implement custom audit rules, you'll want to get started testing custom audit rules in your project:

Define the Runtime Properties of Custom Audit Rules

Use the rules property of the rules.json file to declare the rules in a rule pack, including the properties of individual custom audit rules.

All custom audit rules in the rule pack must be declared in the rules property of the rules.json file. Properties that you can define include standard system properties when you want to override a default value defined by JAF. You can also include optional properties when you want to pass property values to the custom rule at runtime, but these properties must be enclosed in an additional customOpts property.

Here is a basic example of a user-defined rule definition:

"rules": { 
 "my-rule": { 
  // standard system properties 
  "$required" : "true", 
  "severity": "info", 
  "filetype": "html", 
  // optional properties 
  "customOpts": { 
    "maxLevel": 1 
    } 
 } 
}

This declaration specifies that a custom rule exists that is referred to as "my-rule" and that it is implemented in the file my-rule.js, in the same folder as the rules.json file. It includes a number of standard system properties ($required, severity, and filetype). Additionally it declares the rule-specific property maxLevel. This property is not inspected by JAF, and will be passed to the rule in a Rule context object when it is invoked. The custom rule implementation handles the passed values to achieve the desired audit result.

Some property names are reserved by JAF and cannot be re-purposed by the custom audit rule. The following JAF system properties are reserved and all properties are optional on the rule declaration. If you do not add these properties to the custom audit rule declaration, JAF will assign a default value. For example, unless you specifically define the severity property, the custom audit rule will be associated with the severity level critical.

Rule Property Description
inservice Rules are assumed to be in service, unless this property is set to false. This setting overrides the enabled property and suppresses the use of the configuration ruleMods property to attempt to enable the rule. Rules not in service do not participate in an audit. The default value is true.
enabled Enables or disables the custom audit rule. All custom rules are enabled by default.
severity Classifies the severity level of the custom audit rule. By default Oracle JAF defines a set of levels that you can assign: info, minor, major, critical (default), blocker. Use this property to specify the severity of the custom rule so that users can restrict the audit by rule severity level. For example, see Restrict Audit Rule Severity Level.
status Associates a development status with the custom audit rule. May be production (default), alpha, beta, or deprecated.
filetype

Specify the file types for which the custom audit rule will be invoked. By default the custom rule is not restricted to a file type. May be html and/or css, and/or js and/or json. For example:

"filetype : "html"

or

"filetype" : ["html", "css"]

The filetype property is ignored by custom hook rules declared for startup/closedown phases, since these are not file related. For all other audit rules, you should specify this property.

group Specify the group or groups to which the custom audit rule is assigned. Use this property to assign the custom rule to a group of any name so that users can restrict the audit by rule group. For example:

"group" : "jet-html"

or

"group" : [ "jet-html", "jet-aria"]

For example, see Audit with Specific Rules.
jetver Specifies the Oracle JET release version or versions required to invoke the custom audit rule. It the property is omitted, the custom rule will operate across all JET versions. The format supports semantic versioning, as used in programs like npm. For example:
"jetver" : ">=9.1.0"
or
"jetver" : "~9.1.0"
For more information about this property and semantic versioning, see Audit with Specific JET and ECMA Script Versions.
theme Specify a JET theme if the rule is theme dependent. The value is compared with the configuration property theme (or its default), and the rule is disabled if there is no match. Can be specified as a string or an array of theme strings. For example,
"theme": "Redwood"
or
"theme": ["Redwood", "Alta"]
amd Specifies that an audit rule cannot be used in AMD mode if the rule performs any I/O. It can be omitted in all other cases. The property is ignored if not running in AMD mode. It is recommended that you set amd : false if the rule performs any file I/O to prevent failures for future AMD usage.
$required Designates that this rule cannot be disabled by the configuration property ruleMods and, indirectly, by the ruleNames property. This is typically used for rules that perform pack set-up or other non-audit related functions. Rules marked $required are loaded/registered (in the order found in rules.json) ahead of all other rules. Specify true to make running of this rule during pack set-up mandatory. The default value is false.

The custom audit rule's properties may be overridden at runtime by users though the oraclejafconfig.json file configuration property ruleMods, as described in Configure Audit Rule Runtime Properties. Note also that a rule can be designated as one that must not be disabled at runtime by setting the $required property to true.

Define the Message ID of Custom Audit Rules

The message ID that Oracle JAF uses to report an issue can be generated by default by JAF or you can optionally define the IDs to better document custom audit rules.

When JAF reports an issue, it includes a unique message ID of the format ppp-nnnn, where ppp is the prefix of the rule pack, and nnnn is the message ID. The custom audit rule can supply the message number in a number of ways.

The message ID can be either hardcoded, or it can be obtained from some user-defined custom mechanism (for example, by using a rule pack extension), and specified in the Issue constructor.

Alternatively, you may use the optional msgid.json definition file to associate a rule name and message ID within a rule pack. The format of a msgid.json file is shown below:

{
   "rulename1" : "1234",
   "rulename2" : "1235"
   . . .
}

You can annotate a msgid.json file with // and /* */ comments.

At runtime, if no ID is specified for an Issue when it is added to the Reporter instance, JAF will attempt to resolve it by looking for a file named msgid.json within the same folder as the rule .js files and the mandatory rules.json file. In this case, JAF uses the rule name as the message lookup key to obtain the message number

If a msgid.json file is used, for flexibility, it is also possible to change the default lookup key from the rule name to a unique key that you specify in your audit rule handler by using Issue.setMsgKey().

var issue = new ruleContext.Issue(". . .") ;
. . .
issue.setMsgKey("some key value") ;
To hardcode the message ID, your custom audit rule may supply the number (for example, 1234) directly on the Issue object your audit rule handler function creates.
var issue = newruleContext.Issue("some rule message", "1234");

Your handler function may also set the message ID subsequently on an Issue object

var issue = newruleContxt.Issue("some rule message");
 . . .
issue.setMsgId("1234");

Here is an example of how to obtain the message ID through some custom mechanism. In this example, a custom rule pack extension is used.

var RPExtension     = ruleContext.rulePack.getExtension() ;  // get the rulepack's extension object
var myMsgIdAssigner = RPExtension.assignMsgId ;          // assumes the rule pack has created a routine for assigning message ID's
 
var issue = new ruleContext.Issue("some rule message", myMsgIdAssigner(ruleContext)) ;  // (myMsgIdAssigner could use ruleContext.ruleName)

Refer to Rule Issue Class Methods for a description of the Issue constructor and available methods.

Refer to Implement Custom Rules Using the Audit Lifecycle for an example of a custom rule pack extension that you might create for use in a startup hook rule.

Implement the Custom Audit Rules

A custom audit rule is a JavaScript file that you implement and that exports certain public functions.

When you implement custom audit rules in your project, you add a .js file with the same name as the rule you declare in the project's rules.json file. To illustrate how to implement audit rules, we'll describe three rules of increasing complexity that audit HTML files for excessive levels of HTML heading nesting:

  • custom-check-heading-levels-1.js

  • custom-check-heading-levels-2.js

  • custom-check-heading-levels-3.js

The rules.json file for these rules declares the CUSTOM rule pack like this:

{
  "title": "Example Custom Audits",
  "prefix": "CUSTOM",
  "version": "1.0.0",
  "rules": {
    "custom-check-heading-levels-1" : {},
    "custom-check-heading-levels-2" : {},
    "custom-check-heading-levels-3": {
	"filetype": "html",
	"customOpts": {
		"maxLevel": 4
	}
     }
  }
}

The implementation of each rule will use the same JavaScript regular expression to match and extract the numerical part of an HTML heading tag passed from the target audit files. At runtime, JAF processes the HTML files in the JET application and a rule listener that we register in the audit rule passes each HTML tag to an event handler function that our audit rules implement. We will vary the rule handler function implementation to illustrate ways it might use the results of the regular expression matching. Additionally, as the rules.json file sample shows, the third rule declaration differs since it defines a default value for the maxLevel property. The third audit rule illustrates how to make an audit rule configurable by the end-user of the JAF audit.

Version 1 - Report Heading Levels Greater Than H4

To qualify as a valid rule, a custom audit rule must export the following four methods:

/**
  * Copyright (c) 2018, 2022, Oracle and/or its affiliates.
  * Licensed under The Universal Permissive License (UPL), Version 1.0
  * as shown at https://oss.oracle.com/licenses/upl/
  */

/*--------------------------------------------------------------------------------*/
/*   JAF Rule:  'CustomHeadingLevelsAuditBasic'                                   */
/*   Purpose :                                                                    */
/*--------------------------------------------------------------------------------*/


const RULENAME = "CustomHeadingLevelsAuditBasic";
const DESCRIPTION = "This rule checks that excessive levels of header nesting have 
                     not been used on HTML pages by raising an error whenever a 
                     heading tag greater than H4 is used";
const SHORT_DESCRIPTION = "'Checks HTML files for any use of tags <h5> and above";

class Rule {
  getName() {
    return RULENAME;
  }

  getDescription() {
    return DESCRIPTION;
  }

  getShortDescription() {
    return SHORT_DESCRIPTION;
  }

  register(regContext) {
    return ({
      tag: this._doHeaderLevelAudit
    }
    )
  }
. . .
}

module.exports = Rule;

The first three methods in our custom audit rule implementation return usage information that you supply about the audit rule. This information will be passed to Oracle JAF whenever the end-user interacts with the ojaf command line interface to request additional details about the audit rule that emitted a particular diagnostic message.

The fourth method register() is the required entry point to every custom audit rule. This method is called during JAF startup, and you will use it to declare a node listener for specific types of data found during the file set audit. The method returns a context object that contains the events for the specified node listener type. Rules that you write to audit file data are called node audit rules because the register() method returns node data on the context object created by JAF from the Abstract Syntax Tree (AST) it generates on the target file.

Note:

The register() method that you implement in your rule's .js file can also declare listeners for events triggered by JAF on the different phases of the JAF audit lifecycle. This set of listener types provides you with hooks into the audit engine and any rules that you write for these hooks do not rely on file data. For more information about writing hook rules, see About Hook Rule Invocation.

In this version of the heading level audit rule, the register() method specifies the tag listener type to check all HTML tags in the audited file set. To handle events triggered by the processed tags, the rule needs to implement the audit handler function for the ruleContext object and other arguments passed into our handler function. Our implementation invokes the doHeaderLevelAudit handler function in response to the listener event. In the case of the registered tag listener, a ruleContext object and a tagElementName string get passed in as arguments to our function.

/**
  * Copyright (c) 2018, 2022, Oracle and/or its affiliates.
  * Licensed under The Universal Permissive License (UPL), Version 1.0
  * as shown at https://oss.oracle.com/licenses/upl/
  */

. . .
class Rule {

 . . .
  register(regContext) {
    return ({
      tag: this._doHeaderLevelAudit
    }
    )
  }
_doHeaderLevelAudit(ruleContext, tagElementName) {
  . . .    
   }
 }

module.exports = Rule;

In this version of the heading level audit rule, we hardcode the heading level so the rule reports a heading level that exceeds H4 in the rule diagnostic message. Then in JavaScript we define a regular expression that allows us to match and extract the numerical part of an HTML <H*> tag from the passed in tagElementName string. If a match is found, we check the number portion extracted by the regular expression to see if it is greater than the hardcoded limit of 4. Finally, our implementation needs to report the issue by creating an instance of the Issue object with a diagnostic message and an optional message ID for the audit rule. Then a Reporter instance allows us to call addIssue() to allow JAF to output the audit results.

Note:

Hardcoding a unique audit rule message ID in your audit rule handler function is one way to document your custom audit rule. The ID you define will appear in the audit output as ppp-nnnn, where ppp is the rule pack prefix and nnnn is the message ID. If your audit rule does not define a message ID and one cannot be found in the optional msgid.json file, JAF will generate the rule message ID at runtime for you. For more information, see Define the Message ID of Custom Audit Rules.


/**
  * Copyright (c) 2018, 2022, Oracle and/or its affiliates.
  * Licensed under The Universal Permissive License (UPL), Version 1.0
  * as shown at https://oss.oracle.com/licenses/upl/
  */

. . .
class Rule {

 . . .
  _doHeaderLevelAudit(ruleContext, tagElementName) {
    //Define a regular expression that will allow us to match extract the numerical part of an HTML <H*> tag 
    const matchHeader = new RegExp(/^[h](\d*)$/, 'i');
    //Check the tag being processed against the Regular Expression 
    const matches = tagElementName.match(matchHeader);

    //A not-null result means it's some kind of header tag, so now we check the number portion extracted by the 
    //regular expression to see if it is greater than the hardcoded limit of 4 in this case
    if (matches !== null) {
      const headerLevel = parseInt(matches[1]);
      if (headerLevel > 4) {
        //Report the issue
        const issue = new ruleContext.Issue("Header level 4 exceeded", "001");
        ruleContext.reporter.addIssue(issue, ruleContext, 'minor');
      }
    }
  }
}

module.exports = Rule;

Next let's modify this sample rule to improve our rule's diagnostic message.

Version 2 - Include Heading Tag Information in Report

In this sample, our revised heading level audit rule continues to register the tag listener type to trigger the doHeaderLevelAudit audit handler function. However, in this version we enhance the diagnostic message to include the heading text and heading tags. The audit handler function logic tests node data on the children.length and children.type properties of the ruleContext.node object passed to our handler. If the content is a simple header string, we assign the node ruleContext.data to the variable headerText, formatted with the heading tags in problemHeader and passed to the Issue instance that we create. Finally, the call to addIssue() to output the audit result on the Reporter object remains unchanged.

Tip:

Test your audit rules in a development tool that can invoke the Oracle JET ojaf utility, such as VS Code, to more easily visualize the runtime context object properties and their data.

/**
  * Copyright (c) 2018, 2022, Oracle and/or its affiliates.
  * Licensed under The Universal Permissive License (UPL), Version 1.0
  * as shown at https://oss.oracle.com/licenses/upl/
  */

class Rule {

  . . .
  
  _doHeaderLevelAudit(ruleContext, tagElementName) {
    //Define a regular expression that will allow us to match extract the numerical part of an HTML <H*> tag 
    const matchHeader = new RegExp(/^[h](\d*)$/, 'i');
    //Check the tag being processed against the Regular Expression 
    const matches = tagElementName.match(matchHeader);

    //A not-null result means it's some kind of header tag, so now we check the number portion extracted by the 
    //regular expression to see if it is greater than the hardcoded limit of 4 in this case
    if (matches !== null) {
      const headerLevel = parseInt(matches[1]);
      if (headerLevel > 4) {
        //In this enhanced version, before we report the issue let's get the actual 
        //tag information to add to the report
        //Only report the actual content for the simple case though otherwise use ellipsis
        let headerText = '...';
        if (ruleContext.node.children.length === 1 && ruleContext.node.children[0].type === 'text') {
          headerText = ruleContext.node.children[0].data;
        }

        const problemHeader = `<${tagElementName}>${headerText}</${tagElementName}>`;
        const issue = new ruleContext.Issue(`Header level 4 exceeded for element: ${problemHeader}`, "002");
        ruleContext.reporter.addIssue(issue, ruleContext, 'minor');
      }
    }
  }
}

module.exports = Rule;

Notice also that our custom audit rules pass in a severity level as an argument to addIssue(). If you do not hardcode the severity level or define the severity system property in the rule declaration in your project's rules.json file, then JAF will assign the custom audit rule the default severity level critical. In our samples, we hardcode the severity level minor for all three custom audit rules. For details about severity and other system properties that your custom audit rules can define, see Define the Runtime Properties of Custom Audit Rules.

Next let's modify this sample rule to illustrate a configurable audit rule that will allow end-users to configure the audit heading level before they run the audit.

Version 3 - Configure the Audit Rule for a Heading Level

Every rule pack must contain a rules.json file with the list of audit rules that Oracle JAF loads at audit startup. If the rule is configurable, then the rules.json file specifies the property on the declaration line like this maxlevel property we declare in this final version of our heading level audit rule that checks against a configurable heading level.

{
    "title": "My Custom Audit Rules",
    "prefix": "CUSTOM",
    "version": "1.0.0",
    "rules": {
        "custom-check-heading-levels-3": {
            "customOpts": {
                "maxLevel": 4
            }
        }
    }
}

To use the configurable property maxLevel, our audit rule sample calls getRuleOption() to query rule pack information on the Register context object passed in when the rule pack is loaded at startup. We assign the value to configuredLevel and the audit handler function tests the value using the same logic described for the previous version of the rule. If the node data for the heading tag exceeds the configured level, then we report the issue and output the message for the offending heading tag together with the configuredLevel value.


/**
  * Copyright (c) 2018, 2022, Oracle and/or its affiliates.
  * Licensed under The Universal Permissive License (UPL), Version 1.0
  * as shown at https://oss.oracle.com/licenses/upl/
  */

. . .
class Rule {

. . .

_doHeaderLevelAudit(ruleContext, tagElementName) {

    //Before we start, in this version, find out what the configured max level is from 
    //the rules.json declaration for our custom rule
    const configuredLevel = ruleContext.rulePack.getRuleCustomOptions().maxLevel;

    //Define a regular expression that will allow us to match extract the numerical part of an HTML <H*> tag 
    const matchHeader = new RegExp(/^[h](\d*)$/, 'i');
    //Check the tag being processed against the Regular Expression 
    const matches = tagElementName.match(matchHeader);

    //A not-null result means it's some kind of header tag, so now we check the number portion extracted by the 
    //regular expression to see if it is greater than the hardcoded limit of 4 in this case
    if (matches !== null) {
      const headerLevel = parseInt(matches[1]);
      //This time we check against the configured level passed in with the options
      if (headerLevel > configuredLevel) {
        //In this enhanced version, before we report the issue let's get the actual tag information to add to the report
        //Only report the actual content for the simple case though otherwise use ellipsis
        let headerText = '...';
        if (ruleContext.node.children.length === 1 && ruleContext.node.children[0].type === 'text') {
          headerText = ruleContext.node.children[0].data;
        }

        const problemHeader = `<${tagElementName}>${headerText}</${tagElementName}>`;
        const issue = new ruleContext.Issue(`Header level ${configuredLevel} exceeded for element: ${problemHeader}`, "003");
        ruleContext.reporter.addIssue(issue, ruleContext, 'minor');
      }
    }
  }
}

module.exports = Rule;

This concludes our walkthrough of a basic node rule. As an exercise, you may reuse the sample code of the three heading level audit rules to create a custom rule pack to audit the HTML source files of your JET application. The rule pack you create will contain a .js implementation file for each audit rule and a rules.json file to declare the rules. In each implementation file, be sure to include the required methods shown in the sample described for rule version 1 that for brevity the samples omit in rule versions 2 and 3. For more information about creating a custom rule pack that you can reference in an Oracle JAF audit, see Reference the Custom Audit Rules in an Audit.

Note:

End users register your custom rule pack by editing the oraclejafconfig.json file in their JET application to define the rulePacks property. They can also define the ruleMods property to override default values declared within your custom rule pack rule definitions. For details about how end users enable custom rule packs to audit their JET application, see Audit with Custom Rule Packs, and for details about how end users may override properties of configurable audit rules in their audit runs, see Configure Audit Rule Runtime Properties.

Reference the Custom Audit Rules in an Audit

Use the rulePacks property of the oraclejafconfig.json file to register the custom audit rules in your project to be loaded by JAF at audit runtime.

An audit rule is a JavaScript file that exports certain public functions. Rules with a common diagnostic purpose, for example, specific to a group of user-defined Web Components, can be placed in a folder and that folder's location referenced in the configuration file. A group of associated rules is referred to in JAF as a rule pack. A rule pack may also be zipped for distribution to other users. The Oracle JAF configuration file will reference the location of the zip file in this case.

The zip file or folder should have the contents as described in Set up the Custom Audit Rules Test Project.

To declare the rule pack, edit the generated oraclejafconfig.json file rulePacks property to specify the path to the custom rule pack folder or zip file.

"rulePacks" : [
                {
                  "path" : "path/to/myrulepack.zip",
                  "enabled" : [true (default) | false]
                  "status" : ["all" (default), "production", "deprecated", "beta", "alpha"] 
                },
                {
                  "path" : "path/to/my/rulepack/folder",
                  "enabled" : [true (default) | false]
                  "status" : ["all" (default), "production", "deprecated", "beta", "alpha"] 
                },
                ...
              ]

The enabled property is optional and provides the ability to easily disable a complete rule pack. If omitted, the default is enabled.

The specified path can be relative. If relative, it is considered to be relative to the location of the configuration file, or the configuration file's base property, if defined.