xcassetscop 0.0.1
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 +7 -0
- data/bin/xcassetscop +7 -0
- data/lib/xcassetscop/cli.rb +29 -0
- data/lib/xcassetscop/config_options.rb +38 -0
- data/lib/xcassetscop/configfile_parser.rb +13 -0
- data/lib/xcassetscop/hash_extension.rb +7 -0
- data/lib/xcassetscop/image_scale.rb +17 -0
- data/lib/xcassetscop/linter.rb +82 -0
- data/lib/xcassetscop/linter_rule.rb +30 -0
- data/lib/xcassetscop/module.rb +4 -0
- data/lib/xcassetscop/template_rendering_intent.rb +17 -0
- data/lib/xcassetscop/utility.rb +11 -0
- data/lib/xcassetscop.rb +10 -0
- metadata +56 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6392c29c38a1569c9dae8edab100e6da846ecd8cf4a90ade2f0a503a26afb795
|
4
|
+
data.tar.gz: 2bec50f9927a83a4c9f8db12854a2fe9d8d55e10db972737b88a0bd196a10df7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 591b55b55c1ea806189506308ab39620ba8b96080dc088deaa67810499fc4add36c91059ae509cb84f4b3ea9c2cefdd3d5646cfb731194c4be07ca5735e8a61c
|
7
|
+
data.tar.gz: 927b59ca999b135a55238ce15001bc99f3e65d54179690bcc7a877379ecbf2a72c6cb57e0bc789ae1f838340f5b45eb8949e6da757cc29efe3707b9a85a2c8f5
|
data/bin/xcassetscop
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'configfile_parser'
|
4
|
+
|
5
|
+
module XCAssetsCop
|
6
|
+
module CLI
|
7
|
+
def self.run(args)
|
8
|
+
configfile_path = File.expand_path args[0]
|
9
|
+
unless File.file? configfile_path
|
10
|
+
puts "Can't find file on path: #{configfile_path}"
|
11
|
+
return
|
12
|
+
end
|
13
|
+
puts "Using config file at #{configfile_path}"
|
14
|
+
|
15
|
+
rules = ConfigfileParser.parse configfile_path
|
16
|
+
amount_of_files = rules.reduce(0) { |acc, rule| rule.paths.size + acc }
|
17
|
+
errors = Linter.lint_files rules
|
18
|
+
|
19
|
+
puts "#{rules.size} rules found"
|
20
|
+
puts "#{amount_of_files} files checked"
|
21
|
+
if errors.size.positive?
|
22
|
+
puts "Found #{errors.size} offenses:"
|
23
|
+
puts errors
|
24
|
+
else
|
25
|
+
puts 'No errors found'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './hash_extension'
|
4
|
+
require_relative './template_rendering_intent'
|
5
|
+
require_relative './image_scale'
|
6
|
+
|
7
|
+
module XCAssetsCop
|
8
|
+
class ConfigOptions
|
9
|
+
attr_reader :file_extension, :image_scale, :same_file_and_asset_name, :template_rendering_intent
|
10
|
+
|
11
|
+
ALLOWED_KEYS = %i[
|
12
|
+
file_extension
|
13
|
+
image_scale
|
14
|
+
same_file_and_asset_name
|
15
|
+
template_rendering_intent
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
def initialize(obj)
|
19
|
+
ensure_all_keys_are_allowed obj
|
20
|
+
@file_extension = obj.sdig('file_extension')
|
21
|
+
@image_scale = obj.sdig('image_scale')
|
22
|
+
@same_file_and_asset_name = obj.sdig('same_file_and_asset_name') || false
|
23
|
+
@template_rendering_intent = obj.sdig('template_rendering_intent')
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def ensure_all_keys_are_allowed(obj)
|
29
|
+
diff = obj.keys.map(&:to_sym) - ALLOWED_KEYS
|
30
|
+
raise StandardError, "Unexpected key#{'s' if diff.size > 1}: #{diff.map { |s| "'#{s}'" }.join(', ')}" if diff.size.positive?
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate
|
34
|
+
TemplateRenderingIntent.validate @template_rendering_intent if @template_rendering_intent
|
35
|
+
ImageScale.validate @image_scale if @template_rendering_intent
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'utility'
|
4
|
+
|
5
|
+
module XCAssetsCop
|
6
|
+
module ImageScale
|
7
|
+
AVAILABLE_VALUES = %i[
|
8
|
+
single
|
9
|
+
individual
|
10
|
+
individual_and_single
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
def self.validate(value)
|
14
|
+
Utility.validate_params(value, AVAILABLE_VALUES)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative './template_rendering_intent'
|
5
|
+
require_relative './image_scale'
|
6
|
+
require_relative './linter_rule'
|
7
|
+
|
8
|
+
module XCAssetsCop
|
9
|
+
module Linter
|
10
|
+
def self.get_file_name(contents_json)
|
11
|
+
contents_json&.dig('images')&.first&.dig('filename')
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.file_name_matches_asset_name(contents_json, file_path)
|
15
|
+
asset_name = file_path.split('/').select { |str| str.include? '.imageset' }.first.split('.').first
|
16
|
+
file_name = get_file_name(contents_json)&.split('.')&.first
|
17
|
+
return [] if file_name == asset_name
|
18
|
+
|
19
|
+
["Expected asset name and file name to be the same, got:\nAsset name: #{asset_name}\nFile name: #{file_name}"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.validate_image_scale(contents_json, expected)
|
23
|
+
case contents_json&.dig('images')&.size
|
24
|
+
when 1
|
25
|
+
image_scale = :single
|
26
|
+
when 3
|
27
|
+
image_scale = :individual
|
28
|
+
when 4
|
29
|
+
image_scale = :individual_and_single
|
30
|
+
else
|
31
|
+
raise StandardError, "Couldn't figure out the image scale"
|
32
|
+
end
|
33
|
+
return [] if image_scale == expected
|
34
|
+
|
35
|
+
file_name = get_file_name contents_json
|
36
|
+
["Expected #{file_name} scale to be '#{expected}', got '#{image_scale}' instead"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.validate_template_rendering_intent(contents_json, expected)
|
40
|
+
template_rendering_intent = contents_json&.dig('properties')&.sdig('template-rendering-intent')&.to_sym || :default
|
41
|
+
return [] if template_rendering_intent == expected
|
42
|
+
|
43
|
+
file_name = get_file_name contents_json
|
44
|
+
["Expected #{file_name} to be rendered as '#{expected}', got '#{template_rendering_intent}' instead"]
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.validate_file_extension(contents_json, expected)
|
48
|
+
file_name = get_file_name(contents_json)
|
49
|
+
file_extension = file_name.split('.').last
|
50
|
+
return [] if expected.to_sym == file_extension.to_sym
|
51
|
+
|
52
|
+
["Expected #{file_name} type to be #{expected}, got #{file_extension} instead"]
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.lint_file(file_path, config)
|
56
|
+
file = File.read file_path
|
57
|
+
contents_json = JSON.parse file
|
58
|
+
|
59
|
+
template_rendering_intent = config.template_rendering_intent
|
60
|
+
image_scale = config.image_scale
|
61
|
+
same_file_and_asset_name = config.same_file_and_asset_name || false
|
62
|
+
file_extension = config.file_extension
|
63
|
+
|
64
|
+
errors = []
|
65
|
+
|
66
|
+
errors += validate_template_rendering_intent(contents_json, template_rendering_intent.to_sym) if template_rendering_intent
|
67
|
+
errors += validate_image_scale(contents_json, image_scale.to_sym) if image_scale
|
68
|
+
errors += file_name_matches_asset_name(contents_json, file_path) if same_file_and_asset_name
|
69
|
+
errors += validate_file_extension(contents_json, file_extension.to_sym) if file_extension
|
70
|
+
|
71
|
+
errors
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.lint_files(rules)
|
75
|
+
errors = []
|
76
|
+
rules.each do |rule|
|
77
|
+
errors += rule.paths.map { |path| lint_file(path, rule.config) }.flatten
|
78
|
+
end
|
79
|
+
errors
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './config_options'
|
4
|
+
|
5
|
+
module XCAssetsCop
|
6
|
+
class LinterRule
|
7
|
+
attr_reader :paths, :config
|
8
|
+
|
9
|
+
def initialize(obj)
|
10
|
+
LinterRule.ensure_no_missing_keys obj
|
11
|
+
LinterRule.ensure_all_keys_are_allowed obj
|
12
|
+
expanded_paths = obj.sdig(:paths).map { |path| File.expand_path(path) }
|
13
|
+
@paths = Dir.glob(expanded_paths)
|
14
|
+
@config = ConfigOptions.new obj.sdig(:config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.ensure_no_missing_keys(obj)
|
18
|
+
obj_sym = obj.keys.map(&:to_sym)
|
19
|
+
missing_keys = []
|
20
|
+
missing_keys << :paths unless obj_sym.include? :paths
|
21
|
+
missing_keys << :config unless obj_sym.include? :config
|
22
|
+
raise StandardError, "Missing key#{'s' if missing_keys.size > 1}: #{missing_keys.map { |s| "'#{s}'" }.join(', ')}" if missing_keys.size.positive?
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.ensure_all_keys_are_allowed(obj)
|
26
|
+
diff = obj.keys.map(&:to_sym) - %i[paths config]
|
27
|
+
raise StandardError, "Unexpected key#{'s' if diff.size > 1}: #{diff.map { |s| "'#{s}'" }.join(', ')}" if diff.size.positive?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'utility'
|
4
|
+
|
5
|
+
module XCAssetsCop
|
6
|
+
module TemplateRenderingIntent
|
7
|
+
AVAILABLE_VALUES = %i[
|
8
|
+
original
|
9
|
+
template
|
10
|
+
default
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
def self.validate(value)
|
14
|
+
Utility.validate_params(value, AVAILABLE_VALUES)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XCAssetsCop
|
4
|
+
module Utility
|
5
|
+
def self.validate_params(param, valid_params)
|
6
|
+
return true if valid_params.include? param
|
7
|
+
|
8
|
+
raise StandardError, "'#{param}' is not a valid parameter.\nValid parameters: #{valid_params.join(', ')}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/xcassetscop.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './xcassetscop/cli'
|
4
|
+
require_relative './xcassetscop/config_options'
|
5
|
+
require_relative './xcassetscop/configfile_parser'
|
6
|
+
require_relative './xcassetscop/image_scale'
|
7
|
+
require_relative './xcassetscop/linter'
|
8
|
+
require_relative './xcassetscop/linter_rule'
|
9
|
+
require_relative './xcassetscop/module'
|
10
|
+
require_relative './xcassetscop/template_rendering_intent'
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xcassetscop
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aleph Retamal
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-05-11 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Set rules for Xcode assets
|
14
|
+
email: retamal.ph@gmail.com
|
15
|
+
executables:
|
16
|
+
- xcassetscop
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/xcassetscop
|
21
|
+
- lib/xcassetscop.rb
|
22
|
+
- lib/xcassetscop/cli.rb
|
23
|
+
- lib/xcassetscop/config_options.rb
|
24
|
+
- lib/xcassetscop/configfile_parser.rb
|
25
|
+
- lib/xcassetscop/hash_extension.rb
|
26
|
+
- lib/xcassetscop/image_scale.rb
|
27
|
+
- lib/xcassetscop/linter.rb
|
28
|
+
- lib/xcassetscop/linter_rule.rb
|
29
|
+
- lib/xcassetscop/module.rb
|
30
|
+
- lib/xcassetscop/template_rendering_intent.rb
|
31
|
+
- lib/xcassetscop/utility.rb
|
32
|
+
homepage: https://lalacode.io
|
33
|
+
licenses:
|
34
|
+
- MIT
|
35
|
+
metadata: {}
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 2.7.6.2
|
53
|
+
signing_key:
|
54
|
+
specification_version: 4
|
55
|
+
summary: XCAssetsCop
|
56
|
+
test_files: []
|