Skip to content
chris edited this page Aug 31, 2016 · 35 revisions

常见错误修复

JavaScript

JS RULE000 syntax error。

语法错误的原因很多,这里只说最常见的作为 FISwidget 的写法导致的语法错误。

var mod = function () {
    // 这里是模块主要代码
}

return mod;

语法错误的原因是在 function 之外使用 return 语句,这是 FIS 1.x 的写法, FIS 2.x 之后的写法见下面的修正代码。

FIS 1.xwidget 这里之所以可以这样写,是因为 FIS 在构建后会自动 wrap 一个 function

同时兼容 FIS,又不会产生语法错误的写法是:

// 主要代码同上

// return mod; 这里可以改成如下:
// exports = mod;

// 不过更推荐这种兼容 `commonjs` 的写法:
module.exports = mod;

JS RULE003 [强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。

这个问题通常发生在使用 tab 作为缩进,还有部分是由于前面出现的代码中有不恰当的换行或缩进影响的,具体需要使用 fecs 直接检查查看详细的错误信息。

比较容易发现的,是数组内的元素或函数的参数间换行,当内部需要换行时(比如超过 120 字符或排版美观需要),括号内侧也必须换行--左括号之后换行,右括号之前换行。第一个换行的缩进,需要比左括号所在行多一个缩进,右括号所在行的缩进则与左括号所在行的保持一致。

一个特殊的 case 是使用数组作 HTML 字符拼接时,除满足上面所述的缩进外,其它元素间的最多可以差一个缩进(在兄弟节点时可以相等,子节点时增加一个,父节点结束标记减少一个)。如果数组未被识别为 HTML 字符拼接,可以通过增加注释来标识:

// html
var html = [
    objectType,
    functionExpressionType,
    ...
];

JS RULE007 [强制] if / else / for / while / function / switch / do / try / catch / finally 关键字后,必须有一个空格。

文字描述已经很清楚,但很多 RD 同学碰到时可能不明白怎么修改,其实只需在以上关键字后加一个空格即可。

JS RULE008 [强制] 在对象创建时,属性中的 : 之后必须有空格,: 之前不允许有空格。

对象创建是指直接使用 {} 创建的对象直接量,一般情况下,在 : 前是不允许有空格而在它之后是必须有空格的。特殊情况是当使用 : 作对象字段的对齐排版时,允许 : 前有空格。如果提示某些属性名后、: 前缺少空格,是由于当前对象的属性大部分相对于 : 对齐了。

JS RULE015 [强制] 每行不得超过 120 个字符。

除了很长的正则和 URL,这个只能通过添加适当的换行和缩进排版来修复。

  • 对于参数超长的,必须在 ( 后和 ) 前换行,) 的缩进跟 ( 所在行对齐:
// bad
var longFunctionNameHereForTest = function (firstParamForTest, secondParamForTest, thirdParamForTest, fourthParamForTest, fifthParamForTest, sixthParamForTest) {
};

// bad
var longFunctionNameHereForTest = function (
                                            firstParamForTest, secondParamForTest, thirdParamForTest, fourthParamForTest, fifthParamForTest, sixthParamForTest) {
};


// good
var longFunctionNameHereForTest = function (
    firstParamForTest, secondParamForTest, thirdParamForTest,
    fourthParamForTest, fifthParamForTest, sixthParamForTest
) {
};

// good
var longFunctionNameHereForTest = function (
    firstParamForTest,
    secondParamForTest,
    thirdParamForTest,
    fourthParamForTest,
    fifthParamForTest,
    sixthParamForTest,
    seventhParamForTest
) {
};
  • 数组项导致的超长也是同样的处理方式。

  • 对于 HTML 字符拼接导致超长的,可参考 HTML 标签嵌套方式对齐:

// bad
var html = '<div class="class-for-block"><ul class="class-for-ul"><li><a href="http://www.domain.com/path/to/page/one/"></a></li><li><a href="http://www.domain.com/path/to/page/two/"></a></li></ul></div>';


// bad (jsx)
var html = <div className="class-for-block"><ul className="class-for-ul"><li><a href="http://www.domain.com/path/to/page/one/"></a></li><li><a href="http://www.domain.com/path/to/page/two/"></a></li></ul></div>;


// good
var html = ''
    + '<div class="class-for-block">'
    +   '<ul class="class-for-ul">'
    +       '<li><a href="http://www.domain.com/path/to/page/one/"></a></li>'
    +       '<li><a href="http://www.domain.com/path/to/page/two/"></a></li>'
    +   '</ul>'
    + '</div>';

// good
var html = ''
    + '<div class="class-for-block">'
    +   '<ul class="class-for-ul">'
    +       '<li>'
    +           '<a href="http://www.domain.com/path/to/page/one/"></a>'
    +       '</li>'
    +       '<li>'
    +           '<a href="http://www.domain.com/path/to/page/two/"></a>'
    +       '</li>'
    +   '</ul>'
    + '</div>';


// good (jsx)
var html = (
    <div className="class-for-block">
        <ul className="class-for-ul">
            <li><a href="http://www.domain.com/path/to/page/one/"></a></li>
            <li><a href="http://www.domain.com/path/to/page/two/"></a></li>
        </ul>
    </div>
);

// good (jsx)
var html = (
    <div className="class-for-block">
        <ul className="class-for-ul">
            <li>
                <a href="http://www.domain.com/path/to/page/one/"></a>
            </li>
            <li>
                <a href="http://www.domain.com/path/to/page/two/"></a>
            </li>
        </ul>
    </div>
);
  • 对于超长的正则和 URL 导致的问题,可以通过注释来屏蔽:
/* eslint-disable max-len */
// 这里是超长的正则或 URL
/* eslint-enable max-len */

JS RULE016 [强制] 运算符处换行时,运算符必须在新行的行首。

例如:

if (thisIsALongExpressionForCodeDemoView &&
    thisAnotherLogExpression
)

需要改为

if (thisIsALongExpressionForCodeDemoView
    && thisAnotherLogExpression
)

JS RULE024 [强制] IIFE 必须在函数表达式外添加 (,非 IIFE 不得在函数表达式外添加 (

IIFE 是指马上执行的函数表达式:

var task = function () {
    // Code
    return result;
}();

var func = (function () {
});

+function () {
    // blablabla
}();

必须改成:

// good
var task = (function () {
   // Code
   return result;
})();

var func = function () {
};

(function () {
    // blablabla
})();

JS RULE025 [强制] 变量 使用 Camel命名法

使用其他语言的同学,可能习惯使用下划线作为命名中单词的分隔符:

var foo_bar = true;

这里需要改成:

var fooBar = true;

JS RULE029 [强制] 使用 Pascal命名法

换言之,使用类的构建函数名,必须是大写字母开头。当调用了大写字母开头的函数或方法,但没有使用 new 操作符时,也是不允许的,即便结果正确。 如果是因为使用了第三方的代码,如果加 new 不影响结果的正确性,可以参见 FAQ 中的 《如何修复使用 jQueryDataTable 插件的问题?》,否则需要使用以下方式屏蔽该条规则:

/* eslint-disable new-cap */

JS RULE030 [强制] 类的 方法 / 属性 使用 Camel命名法

  • 部分情况同 《JS RULE029 [强制] 使用 Pascal命名法》。

  • 如果方法属性命名是受 RD 接口影响,需要使用以下方式处理:

/* eslint-disable fecs-camelcase */
// 这里是你的代码
/* eslint-enable fecs-camelcase */
  • 如果有固定的模式,比如都以 api_ 开头,可以这样配置:
/* eslint fecs-camelcase: [2, {ignore: ["/^api_/"]}] */
ajax.send({
    api_site: 'baidu',
    api_key: 'djk13-liwfu-bstdj'
});

其中 ignore 的取值是字符串数组,字符串以 / 开始和结束时,将按正则字符匹配处理。

  • 如果习惯使用 _ 前缀标识私有属性或方法,则需要增加 @private 来避免检查:
/**
 * 类描述
 *
 * @class
 * @extends Developer
 */
var Fronteer = function () {
    Developer.call(this);

    /**
     * 属性描述
     *
     * @type {string}
     * @private
     */
    this._level = 'T12';

    // constructor body
};
util.inherits(Fronteer, Developer);

/**
 * 方法描述
 *
 * @private
 * @return {string} 返回值描述
 */
Fronteer.prototype._getLevel = function () {
};

JS RULE031 [强制] 枚举变量 使用 Pascal命名法枚举的属性 使用 全部字母大写,单词间下划线分隔 的命名方式。

当变量名符合 Pascal 命名法,并且值类型为对象字面量时,会要求对象的所有属性名全部字母大写,即使用常量的命名方式。

所以修改方式有两种,一是按规范要求把属性名按常量的命名方式修改(全部字母大写,单词间下划线分隔 ),二是调整变量名,比如首字母恢复小写。

JS RULE044 [强制] 对于基本类型 {string}, {number}, {boolean},首字母必须小写。

意思是除了 String/Number/Boolean 类型的首字母小写,其它类型都大写,如:{Array},{Date},{Function},{Object},{RegExp}。

JS RULE045 [强制] 文件顶部必须包含文件注释,用 @file 标识文件说明。

在文件开始,必须使用 @file 对当前文件作注释(注意文档注释开始行是两个星号 /** ):

/**
 * @file 介绍当前文件的说明
 * @author name<email>
 */

JS RULE052 [强制] 函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。

这种情况通常是漏了某些参数或返回值的注释,可以通过本地运行 fecs 看具体的信息。 对于 Object 类型的参数(比如写配置项时,假设叫 options),想对参数对象的各个字段作注释时,首先不能漏了参数名(options)的注释,然后对于各个字段注释,需要带上 options. 作前缀:

/**
 * 初始化
 *
 * @param {Object} options 配置项
 * @param {boolean} options.disabled 控件的不可用状态
 * @param {(string | HTMLElement)} options.main 控件渲染容器
 * @param {(string | HTMLElement)} options.target 计算弹出层相对位置的目标对象
 * @param {string} options.prefix 控件class前缀,同时将作为main的class之一
 * @param {number} options.index 默认激活的标签索引
 */

JS RULE053 [强制] 参数和返回值注释必须包含类型信息和说明。

错误的注释:

/**
 * blablabla
 *
 * @param foo
 * @param bar
 */

需要加上参数类型和说明

/**
 * blablabla
 *
 * @param {number} foo 这是 foo 的说明
 * @param {boolean} bar 这是 bar 的说明
 */

JS RULE070 [强制] 变量在使用前必须通过 var 定义。

有三种情况会导致出现该错误。

(一)、使用了非当前文件内定义的全局变量或函数,或者是定义时漏写 var 的变量。

  • 使用了 AMD 的项目,应该通过配置 shim 来把非 AMD 模块伪装成 AMD 模块 require。

  • 未使用 AMD 的项目,作为临时解决方案,需要把该变量或函数标识为 globals:

/* globals foo */

(二)、错误的写法导致出现的全局变量 bar:

var foo = bar = true;

正确写法应该是:

var foo = true;
var bar = foo;

(三)、在代码中,定义的代码在被使用的代码之后(使用变量或函数时,还没出现定义的代码):

function foo() {
    bar();
}

var bar = function () {
    console.log(baz);
};

var baz = true;

注意:如果 bar 是函数声明则不会报错。

JS RULE071 [强制] 每个 var 只能声明一个变量。

var foo = true,
    bar = false;

需要改为:

var foo = true;
var bar = false;

JS RULE072 [强制] 变量必须 即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量。

var foo = function () {
    bar();
};

var bar = function () {
    // blablabla
};

这种代码的报错主要是因为 bar 的调用在定义之前所致。解决的办法很简单,把 bar 的定义提前:

var bar = function () {
    // blablabla
};

var foo = function () {
    bar();
};

也可以把 bar 改成函数声明:

var foo = function () {
    bar();
};

function bar() {
    // blablabla
}

JS RULE073 [强制] 在 Equality Expression 中使用类型严格的 ===。仅当判断 null 或 undefined 时,允许使用 == null

当判断 foo 为 null 或 undefined 时,使用 foo == null,不是 foo == undefined

JS RULE086 [强制] 使用 parseInt 时,必须指定进制。

其实就是为 parseInt 指定第二个参数:

// bad
parseInt(str);

// good
parseInt(str, 10);

主要是防止低级浏览器中的 0 开头的字符默认识别为 8 进制问题:

parseInt('010'); // 8
parseInt('010', 10); // 10

JS RULE089 [强制] 字符串开头和结束使用单引号 '

单引号输入时可以少按一个 Shift 键,而在拼写 HTML 字符串时,还可以保留 HTML 属性中的双引号,避免使用 \ 转义嵌套的双引号。

var foo = 'bar';

JS RULE094 [建议] 对象创建时,如果一个对象的所有 属性 均可以不添加引号,则所有 属性 不得添加引号。

JS RULE095 [建议] 对象创建时,如果任何一个 属性 需要添加引号,则所有 属性 必须添加 '

这两个问题通常和《JS RULE030 [强制] 类的 方法 / 属性 使用 Camel命名法》相关。

当属性中使用下划线时,不需要添加双引号,但是此时会报 030 的问题。正确的做法是除非有某一属性名出现关键字或非字母数字和 $_ 之外字符时,可以全部添加引号,否则不允许使用引号。

// 不允许添加引号
var foo = {
    'bar': true,
    'baz': false
};
// 必须全部添加引号
var foo = {
    'bar': true,
    'foo-baz': false
};

JS RULE998 [强制] 存在兼容性问题或运行时错误。(%s)

从 Cooder 或 eagle 报的描述中,%s 没有替换为具体的错误信息,所以需要本地运行 fecs 来获取详细的信息再作修改。

JS RULE999 [强制] 语法错误。(%s)

和 RULE998 问题一样,需要本地运行 fecs 来获取详细的信息再作修改。

HTML

HTML RULE012 [强制] 对 HTML5 中规定允许省略的闭合标签,不允许省略闭合标签。

该错误源于对未闭合的标签的检查,示例如下:

<!-- good -->
<ul>
    <li>first</li>
    <li>second</li>
</ul>

<!-- bad -->
<ul>
    <li>first
    <li>second
</ul>

不过大多数时候,报告该错误都是因为文件内容并非单纯 HTML 代码,而是某种模板,模板语法破坏了HTML本身的结构,导致一些 HTML 标签被认为没有正确闭合。对于模板文件,建议的做法是修改文件后缀名为 .tpl.tmpl,避免 HTML 规范检查。如果因为某些原因需要使用 .html 后缀名,可以使用 .tpl.html,也可以避免检查。

HTML RULE033 [强制] title 必须作为 head 的直接子元素,并紧随 charset 声明之后。

HTML RULE024 [强制] 页面必须使用精简形式,明确指定字符编码。指定字符编码的 meta 必须是 head 的第一个直接子元素。

这两条字面上很好理解,要求 head 中第一个子元素为指定字符编码的 meta 标签,紧随其后是 title 标签。 常见的不规范情况包括:

  • meta标签未使用精简形式

    精简形式:

    <meta charset="UTF-8">

    非精简形式(不符规范):

    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  • metatitle 标签位置不正确,规范明确要求了 meta 作为 head 的第一个直接子元素,且 title 紧随其后

这两条字面上很好理解,要求 head 中第一个子元素为指定字符编码的 meta 标签,紧随其后是 title 标签。 常见的不规范情况包括:

  • meta标签未使用精简形式

    精简形式:

    <meta charset="UTF-8">

    非精简形式(不符规范):

    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  • metatitle 标签位置不正确,规范明确要求了 meta 作为 head 的第一个直接子元素,且 title 紧随其后

HTML998 [强制] 存在兼容性问题或运行时错误(%s)。

这条 rule 包含两种情况,attr-unsafe-charsid-class-ad-disabled,因为系统尚未展示错误报告的详细信息,所以这两者目前无法根据错误信息区分。

  • 前者不允许在元素属性值中使用不安全字符,具体为/[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/

  • 后者不允许在 idclass 的值中使用 adad 通过-_与其他字符分隔开,形如:ad-, xx-ad-xx, xx-ad, ad_, xx_ad_xx, xx_ad),否则很大可能会被广告插件过滤。

HTML003 [强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。(Bad indentation (4 instead 0).)

目前的 cooder 会把对内联的 script/style 内容的检查认为是 html 检查结果,所以有时会出现类似

HTML003 [强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。(Bad indentation (4 instead 0).)

这样的结果。这里的问题实则是内联的 script 内容的缩进错误。

内联的 script/style 内容的缩进要求在标签本身(<script>/<style>)基础上不做增加,即:

<!-- bad -->
<script>
    alert('!');
</script>

<!-- good -->
<script>
alert('!');
</script>

CSS

CSS RULE002 [强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。

CSS RULE039 [强制] font-weight 属性必须使用数值方式描述。

必须将font-weight属性值改为数字,数字值 400 相当于关键字 normal,700 等价于 bold,900 等价于 bolder。

CSS RULE046 [强制] 带私有前缀的属性由长到短排列,按冒号位置对齐。

这两条规则看起来似乎有点矛盾,RULE002 说要使用 4 个空格作为缩进,而 RULE046 又说带私有前缀的属性要按长短排列,按冒号的位置来对齐。意思就是带私有前缀的属性可以不使用 4 个空格来作为缩进层级。那么关键词就是 私有前缀 了。但是有时候我们会发现我写的是按照规范来的,为什么还给我报错,而且报的错并不是 RULE002RULE046。我们来看如下示例:

.ani {
    -webkit-animation: spin 2s infinite linear;
       -moz-animation: spin 2s infinite linear;
        -ms-animation: spin 2s infinite linear;
         -o-animation: spin 2s infinite linear;
            animation: spin 2s infinite linear;
    color: #fff;
}

可以看到这段代码是完全符合 RULE002RULE046 的,但是用 fecs 来检测一样会报错出来。 fecs 执行结果如下:

fecs  INFO test.css (2 messages)
fecs ERROR → line   4, col   9, rule 998: [强制] 存在兼容性问题或运行时错误。(Current property `-ms-animation` is not existed)	(property-not-existed)
fecs ERROR → line   5, col  10, rule 998: [强制] 存在兼容性问题或运行时错误。(Current property `-o-animation` is not existed)	(property-not-existed)

信息很明确,我们就知道了其实是 -ms-animation-o-animation 这两个属性不存在导致的。那么问题就来了,如何判断一个带私有前缀的属性是否存在呢?

在工具中,存放带私有前缀的属性的代码在 这里。web 技术发展这么快,各个浏览器厂商也会时不时更新自己产品的实现,当然也包括对一些 CSS 属性的支持等等。因此,这个文件内容也不是一成不变的,也是会时常更新的。如果万一更新得不及时导致代码报错,那么你可以使用行内注释把这两条规则注释掉 /* csshint-disable block-indent vendor-prefixes-sort */,但是这样写的话,当前你的这个文件就不会得到这两个规则的检测了。因此更好的方式是你提 issue 然后我们更新属性的集合。

其他

当错误超出以上范围,并且认为不需要修复代码,可按以下步骤处理:

  • 安装 fecs

  • 运行 fecs [files] --rule,记下打印出的错误行尾显示的规则名。

  • 在文件头部使用 /* linter-disable ruleName */ 来屏蔽对应的规则。其中,JavaScript、CSS 和 HTML 文件分别对应的 linter 为 eslint、csshint 和 htmlcs。

  • 如果只需要对指定代码块作规则屏蔽,可以在代码块结束后使用 /* linter-enable ruleName */ 来恢复规则检查。

注意:

  • 当省略 ruleName 时,意味着关闭对当前文件的检查,但 ruleName 不存在时,则忽略该条设置。

  • 在 HTML 中, /**/ 应该换成 <!---->

自动豁免

自动豁免主要是指在 eagle 中自动跳过检查,分为目录、第三方和文件名三种方式。

目录豁免

被检查代码是压缩或编译后的代码、第三方类库、mock 数据或测试文件等,可以归类放置于以下目录内:

  • test tests
  • dist output
  • dep third_party thirdsrc
  • mock mocks mockup mockups
  • demo
  • tool tools
  • doc docs
  • node_modules bower_components

第三方类库豁免

以下匹配的第三方类库会自动豁免:

  • jquery(..+)?.(js|css)$
  • tangram.js echarts.js esl.js
  • angular.js backbone.js ember.js knockout.js
  • bootstrap.js
  • yui.js
  • zepto.js
  • when.js
  • moment.js
  • html5shiv.js
  • typo.css

文件名后缀

对于识别为压缩后文件或模板文件的后缀自动豁免:

  • *.min.js, *.m.js
  • *.mock.js, *.mockup.js
  • *.min.css, *.m.css
  • *.min.html, *.m.html, *.tpl.html
Clone this wiki locally