HowToFix

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
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.