使用jscpd实现单个项目或多个项目代码重复度检测

2,319 阅读6分钟

一个项目运行久了,中间又经过开发人员的更替,常常会导致项目代码臃肿,重复率增高,后面想要优化也变得难上加难,同时多个项目间也会出现代码复制粘帖的情况,这种问题其实是可以通过工具检测和统计出来的。最近逛社区发现了一个检测代码重复率的纯JavaScript代码库【jscpd】,于是自己在本地跑了几遍,还不错,在这里记录分享一下~

jscpd介绍

  1. 根据Rabin-Karp算法实现代码重复率的搜索。
  2. 支持150多种编程语言源码文件格式(包括各种前端框架,vue、react等)。
  3. 支持输出多种文档形式的检测报告,比如:html、json、markdown等。
  4. 开源地址仓库:github.com/kucherenko/jscpd/tree/master

jscpd使用

1、安装

两种安装方式,根据自身条件选择即可

// npm方式
npm install -g jscpd
// yarn方式
yarn global add jscpd

2、使用示例

  • 单个文件检测
jscpd ./custom-select.vue
  • 文件夹检测
jscpd ./src

命令执行完成后,会生成一个检测报告表格,如下: image.png

  • 字段介绍
  1. Format: 文件格式,例如 javascript、scss、markup、css等。

  2. Files analyzed: 分析的文件数量,可以统计项目中文件数量。

  3. Total lines: 被分析的所有文件中的代码总行数。

  4. Total tokens: 所有token的数量,一般以 标识符/变量等数字字符串空格 或 符号 等等作为一个 token 来统计数量。一行代码一般包含几个到几十个不等的token数量。

  5. Clones found: 查找到拷贝的重复代码块数量

  6. Duplicated lines: 重复的行数及占比,占比 = 重复行数 / 总行数 * 100,这里以markup为例:30873(重复行数)/206720(总行数) = 0.149346。

  7. Duplicated tokens: 重复的token数量及占比。占比计算公式与上面的Duplicated lines一样,这里就不举例了。

  8. Found N clones: 共检测到N个重复块,示例显示为1185。

  9. Detection time: 检测耗时,示例本次耗时20.564秒。

根据上面的检测结果介绍,可以初步了解jscpd的一些基本知识,接下来说一下如何在项目中配置jscpd。

3、单个项目中配置jscpd

下面的代码来自@jscpd/core,可以看到jscpd提供的配置项。

export function getDefaultOptions(): IOptions {
      return {
        executionId: new Date().toISOString(),
        path: [process.cwd()],
        mode: getModeHandler('mild'),
        minLines: 5,
        maxLines: 1000,
        maxSize: '100kb',
        minTokens: 50,
        output: './report',
        reporters: ['console'],
        ignore: [],
        threshold: undefined,
        formatsExts: {}, 
        debug: false,
        silent: false,
        blame: false,
        cache: true,
        absolute: false,
        noSymlinks: false,
        skipLocal: false,
        ignoreCase: false,
        gitignore: false,
        reportersOptions: {},
        exitCode: 0,
      };
}

以下是一些常用的配置项介绍

配置项功能默认值类型
minLines最小代码行数5number
maxLines最大代码行数1000number
maxSize最大文件大小,单位为kb100string
minTokens代码的最小块大小。代码块小于设置的min-tokens将被跳过50number
output检测完成后,文件输出目录./reportstring
reporters输出类型,比如:markdown、html、json、xml、csv等consolearray
ignore检测是想要忽略的文件目录或文件,用于过滤一些非业务代码,如依赖包、构建或静态文件等[]array
threshold重复率阈值undefined[number,undefined]
absolute在检测报告中是否使用绝对路径falseboolean
gitignore最小代码行数5
formatsExts设置自定义扩展名的文件{}object
silent是否打印更多关于检测过程中的信息falseboolean
cache缓存trueboolean

3.1 jscpd提供两种配置方式

  1. 项目根目录下创建配置文件 .jscpd.json,在此文件中配置具体参数。
// .jscpd.json
{
  "threshold": 0.1,
  "reporters": [
    "html",
    "console"
  ],
  "ignore": [
    "node_modules",
    ".npmrc"
  ],
  "absolute": true
}

  1. 直接在 package.json 文件中添加配置项,项目中没有package.json,可以自行添加一个。
// package.json
{ 
    ... 
    "jscpd": {
        "threshold": 1,
        "reporters": [
          "html",
          "console"
        ],
        "ignore": [
          "node_modules",
          ".npmrc"
        ],
        "absolute": true,
        "gitignore": true
      }
    ...
}

以上两种方式选择任意一种配置完成后,执行对应的命令即可输出报告。

这里以上面的package.json文件中的配置为示例,执行下面的命令

jscpd ./src 

jscpd会根据package.json文件中的配置项检测当前项目下src目录下的所有文件,阈值为1,检测完成后,会在项目根目录下生成一个report目录,里面存放输出报告,报告的类型为html格式。

下面是命令执行完成后生成的检测报告目录: image.png

在浏览器中打开index.html,显示的内容如下: image.png

image.png

此外,也可以在scripts中配置运行脚本命令:

"scripts": {
    "jscpd": "jscpd ./src"
}

3.2 命令行方式检测

有些时候,可能不需要针对整个项目进行检测,想要检测几个文件间的代码重复度,这种情况下,可以不用配置jscpd的配置文件,直接在命令行输入对应的简易命令即可。

例如:

jscpd ./src --min-tokens 20 --min-lines 20 --max-lines 2000 -o 'report' -r html

// 简写方式
jscpd ./src -k 200 -l 10 -x 2000 -o 'report' -r html
  • 最小tokens:--min-tokens,简写 -k
  • 最小行数:--min-lines,简写 -l
  • 最大行数:--max-lines,简写 -x
  • 输出类型:--reporters,简写 -r

4、多个项目配置jscpd

还有一种场景,就是检测多个项目间代码重复度,是否存在复制粘贴代码的现象。 针对这种场景,只需要在多个项目上级目录下配置一个package.json即可,额外需要注意的是,在配置文件中 ignore 属性的忽略目录,需要带上各项目的项目名称。

4.1 示例

  • 目录如下:

test-jscpd目录下存在四个以xc-为前缀的项目,在目录下创建一个package.json文件 image.png

  • 配置package.json文件如下:
"jscpd": {
    "threshold": 1,
    "silent": true,
    "minLines": 20,
    "reporters": [
      "html",
      "console"
    ],
    "ignore": [
      "xc-rate/node_modules",
      "xc-test-122/node_modules",
      "xc-test-xcm01/node_modules",
      "xc-test-xcm03/node_modules",
      "xc-rate/package.json",
      "xc-test-122/package.json",
      "xc-test-xcm01/package.json",
      "xc-test-xcm03/package.json"
    ],
    "absolute": true,
    "gitignore": true
}
  • 执行命令
jscpd  -o 'report' -r html
  • 输出报告

jscpd自动创建一个名为report的文件夹,里面的检测报告为html类型,如下图: image.png

在浏览器中打开index.html文件,内容如下: image.png

5、忽略检测

很多时候,项目中有些重复的代码是必要的,而上面说的ignore属性中忽略某个文件或者文件夹已经无法满足需求了,此时可以使用注释代码标识的方式来忽略检测,在代码的首尾位置添加注释,jscpd:ignore-start 和 jscpd:ignore-end 包裹代码即可。

  • 在js中使用
/* jscpd:ignore-start */
import XEUtils from 'xe-utils';
import { User } from './common';
import Api from './api.js';
/* jscpd:ignore-end */
  • 在css以及各种预处理中使用
/* jscpd:ignore-start */
.bottom-operation {
    box-sizing: border-box;
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 16px;
    bottom: 0;
    left: 0;
    width: 100%;
    min-height: 80px;
    background: #fff;
    border-radius: 4px 4px 0 0;
    z-index: 999;
}
/* jscpd:ignore-end */
  • 在html中使用
<!-- // jscpd:ignore-start -->
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<!-- // jscpd:ignore-end -->

以上就是全部内容了,有错误的地方欢迎掘友们纠正~

参考

  1. github.com/kucherenko/…
  2. juejin.cn/post/728869…
  3. juejin.cn/post/704288…