Skip to content

规则配置语法

breezet edited this page Oct 16, 2018 · 18 revisions

mip-validator采取JSON格式的配置文件,所有校验规则均来源于该文件。 本文档描述了该配置文件的语法,为规则的开发者以及MIP校验工具的其他实现提供参考。

注意:

  • 本文给出的规则样例只为阐明机制,不一定是真正的MIP规则。
  • mip-validator使用parse5作为DOM树解析工具,HTML语法错误已被容错。因而语法相关的配置无效。

规则文件的整体结构

标签规则

规则文件应为合法的JSON格式,每个根键代表一个标签名(根键不可重复)。 根键对应的值为校验规则对象,或校验规则对象数组(见下文)。 每个校验规则对象定义了当前根键所表示的标签的校验规则, 下面示例表示script标签在整个HTML中不允许出现(disallow规则见下文)。

{
    "script": {
        "disallow": true
    }
}

属性规则

标签规则对象的attrs键对应的值为该标签的属性的校验规则对象,例如:

{
    "input": {
        "attrs": {
            "name": {
                "mandatory": true
            }
        }
    }
}

指定了input标签的name属性有如下的校验规则对象

{
    "mandatory": true
}

表示input标签必须定义name属性。

标签校验规则对象数组

标签校验规则对象和属性校验规则对象都可以形成一个数组。 此时数组的每一项都会被解析为一个独立的校验规则对象。 所有这些对象都应得到校验(与的关系,即都必须通过)。下面分别给出标签和属性的示例。

{
    "script": [{
        "disallow": true  
    },{
        "mandatory": true
    }]
}

mandatory表示必须出现(见下文)。对于如上的规则,任何HTML都将无法通过校验。 因为一个规则表示script必须出现,而另一个表示script不允许出现。

属性校验规则对象数组

与标签规则类似,属性规则也可以是数组,例如:

{
    "meta": {
        "attrs":{
            "name": [{
                "mandatory": true
            },{
                "disallow": true
            }]
        }
    }
}

任何包含meta标签的HTML都无法通过上述规则的校验。 因为它要求meta标签必须有name属性,同时禁止name属性。

规则字段

这一部分定义了校验规则对象中规则字段的语义。包括其属性路径、值的类型、默认值、以及错误代号, 并给出相应的示例。

mandatory

属性:<TagName>.mandatory

类型:Boolean<Object>Array<Object>

默认:false

错误代号:"MANDATORY_TAG_MISSING"

该字段用来指定强制包含的元素:

  • 当该字段为true时,HTML必须包含该标签,为false则相当于不设置;
  • 当该字段为对象时,HTML必须包含属性匹配该对象的标签;
  • 当该字段为数组时,HTML必须包含匹配该数组每一项的标签。

例如<link rel="miphtml"><link rel="standardhtml">都必须出现可以写成:

{
    "link": {
        "mandatory": [{
            "rel": "/standardhtml/"
        }, {
            "rel": "/miphtml/"
        }]
    }
}

mandatory_or

属性:<TagName>.mandatory_or

类型:Array<Object>

默认:undefined

错误代号:"MANDATORY_TAG_MISSING"

<TagName>.mandatory,但数组元素是或的关系,例如检查charset设置:

{
    "meta": {
        "mandatory_or": [{
            "http-equiv": "/Content-Type/i",
            "content": "/charset=utf-8/"
        }, {
            "charset": "utf-8"
        }]
    }
}

其中i为不区分大小写,参考JavaScript正则表达式

mandatory_ancestor

属性:<TagName>.mandatory_ancestor

类型:String

默认:undefined

错误代号:"MANDATORY_TAG_ANCESTOR"

该字段用来指定一个标签必须拥有的祖先标签。例如<mip-input>一定要位于<mip-form>下:

{
    "mip-input": {
        "mandatory_ancestor": "mip-form"
    }
}

mandatory_parent

属性:<TagName>.mandatory_parent

类型:String

默认:undefined

错误代号:"WRONG_PARENT_TAG"

该字段用来指定强制父标签。例如:

{
    "head": {
        "mandatory_parent": "html"
    }
}

disallow

属性:<TagName>.disallow

类型:Boolean

默认:false

错误代号:"DISALLOWED_TAG"

true表示该标签不允许在HTML中出现,否则为允许出现。例如不允许<img>标签出现:

{
    "img": {
        "disallow": true
    }
}

disallowed_ancestor

属性:<TagName>.disallowed_ancestor

类型:StringArray<String>

默认:undefined

错误代号:"DISALLOWED_TAG_ANCESTOR"

该字段设置不允许出现的祖先标签,可以是单个标签名,也可以是标签名数组。 例如:

{
    "div": {
        "disallowed_ancestor": "span"
    }, 
    "form":{
        "disallowed_ancestor": ["span", "a"]
    }
}

ignore_tag

属性:<TagName>.ignore

类型:Boolean

默认:undefined

错误代号:"null"

该字段设置某个标签下所有内容可以被豁免校验 例如:

{
    "template": {
        "ignore": true
    }
}

inner_html

属性:<TagName>.inner_html

类型:String

默认:undefined

错误代号:"INVALID_INNER_HTML"

单元测试:https://github.com/mipengine/mip-validator/blob/master/test/invalid_inner_html.js

该字段设置 innerHTML 的内容规则,支持正则表达式(见下文)。例如:

{
    "div": {
        "inner_html": "foo"
    }, 
    "form":{
        "inner_html": "/^<span>[^<]*<\/span>$/"
    }
}

若需配置禁止出现的 inner_html 内容,可在正则表达式前添加!,例如:"!/position:\\s*fixed/"

duplicate

属性:<TagName>.duplicate

类型:ObjectArray<Object>

默认:undefined

错误代号:"DUPLICATE_UNIQUE_TAG"

该属性设置一个或一组模式,符合该模式的标签不可重复,属性值采用正则表达式来书写。 如果是一个模式,则完全匹配该模式的标签不可重复,如果是多个模式则分别不可重复。 例如:

{
    "meta": {
        "duplicate": {
            "viewport": "/.*/"
        }
    },
    "link": {
        "duplicate": [{
            "rel": "miphtml"
        }, {
            "rel": "standardhtml"
        }]
    }
}

attrs.value

属性:<TagName>.attrs.<AttrName>.value

类型:String

默认:""

错误代号:"INVALID_ATTR_VALUE"

该字段用来校验属性值是否合法。传入的字符串将被用来构建使用正则表达式。 例如:

{
    "mip-img": {
        "attrs": {
            "src": {
                "value": "/^http:///"
            }
        }
    }
}

attrs.properties

属性:<TagName>.attrs.<AttrName>.properties

类型:Object

默认:undefined

错误代号:"INVALID_PROPERTY_VALUE_IN_ATTR_VALUE"

该字段用来配置attribute值中的property是否拥有合法的值。 该字段生效的前提是同一对象下的<TagName>.attrs.<AttrName>.match与当前标签匹配。 例如:

{
    "meta": {
        "attrs": {
            "content": {
                "match": {
                    "name": "viewport"  
                },
                "properties": {
                    "width": "device-width",
                    "initial-scale": "1"
                }
            }
        }
    }
}

上述规则将会对所有<meta name="viewport">进行校验,验证content中的属性是否合法。 比如<meta name="viewport" content="width=device-width,initial-scale=1">是合法的。

attrs.mandatory

属性:<TagName>.attrs.<AttrName>.mandatory

类型:Boolean

默认:false

错误代号:"MANDATORY_ONEOF_ATTR_MISSING"

该字段用来指定标签的某个属性是强制包含的。例如:

{
    "mip-input": {
        "attrs": {
            "name": {
                "mandatory": true
            }
        }
    }
}

上述规则强制要求所有<mip-input>标签拥有name属性。

规则匹配字段

为了实现校验规则见『或』的关系,引入规则匹配字段。 每一个标签或属性的校验规则对象都可以包含规则匹配字段的声明。 规则匹配字段有多种:

  • 对于节点(node)而言,包括match, match_ancestor, match_parent
  • 对于属性(attribute)而言,包括match, nomatch_descendant

如需要更多规则匹配语法,请提 Issue。

match

match规则匹配字段可以用来匹配拥有特定属性(attribute)的节点(node)。 只有被匹配的标签才会应用当前的校验规则对象。 下面分别以标签和属性来给出规则匹配对象的例子。

{
    "script": [{
        "disallow": true,
        "match": {
            "type": "application/json",
            "src": "/^https:/"
        }
    },{
        "mandatory": true  
    }]
}

这样就只有属性type的值为application/json并且 属性src的值为https起始的script标签应用disallow规则。

与标签类似,属性规则对象也支持match规则匹配字段。例如:

{
    "meta": {
        "attrs": [{
            "content": [{
                "match": {
                    "name": "viewport"
                },
                "mandatory": true
            }]
        }]
    }
}

上述规则表示,只有name属性值为viewportmeta标签,必须出现content属性。

match_ancestor

match_ancestor用来匹配祖先标签名。只有匹配成功的校验规则对象才会生效。例如:

{
    "input": {
        "disallow": true,
        "match_ancestor": "form"
    }
}

这样我们就定义了一个奇怪的规则:只有在form下不允许input

match_parent

类似match_ancestormatch_parent用来匹配直接父标签名。 match_ancestormatch_parent的值都支持正则表达式(见下文)。

{
    "input": {
        "disallow": true,
        "match_parent": "form"
    }
}

上述规则表示,input不能是form的直接子节点,但可以是form下的深层节点。

nomatch_descendant

nomatch_descendant用于否定匹配后代节点。例如:

{
    "video": {
        "attrs": {
            "src": {
                "mandatory": true,
                "nomatch_descendant": "source"
            }
        }
    }
}

对于不包含source后代节点的video标签,src属性是强制的。

正则表达式与字符串

标签名、属性名、属性值、属性的属性值(property within attribute)都允许以正则表达式和字符串两种方式来规约。识别方式如下:

  • /开始并以/\w*结尾的字符串将会被解析为正则表达式,按正则来匹配。
  • 其他字符串将会被解析为字符串,要求字符串全等。

下列字符串都将被识别为正则表达式:

  • /foo/
  • /foo/g
  • /foo/ig
  • !/foo/

前三项正则表达式为ECMAScript风格,见:http://www.regular-expressions.info/javascript.html。最后一项为正则表达式增强,表示对匹配结果取非。

这里的正则完全等同于JavaScript中的正则声明,不同的一点是该字符串需要转义, 因为该字符串将以new RegExp的方式转换为正则表达式对象。

正则表达式规约标签名

标签名允许以正则表达式的方式给出,例如:

{
    "/^h/": {
        "disallow": true
    }
}

上述规则表示以h起始的标签都是不允许的,即html, header, h1等都不能通过校验。

正则表达式规约属性名

与标签类似,属性名也可以正则匹配,例如:

{
    "input": {
        "attrs": {
            "/^on.+/": {
                "disallow": true
            }
        }
    }
}

上述配置表示所有以on起始的属性都是不允许的。