简介:
本篇主要介绍swift和dart代码规范检查工具,以及他们的工作原理,操作过程,代码规范规则。
SwiftLint 是 realm 公司开发的一个插件,专门用于管理 Swift 代码的规范。
SwiftLint 的工作原理是检查 Swift 代码编译过程中的 AST 和 SourceKit 环节,从而可以摆脱不同版本 Swift 语法变化的影响。AST 是编译前端形成的抽象语法树(Abstract Symbolic Tree), SourceKit 过程用来对 AST 进行代码优化,减少内存开销,提高执行效率。如果对编译过程理解不太清楚,可以参考:Clang官方文档以及网络上两篇比较好的文章AST 和 LLVM优点以及戴铭的深入剖析 iOS 编译 Clang / LLVM
预处理 -> 词法分析 -> Token -> 语法分析 -> AST -> 代码生成 -> LLVM IR -> 优化 -> 生成汇编代码 -> Link -> 目标文件
SourceKit 是一套工具集,使得大多数 Swift 源代码层面的操作特性得以支持,例如源代码解析、语法高亮、排版(typesetting)、自动补全、跨语言头文件生成,等等
由于 SourceKit 是独立于Xcode之外的,所以可以利用以构建从 Swift IDE 到文档生成器等任何东西
例如第三方的工具
1.jazzy是一个命令行实用程序,可为Swift或Objective-C生成文档
1.3.1 swiftlint配置
具体环境安装配置详见官方文档,写的比较详细就不一一赘述了 swiftlint官方文档以及触发规则文档。
swiftlint操作大体流程:
->安装swiftlint
->配置工程脚本
->配置.swiftlint.yml规则文件到项目根目录
->编译代码
->触发规则的项目报error和warning
->通过命令行进行具体操作(见下文)
->根据触发的规则对比触发规则文档修改代码
看一下配置的文件.swiftlint.yml(通过配置.swiflint.yml,控制禁用/启用哪个规则,并为给定规则设置警告和错误的阈值)
disabled_rules: # 执行时排除掉的规则
- colon
- comma
- control_statement
opt_in_rules: # 启用非默认设置的规则
- empty_count
- missing_docs
# 可以通过执行如下指令来查找所有可用的规则:
# swiftlint rules
included: # 执行 linting 时包含的路径。如果出现这个 `--path` 会被忽略。
- Source
excluded: # 执行 linting 时忽略的路径。 优先级比 `included` 更高。
- Carthage
- Pods
- Source/ExcludedFolder
- Source/ExcludedFile.swift
# 可配置的规则可以通过这个配置文件来自定义
# 强制转换规则,可以设置他们的严重程度error,warning
force_cast: warning # 隐式
force_try:
severity: warning # 显式
# 同时有警告和错误等级的规则,可以只设置它的警告等级
# 隐式
line_length: 110
# 可以通过一个数组同时进行隐式设置
type_body_length:
- 300 # warning
- 400 # error
# 或者也可以同时进行显式设置
file_length:
warning: 500
error: 1200
# 命名规则可以设置最小长度和最大程度的警告/错误
# 此外它们也可以设置排除在外的名字
type_name:
min_length: 4 # 只是警告
max_length: # 警告和错误
warning: 40
error: 50
excluded: iPhone # 排除某个名字
identifier_name:
min_length: # 只有最小长度
error: 4 # 只有错误
excluded: # 排除某些名字
- id
- URL
- GlobalAPIKey
reporter: "xcode" # 报告类型 (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging)
强制转换,严重级别设置warning和error两个等级
force_cast: warning # 隐式
force_try:
severity: warning # 显式
force_cast
非触发例子
NSNumber() as? Int
触发例子
NSNumber() as! Int
force_try 非触发例子
func a() throws {}
do {
try a()
} catch {}
触发例子
func a() throws {}
try! a()
也可以自定义规则:
custom_rules:
pirates_beat_ninjas: # 规则标识符
name: "Pirates Beat Ninjas" # 规则名称,可选
regex: "([nN]inja)" # 匹配的模式
match_kinds: # 需要匹配的语法类型,可选
- comment
- identifier
message: "Pirates are better than ninjas." # 提示信息,可选
severity: error # 提示的级别,可选
no_hiding_in_strings:
regex: "([nN]inja)"
match_kinds: string
输出样式:
swiftlint lint
swiftlint lint --path ~/Desktop --reporter html > swiftlint.html
swiftlint autocorrect
swiftlint docs
swiftlint generate-docs --path
swiftlint rules
identifier:规则名称
Opt-in:启用非默认设置的规则
correctable:可纠正的规则
enabled in your config:配置中已经启用
Kind:规则的种类
也可以用fastlane官方的SwiftLint功能来运行SwiftLint作为你的Fastlane程序的一部分
swiftlint(
mode: :lint, # SwiftLint模式: :lint (默认) 或者 :autocorrect
executable: "Pods/SwiftLint/swiftlint", # SwiftLint的程序路径 (可选的). 对于用CocoaPods集成SwiftLint时很重要
path: "/path/to/lint", # 特殊的检查路径 (可选的)
output_file: "swiftlint.result.json", # 检查结果输出路径 (可选的)
reporter: "json", # 输出格式 (可选的)
config_file: ".swiftlint-ci.yml", # 配置文件的路径 (可选的)
files: [ # 指定检查文件列表 (可选的)
"AppDelegate.swift",
"path/to/project/Model.swift"
],
ignore_exit_status: true, # 允许fastlane可以继续执行甚至是Swiftlint返回一个非0的退出状态(默认值: false)
quiet: true, # 不输出像‘Linting’和‘Done Linting’的状态日志 (默认值: false)
strict: true # 发现警告时报错? (默认值: false)
)
1.Flutter工程沿用Dart的静态代码检查器dartanalyzer, 并使用内置在Flutter Tools内的终端工具进行代码扫描和分析, 相关代码位于:commands
一般情况下, 在工程文件下配有分析脚本的情况下, 可以直接使用flutter analyze命令进行静态检查, 这和开发工具Android Studio自带的检查插件的效果是一样的, 最终结果会显示在AS下方的Dart Analysis Tab下.
检查器会根据项目根目录下的分析脚本执行检查, 该文件通常会与pubspec文件处于同一层级.
老版本的分析脚本命名为.analysis_options, 没有yaml后缀, 新版本统一命名为:analysis_options.yaml
除了这么放还能怎么放,如果遇到更加复杂的情况怎么办,比如说不同的文件夹下适应不同的规则,见下图:
检查器会使用#1检查other package和other other package, 使用#2检查my package.
在flutter 1.22 版本后有默认的分析脚本,内置在flutter包中analysis_options_user.yml
如果不想使用默认的分析脚本,当然也可以自己进行配置,如果嫌一条条配置lint规则麻烦, 可以直接集成Google的开源项目pedantic或者effective dart(二选一).
analysis_options.yaml配置
dart语言的代码规范以及相关触发规则详见linter
1). pedantic: Google内部执行的规则
在 pubspec.yaml
中添加如下,再flutter pub get
dev_dependencies:
pedantic: ^1.11.0
在 analysis_options.yaml
中引入
include: package:pedantic/analysis_options.yaml
2). effective_dart : 与 effective-dart指南 相对应的规则
在pubspec.yaml中
dev_dependencies:
effective_dart: ^1.0.0
执行 flutter pub get
然后在 analysis_options.yaml
中引入
include: package:effective_dart/analysis_options.yaml
3). Flutter官方在1.22版本默认使用的分析脚本 : analysis_options_user.yml
在flutter 1.22 版本默认使用的分析脚本 (注:flutter版本查看 flutter --version
)当然也可以导入之后进行自定义,如下
include: package:flutter/analysis_options_user.yaml
示例一个以google的pedantic为例 自定义 analysis_options.yaml
# 指定引用第三方库中预设文件的路径
include: package:pedantic/analysis_options.1.8.0.yaml
## analyzer : 配置static analysis的条目,包括启用更严格的类型检查,排除文件,忽略特定规则,更改规则的严重程度等。
## exclude 排除文件
analyzer:
exclude:
- [build/**]
- lib/http_client.dart
- lib/models/*.g.dart
- lib/mock/**
strong-mode:
implicit-casts: false
implicit-dynamic: false
errors:
todo: ignore
## linter : 配置linter规则
linter:
rules:
- camel_case_types
- cancel_subscriptions
我们知道dart使用语法糖实现了伪动态类型 - dynamic, 可以在编译器不确定类型时, 使用dynamic代替, implicit-dynamic可以阻止这种操作. implicit-casts表示禁止Object类型隐式转换为其他类型.
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
lint规则有两种配置方式一种是list方式 另一种是key-value方式,两者不能混用
list方式
linter:
rules:
-- annotate_overrides
-- await_only_futures
key-value方式
linter:
rules:
annotate_overrides: false #禁用规则
await_only_futures: true #开启规则
对于具体规则什么意思呢,咱们以上文中提到的 annotate_overrides和await_only_futures为例
可以看到文档写的非常清楚,其他规则触发详见 dart语言的代码规范以及相关触发规则linter
1).忽略文件
要忽略特定文件的特定非错误规则,请在文件中添加ignore_for_file注释
// ignore_for_file: unnecessary_new
这在注释之前或之后对整个文件起作用,并且对于生成的代码特别有用。
忽略多个规则
// ignore_for_file: unnecessary_new, unused_import, unused_local_variable
忽略单行
// ignore: unnecessary_new
每个linter规则都有默认的严重性。您可以使用分析选项文件来更改单个规则的严重性,或者始终忽略某些规则。
支持三种严重性级别:
忽略规则
analyzer:
errors:
todo: ignore
更改规则的严重性
analyzer:
errors:
invalid_assignment: warning
missing_return: error
dead_code: info
万事具备只欠东风 通过 dart analyze
挑出其中两条.
触发规则
info • Unnecessary new keyword at lib/business/home/home_page.dart:36:40 • (unnecessary_new)
具体代码
查看规则文档可知unnecessary_new应避免使用new关键字创建实例。
error • Missing return type for 'saveStringList' at lib/core/storage/shared_preferences_storage.dart:25:3 • (implicit_dynamic_return)
具体代码
查看所给的提示可知没有添加函数的返回值,找了规则文档没有找到这条implicit_dynamic_return规则。
原来我启用了更为严格的类型检查,所以才会触发这个error级别的错误。
上文说过这里就不多解释了。