fui 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +14 -8
- data/LICENSE.md +1 -1
- data/README.md +56 -8
- data/RELEASING.md +61 -0
- data/bin/fui +10 -6
- data/lib/fui.rb +1 -0
- data/lib/fui/finder.rb +48 -7
- data/lib/fui/header.rb +1 -0
- data/lib/fui/project.rb +32 -0
- data/lib/fui/version.rb +1 -1
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ca2369b75631de675a012aa298db4edc1976fba82ca689411be60347be016525
|
4
|
+
data.tar.gz: 179e9195e0ededab573b0dee845cb4c60b766ce3e64cf001bf86d6be8a937c8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f2b6927e03089fee397a11ea73ce511c88ddbbe15652e106e4f1801fc677351f10f90cb39734bb2279cdda003e8c577108c9efab324a3dfe848b90c01133745
|
7
|
+
data.tar.gz: 2039608e5a2394039f3d576838da7e7324cdd8588bdca12cb15570a3d729446885568d2e1e3d05fd7777a9e9313d3f500c775368eb77a667a3495c470e5928cf
|
data/CHANGELOG.md
CHANGED
@@ -1,29 +1,35 @@
|
|
1
|
-
### 0.
|
1
|
+
### 0.5.0 (2018/12/19)
|
2
2
|
|
3
|
-
*
|
3
|
+
* [#29](https://github.com/dblock/fui/pull/29): Added support for ignoring paths through `-i`, `--ignore-path` - [@jeffctown](https://github.com/jeffctown).
|
4
|
+
* [#28](https://github.com/dblock/fui/pull/28): Added support for finding global imports (bracket notation) - [@jeffctown](https://github.com/jeffctown).
|
5
|
+
* [#28](https://github.com/dblock/fui/pull/28): Added ability to turn off global or local import checks through `-g`, `--ignore-global-imports` or `-l`, `--ignore-local-imports` - [@jeffctown](https://github.com/jeffctown).
|
6
|
+
* [#28](https://github.com/dblock/fui/pull/28): The `--ignorexib` option has been renamed to `--ignore-xib-files` - [@jeffctown](https://github.com/jeffctown).
|
7
|
+
* [#31](https://github.com/dblock/fui/pull/31): Added Danger, PR linter and a README TOC - [@jeffctown](https://github.com/jeffctown).
|
8
|
+
* [#32](https://github.com/dblock/fui/pull/32): Added support for ignoring bridging headers - [@jeffctown](https://github.com/jeffctown).
|
9
|
+
* [#33](https://github.com/dblock/fui/pull/33): Added RELEASING.md to document release process - [@jeffctown](https://github.com/jeffctown).
|
4
10
|
|
5
|
-
### 0.4.1 (8/16
|
11
|
+
### 0.4.1 (2017/8/16)
|
6
12
|
|
7
13
|
* [#24](https://github.com/dblock/fui/pull/24): Support .mm files - [@shachlan](https://github.com/Shachlan).
|
8
14
|
|
9
|
-
### 0.4.0 (5/14
|
15
|
+
### 0.4.0 (2016/5/14)
|
10
16
|
|
11
17
|
* [#20](https://github.com/dblock/fui/pull/20): Added `-x`, `--ignorexib`, find unused classes referenced from its own XIB - [@Ezor](https://github.com/Ezor).
|
12
18
|
|
13
|
-
### 0.3.0 (2/7
|
19
|
+
### 0.3.0 (2014/2/7)
|
14
20
|
|
15
21
|
* [#5](https://github.com/dblock/fui/issues/5): Explicitly require Ruby 1.9.3 or later in .gemspec - [@paulyoung](https://github.com/paulyoung).
|
16
22
|
* [#4](https://github.com/dblock/fui/issues/4): Added support for .storyboard and .xib `customClass` references - [@dblock](https://github.com/dblock).
|
17
23
|
|
18
|
-
### 0.2.0 (1/23
|
24
|
+
### 0.2.0 (2014/1/23)
|
19
25
|
|
20
26
|
* By default will display "(simulation)" because no actual files are being deleted - [@dblock](https://github.com/dblock).
|
21
27
|
* Fui's exit code with `find` will be the number of unused references found - [@dblock](https://github.com/dblock).
|
22
28
|
|
23
|
-
### 0.1.1 (1/22
|
29
|
+
### 0.1.1 (2014/1/22)
|
24
30
|
|
25
31
|
* Fix: properly handle .pch includes - [@dblock](https://github.com/dblock).
|
26
32
|
|
27
|
-
### 0.1.0 (1/22
|
33
|
+
### 0.1.0 (2014/1/22)
|
28
34
|
|
29
35
|
* Initial public release, based on code by [@dstnbrkr](https://github.com/dstnbrkr) - [@dblock](https://github.com/dblock).
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -6,19 +6,35 @@ Fui
|
|
6
6
|
|
7
7
|
Find unused Objective-C imports.
|
8
8
|
|
9
|
+
# Table of Contents
|
10
|
+
|
11
|
+
- [Usage](#usage)
|
12
|
+
- [Get Help](#get-help)
|
13
|
+
- [Find Unused Classes in the Current Directory](#find-unused-classes-in-the-current-directory)
|
14
|
+
- [Find Unused Classes in any Path](#find-unused-classes-in-any-path)
|
15
|
+
- [Skip Interface Builder (.xib) Files](#skip-interface-builder-xib-files)
|
16
|
+
- [Ignore Local Imports](#ignore-local-imports)
|
17
|
+
- [Ignore Global Imports](#ignore-global-imports)
|
18
|
+
- [Ignore a Path](#ignore-a-path)
|
19
|
+
- [Ignore Multiple Paths](#ignore-multiple-paths)
|
20
|
+
- [Delete All Unused Class Files with Prompt](#delete-all-unused-class-files-with-prompt)
|
21
|
+
- [Xcode Plugin](#xcode-plugin)
|
22
|
+
- [Contributing](#contributing)
|
23
|
+
- [Copyright and License](#copyright-and-license)
|
24
|
+
|
9
25
|
## Usage
|
10
26
|
|
11
27
|
```
|
12
28
|
gem install fui
|
13
29
|
```
|
14
30
|
|
15
|
-
|
31
|
+
### Get Help
|
16
32
|
|
17
33
|
```
|
18
34
|
fui help
|
19
35
|
```
|
20
36
|
|
21
|
-
|
37
|
+
### Find Unused Classes in the Current Directory
|
22
38
|
|
23
39
|
```
|
24
40
|
fui find
|
@@ -26,27 +42,59 @@ fui find
|
|
26
42
|
|
27
43
|
The `find` command lists all the files that contain unused imports and exits with the number of files found.
|
28
44
|
|
29
|
-
|
45
|
+
### Find Unused Classes in any Path
|
30
46
|
|
31
47
|
```
|
32
48
|
fui --path=~/source/project/Name find
|
33
49
|
```
|
34
50
|
|
35
|
-
|
51
|
+
### Skip Interface Builder (.xib) Files
|
36
52
|
|
37
|
-
|
53
|
+
Running `fui` with `-x` (or `--ignore-xib-files`) will, for example, mark `Foo.h` as unused when `Foo.xib` holds a reference to the `Foo` class and no other references to Foo.h exist.
|
38
54
|
|
39
55
|
```
|
40
56
|
fui -x --path=~/source/project/Name find
|
41
57
|
```
|
42
58
|
|
43
|
-
|
59
|
+
### Ignore Local Imports
|
60
|
+
|
61
|
+
Running `fui` with `-l` (or `--ignore-local-imports`) will, for example, mark `Foo.h` as unused when `Bar.h` contains a local (quotation syntax) import of `Foo.h` (eg. `#import Foo.h`).
|
62
|
+
|
63
|
+
```
|
64
|
+
fui -l --path=~/source/project/Name find
|
65
|
+
```
|
66
|
+
|
67
|
+
### Ignore Global Imports
|
68
|
+
|
69
|
+
Running `fui` with `-g` (or `--ignore-global-imports`) will, for example, mark `Foo.h` as unused when `Bar.h` contains a global (bracket syntax) import of `Foo.h` (eg. `#import <Framework/Foo.h>`).
|
70
|
+
|
71
|
+
```
|
72
|
+
fui -g --path=~/source/project/Name find
|
73
|
+
```
|
74
|
+
|
75
|
+
### Ignore a Path
|
76
|
+
|
77
|
+
Running `fui` with `-i` (or `--ignore-path`) will, for example, ignore a `Pods` folder when searching for headers or referencing files.
|
78
|
+
|
79
|
+
```
|
80
|
+
fui --path=~/source/project/Name --ignore-path=Pods find
|
81
|
+
```
|
82
|
+
|
83
|
+
### Ignore Multiple Paths
|
84
|
+
|
85
|
+
Running `fui` with `-i` (or `--ignore-path`) can ignore multiple folders when searching for headers or referencing files.
|
86
|
+
|
87
|
+
```
|
88
|
+
fui --path=~/source/project/Name --ignore-path=Pods --ignore-path=Libraries find
|
89
|
+
```
|
90
|
+
|
91
|
+
### Delete All Unused Class Files with Prompt
|
44
92
|
|
45
93
|
```
|
46
94
|
fui --path=~/source/project/Name delete --perform --prompt
|
47
95
|
```
|
48
96
|
|
49
|
-
|
97
|
+
## Xcode Plugin
|
50
98
|
|
51
99
|
Use [xcfui](https://github.com/jcavar/xcfui) for integration with Xcode.
|
52
100
|
|
@@ -56,6 +104,6 @@ There're [a few feature requests and known issues](https://github.com/dblock/fui
|
|
56
104
|
|
57
105
|
## Copyright and License
|
58
106
|
|
59
|
-
Copyright (c) 2014, Daniel Doubrovkine, [Artsy](http://artsy.github.io), based on code by [Dustin Barker](https://github.com/dstnbrkr).
|
107
|
+
Copyright (c) 2014-2018, Daniel Doubrovkine, [Artsy](http://artsy.github.io), based on code by [Dustin Barker](https://github.com/dstnbrkr).
|
60
108
|
|
61
109
|
This project is licensed under the [MIT License](LICENSE.md).
|
data/RELEASING.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Releasing fui
|
2
|
+
|
3
|
+
There are no hard rules about when to release fui. Release bug fixes frequently, features not so frequently, and breaking changes rarely.
|
4
|
+
|
5
|
+
### Release
|
6
|
+
|
7
|
+
Run tests, check that all tests succeed locally.
|
8
|
+
|
9
|
+
```
|
10
|
+
bundle install
|
11
|
+
rake
|
12
|
+
```
|
13
|
+
|
14
|
+
Check that the last build succeeded in [Travis CI](https://travis-ci.org/dblock/fui).
|
15
|
+
|
16
|
+
Change "Next" in [CHANGELOG.md](CHANGELOG.md) to the current date.
|
17
|
+
|
18
|
+
```
|
19
|
+
### 0.4.0 (2016/5/14)
|
20
|
+
```
|
21
|
+
|
22
|
+
Remove the line with "Your contribution here.", since there will be no more contributions to this release.
|
23
|
+
|
24
|
+
Commit your changes.
|
25
|
+
|
26
|
+
```
|
27
|
+
git add CHANGELOG.md
|
28
|
+
git commit -m "Preparing for release, 0.4.0."
|
29
|
+
git push origin master
|
30
|
+
```
|
31
|
+
|
32
|
+
Release.
|
33
|
+
|
34
|
+
```
|
35
|
+
$ rake release
|
36
|
+
|
37
|
+
fui 0.4.0 built to pkg/fui-0.4.0.gem.
|
38
|
+
Tagged v0.4.0.
|
39
|
+
Pushed git commits and tags.
|
40
|
+
Pushed fui 0.4.0 to rubygems.org.
|
41
|
+
```
|
42
|
+
|
43
|
+
### Prepare for the Next Version
|
44
|
+
|
45
|
+
Add the next release to [CHANGELOG.md](CHANGELOG.md).
|
46
|
+
|
47
|
+
```
|
48
|
+
### 0.4.1 (Next)
|
49
|
+
|
50
|
+
* Your contribution here.
|
51
|
+
```
|
52
|
+
|
53
|
+
Increment the third version number in [lib/fui/version.rb](lib/fui/version.rb).
|
54
|
+
|
55
|
+
Commit your changes.
|
56
|
+
|
57
|
+
```
|
58
|
+
git add CHANGELOG.md lib/fui/version.rb
|
59
|
+
git commit -m "Preparing for next development iteration, 0.4.1."
|
60
|
+
git push origin master
|
61
|
+
```
|
data/bin/fui
CHANGED
@@ -6,13 +6,16 @@ include GLI::App
|
|
6
6
|
|
7
7
|
program_desc 'Find unused imports in an Objective-C codebase.'
|
8
8
|
|
9
|
-
flag [
|
10
|
-
|
11
|
-
switch [
|
9
|
+
flag %i[p path], desc: 'Path to search.', default_value: Dir.pwd
|
10
|
+
flag %i[i ignore-path], desc: 'Path to ignore.', default_value: nil, multiple: true
|
11
|
+
switch %i[v verbose], desc: 'Produce verbose output.', default_value: false
|
12
|
+
switch %i[x ignore-xib-files], desc: 'Ignore interface builder (.xib) files.', default_value: false
|
13
|
+
switch %i[g ignore-global-imports], desc: 'Ignores imports using a global (angle bracket) format.', default_value: false
|
14
|
+
switch %i[l ignore-local-imports], desc: 'Ignores imports using a local (quote) format.', default_value: false
|
12
15
|
|
13
16
|
default_command :find
|
14
17
|
|
15
|
-
pre do |global_options, _command,
|
18
|
+
pre do |global_options, _command, _options, _args|
|
16
19
|
options = global_options.dup
|
17
20
|
path = options.delete(:path)
|
18
21
|
$fui = Fui::Finder.new(path, options)
|
@@ -40,8 +43,8 @@ end
|
|
40
43
|
|
41
44
|
desc 'Delete header and implementation files of unused classes'
|
42
45
|
command :delete do |c|
|
43
|
-
c.switch [
|
44
|
-
c.switch [
|
46
|
+
c.switch %i[t prompt], desc: 'Prompt on delete', default_value: true
|
47
|
+
c.switch %i[f perform], desc: 'Actually perform deletion', default_value: false, negatable: false
|
45
48
|
|
46
49
|
c.action do |global_options, options, _args|
|
47
50
|
begin
|
@@ -67,6 +70,7 @@ command :delete do |c|
|
|
67
70
|
File.delete(k.path) if options[:perform]
|
68
71
|
impl_path = k.path.gsub(/\.h$/, '.m')
|
69
72
|
next unless File.exist?(impl_path)
|
73
|
+
|
70
74
|
relative_path = Pathname.new(impl_path).relative_path_from(root).to_s
|
71
75
|
if global_options[:verbose]
|
72
76
|
puts "Removing #{relative_path}#{options[:perform] ? '' : ' (simulation)'}\r\n"
|
data/lib/fui.rb
CHANGED
data/lib/fui/finder.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Fui
|
2
|
+
# A class to find various things in an Objective C project.
|
2
3
|
class Finder
|
3
4
|
attr_reader :path, :options
|
4
5
|
|
@@ -9,7 +10,21 @@ module Fui
|
|
9
10
|
end
|
10
11
|
|
11
12
|
def headers
|
12
|
-
@headers ||=
|
13
|
+
@headers ||= find(path) { |path| Header.header?(path) }.collect { |path| Header.new(path) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def bridging_headers
|
17
|
+
@bridging_headers ||= find(path) { |path| Project.project?(path) }.collect { |path| Project.new(path).bridging_headers(options[:verbose]) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def ignores
|
21
|
+
return unless options['ignore-path']
|
22
|
+
|
23
|
+
@ignores ||= options['ignore-path'].map do |i|
|
24
|
+
raise Errno::ENOENT, i unless Dir.exist?(i)
|
25
|
+
|
26
|
+
Pathname(i)
|
27
|
+
end
|
13
28
|
end
|
14
29
|
|
15
30
|
def references(&block)
|
@@ -19,7 +34,6 @@ module Fui
|
|
19
34
|
references[header] = []
|
20
35
|
end
|
21
36
|
Find.find(path) do |path|
|
22
|
-
next unless File.ftype(path) == 'file'
|
23
37
|
if ['.m', '.mm', '.h', '.pch'].include?(File.extname(path))
|
24
38
|
process_code references, path, &block
|
25
39
|
elsif ['.storyboard', '.xib'].include?(File.extname(path))
|
@@ -31,27 +45,53 @@ module Fui
|
|
31
45
|
end
|
32
46
|
|
33
47
|
def unused_references(&block)
|
34
|
-
@unused_references ||= references(&block).select { |
|
48
|
+
@unused_references ||= references(&block).select { |k, v| v.count.zero? && !bridging_headers.include?(k.filename) }
|
35
49
|
end
|
36
50
|
|
37
51
|
private
|
38
52
|
|
39
53
|
# Find all files for which the block yields.
|
40
|
-
def
|
54
|
+
def find(path)
|
41
55
|
results = []
|
42
56
|
Find.find(path) do |fpath|
|
57
|
+
if FileTest.directory?(fpath)
|
58
|
+
next unless ignores
|
59
|
+
|
60
|
+
ignores.each do |ignore|
|
61
|
+
next unless fpath.include?(ignore.realpath.to_s)
|
62
|
+
|
63
|
+
puts "Ignoring Directory: #{fpath}" if options[:verbose]
|
64
|
+
Find.prune
|
65
|
+
end
|
66
|
+
end
|
43
67
|
results << fpath if yield fpath
|
44
68
|
end
|
45
69
|
results
|
46
70
|
end
|
47
71
|
|
72
|
+
def local_imported(file_contents, header)
|
73
|
+
return false if options['ignore-local-imports']
|
74
|
+
|
75
|
+
file_contents.include?("#import \"#{header.filename}\"")
|
76
|
+
end
|
77
|
+
|
78
|
+
def global_imported(file_contents, header)
|
79
|
+
return false if options['ignore-global-imports']
|
80
|
+
|
81
|
+
escaped_header = Regexp.quote(header.filename)
|
82
|
+
regex = '(#import\s{1}<.+\/' + escaped_header + '>)'
|
83
|
+
file_contents.match(regex)
|
84
|
+
end
|
85
|
+
|
48
86
|
def process_code(references, path)
|
49
87
|
File.open(path) do |file|
|
50
88
|
yield path if block_given?
|
51
|
-
filename = File.basename(path)
|
52
89
|
headers.each do |header|
|
53
90
|
filename_without_extension = File.basename(path, File.extname(path))
|
54
|
-
|
91
|
+
file_contents = File.read(file)
|
92
|
+
global_import_exists = global_imported(file_contents, header)
|
93
|
+
local_import_exists = local_imported(file_contents, header)
|
94
|
+
references[header] << path if filename_without_extension != header.filename_without_extension && (local_import_exists || global_import_exists)
|
55
95
|
end
|
56
96
|
end
|
57
97
|
end
|
@@ -61,7 +101,8 @@ module Fui
|
|
61
101
|
yield path if block_given?
|
62
102
|
headers.each do |header|
|
63
103
|
filename_without_extension = File.basename(path, File.extname(path))
|
64
|
-
|
104
|
+
check_xibs = !options['ignore-xib-files']
|
105
|
+
references[header] << path if (check_xibs || filename_without_extension != header.filename_without_extension) && File.read(file).include?("customClass=\"#{header.filename_without_extension}\"")
|
65
106
|
end
|
66
107
|
end
|
67
108
|
end
|
data/lib/fui/header.rb
CHANGED
data/lib/fui/project.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Fui
|
2
|
+
# Represents an Xcode Project pbxproj file
|
3
|
+
class Project
|
4
|
+
attr_accessor :filename, :bridging_header, :path
|
5
|
+
|
6
|
+
def self.project?(path)
|
7
|
+
File.extname(path) == '.pbxproj'
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@path = path
|
12
|
+
@filename = File.basename(path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def bridging_headers(verbose)
|
16
|
+
@bridging_headers ||= begin
|
17
|
+
regex = /(SWIFT_OBJC_BRIDGING_HEADER) = \".+\"/
|
18
|
+
bridging_headers = []
|
19
|
+
File.new(path).grep regex do |result|
|
20
|
+
tokens = result.split('"')
|
21
|
+
next if tokens.length < 2
|
22
|
+
|
23
|
+
path_tokens = tokens[1].split('/')
|
24
|
+
bridging_header = path_tokens[path_tokens.length - 1]
|
25
|
+
puts "Bridging Header Found: #{bridging_header} in #{project_path}." if verbose
|
26
|
+
bridging_headers << bridging_header
|
27
|
+
end
|
28
|
+
bridging_headers.uniq
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/fui/version.rb
CHANGED
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Doubrovkine
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gli
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
description:
|
@@ -35,10 +35,12 @@ files:
|
|
35
35
|
- CONTRIBUTING.md
|
36
36
|
- LICENSE.md
|
37
37
|
- README.md
|
38
|
+
- RELEASING.md
|
38
39
|
- bin/fui
|
39
40
|
- lib/fui.rb
|
40
41
|
- lib/fui/finder.rb
|
41
42
|
- lib/fui/header.rb
|
43
|
+
- lib/fui/project.rb
|
42
44
|
- lib/fui/version.rb
|
43
45
|
homepage: http://github.com/dblock/fui
|
44
46
|
licenses:
|
@@ -50,17 +52,17 @@ require_paths:
|
|
50
52
|
- lib
|
51
53
|
required_ruby_version: !ruby/object:Gem::Requirement
|
52
54
|
requirements:
|
53
|
-
- -
|
55
|
+
- - ">="
|
54
56
|
- !ruby/object:Gem::Version
|
55
57
|
version: 1.9.3
|
56
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
59
|
requirements:
|
58
|
-
- -
|
60
|
+
- - ">="
|
59
61
|
- !ruby/object:Gem::Version
|
60
62
|
version: 1.3.6
|
61
63
|
requirements: []
|
62
64
|
rubyforge_project:
|
63
|
-
rubygems_version: 2.
|
65
|
+
rubygems_version: 2.7.8
|
64
66
|
signing_key:
|
65
67
|
specification_version: 4
|
66
68
|
summary: Find unused Objective-C imports.
|