xat_support 1.29.3
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/LICENSE +176 -0
- data/README.md +33 -0
- data/config/locales/en.yml +85 -0
- data/config/locales/translations/zendesk_apps_support.yml +210 -0
- data/lib/xat_support.rb +30 -0
- data/lib/zendesk_apps_support/app_file.rb +38 -0
- data/lib/zendesk_apps_support/app_requirement.rb +5 -0
- data/lib/zendesk_apps_support/app_version.rb +64 -0
- data/lib/zendesk_apps_support/assets/default_styles.scss +3 -0
- data/lib/zendesk_apps_support/assets/default_template.html.erb +10 -0
- data/lib/zendesk_apps_support/assets/installed.js.erb +17 -0
- data/lib/zendesk_apps_support/assets/src.js.erb +39 -0
- data/lib/zendesk_apps_support/build_translation.rb +50 -0
- data/lib/zendesk_apps_support/engine.rb +9 -0
- data/lib/zendesk_apps_support/i18n.rb +28 -0
- data/lib/zendesk_apps_support/installation.rb +20 -0
- data/lib/zendesk_apps_support/installed.rb +22 -0
- data/lib/zendesk_apps_support/location.rb +29 -0
- data/lib/zendesk_apps_support/package.rb +339 -0
- data/lib/zendesk_apps_support/product.rb +15 -0
- data/lib/zendesk_apps_support/sass_functions.rb +20 -0
- data/lib/zendesk_apps_support/stylesheet_compiler.rb +23 -0
- data/lib/zendesk_apps_support/validations/banner.rb +33 -0
- data/lib/zendesk_apps_support/validations/manifest.rb +214 -0
- data/lib/zendesk_apps_support/validations/marketplace.rb +20 -0
- data/lib/zendesk_apps_support/validations/requirements.rb +105 -0
- data/lib/zendesk_apps_support/validations/source.rb +95 -0
- data/lib/zendesk_apps_support/validations/stylesheets.rb +29 -0
- data/lib/zendesk_apps_support/validations/templates.rb +18 -0
- data/lib/zendesk_apps_support/validations/translations.rb +64 -0
- data/lib/zendesk_apps_support/validations/validation_error.rb +101 -0
- metadata +229 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module ZendeskAppsSupport
|
2
|
+
module Product
|
3
|
+
# The product code below match the values in the database, do not change them!
|
4
|
+
PRODUCTS_AVAILABLE = [
|
5
|
+
{
|
6
|
+
code: 1,
|
7
|
+
name: 'support',
|
8
|
+
},
|
9
|
+
{
|
10
|
+
code: 2,
|
11
|
+
name: 'chat',
|
12
|
+
}
|
13
|
+
].freeze
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'sass'
|
2
|
+
|
3
|
+
module Sass::Script::Functions
|
4
|
+
module AppAssetUrl
|
5
|
+
def app_asset_url(name)
|
6
|
+
assert_type name, :String
|
7
|
+
result = %{url("#{app_asset_url_helper(name)}")}
|
8
|
+
Sass::Script::String.new(result)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def app_asset_url_helper(name)
|
14
|
+
url_builder = options[:app_asset_url_builder]
|
15
|
+
url_builder.app_asset_url(name.value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
include AppAssetUrl
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'sass'
|
2
|
+
|
3
|
+
module ZendeskAppsSupport
|
4
|
+
class StylesheetCompiler
|
5
|
+
def initialize(source, app_id, url_prefix)
|
6
|
+
@source, @app_id, @url_prefix = source, app_id, url_prefix
|
7
|
+
end
|
8
|
+
|
9
|
+
def compile
|
10
|
+
Sass::Engine.new(wrapped_source, syntax: :scss, app_asset_url_builder: self).render
|
11
|
+
end
|
12
|
+
|
13
|
+
def app_asset_url(name)
|
14
|
+
"#{@url_prefix}#{name}"
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def wrapped_source
|
20
|
+
".app-#{@app_id} {#{@source}}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'image_size'
|
2
|
+
|
3
|
+
module ZendeskAppsSupport
|
4
|
+
module Validations
|
5
|
+
module Banner
|
6
|
+
BANNER_WIDTH = 830
|
7
|
+
BANNER_HEIGHT = 200
|
8
|
+
|
9
|
+
class <<self
|
10
|
+
def call(package)
|
11
|
+
File.open(package.path_to('assets/banner.png'), 'rb') do |fh|
|
12
|
+
begin
|
13
|
+
image = ImageSize.new(fh)
|
14
|
+
|
15
|
+
unless image.format == :png
|
16
|
+
return [ValidationError.new('banner.invalid_format')]
|
17
|
+
end
|
18
|
+
|
19
|
+
unless (image.width == BANNER_WIDTH && image.height == BANNER_HEIGHT) ||
|
20
|
+
(image.width == 2 * BANNER_WIDTH && image.height == 2 * BANNER_HEIGHT)
|
21
|
+
return [ValidationError.new('banner.invalid_size', required_banner_width: BANNER_WIDTH,
|
22
|
+
required_banner_height: BANNER_HEIGHT)]
|
23
|
+
end
|
24
|
+
rescue
|
25
|
+
return [ValidationError.new('banner.invalid_format')]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module ZendeskAppsSupport
|
5
|
+
module Validations
|
6
|
+
module Manifest
|
7
|
+
REQUIRED_MANIFEST_FIELDS = %w( author defaultLocale ).freeze
|
8
|
+
OAUTH_REQUIRED_FIELDS = %w( client_id client_secret authorize_uri access_token_uri ).freeze
|
9
|
+
TYPES_AVAILABLE = %w( text password checkbox url number multiline hidden ).freeze
|
10
|
+
|
11
|
+
class <<self
|
12
|
+
def call(package)
|
13
|
+
return [ValidationError.new(:missing_manifest)] unless package.has_file?('manifest.json')
|
14
|
+
|
15
|
+
manifest = package.manifest_json
|
16
|
+
|
17
|
+
errors = []
|
18
|
+
errors << missing_keys_error(manifest)
|
19
|
+
errors << default_locale_error(manifest, package)
|
20
|
+
errors << oauth_error(manifest)
|
21
|
+
errors << parameters_error(manifest)
|
22
|
+
errors << invalid_hidden_parameter_error(manifest)
|
23
|
+
errors << invalid_type_error(manifest)
|
24
|
+
errors << name_as_parameter_name_error(manifest)
|
25
|
+
|
26
|
+
if manifest['requirementsOnly']
|
27
|
+
errors << ban_location(manifest)
|
28
|
+
errors << ban_framework_version(manifest)
|
29
|
+
else
|
30
|
+
errors << missing_location_error(package)
|
31
|
+
errors << invalid_location_error(package)
|
32
|
+
errors << duplicate_location_error(manifest)
|
33
|
+
errors << missing_framework_version(manifest)
|
34
|
+
errors << invalid_version_error(manifest, package)
|
35
|
+
end
|
36
|
+
|
37
|
+
errors.flatten.compact
|
38
|
+
rescue JSON::ParserError => e
|
39
|
+
return [ValidationError.new(:manifest_not_json, errors: e)]
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def ban_location(manifest)
|
45
|
+
ValidationError.new(:no_location_required) unless manifest['location'].nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
def ban_framework_version(manifest)
|
49
|
+
ValidationError.new(:no_framework_version_required) unless manifest['frameworkVersion'].nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
def oauth_error(manifest)
|
53
|
+
return unless manifest['oauth']
|
54
|
+
|
55
|
+
missing = OAUTH_REQUIRED_FIELDS.select do |key|
|
56
|
+
manifest['oauth'][key].nil? || manifest['oauth'][key].empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
if missing.any?
|
60
|
+
ValidationError.new('oauth_keys.missing', missing_keys: missing.join(', '), count: missing.length)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def parameters_error(manifest)
|
65
|
+
return unless manifest['parameters']
|
66
|
+
|
67
|
+
unless manifest['parameters'].is_a?(Array)
|
68
|
+
return ValidationError.new(:parameters_not_an_array)
|
69
|
+
end
|
70
|
+
|
71
|
+
para_names = manifest['parameters'].collect { |para| para['name'] }
|
72
|
+
duplicate_parameters = para_names.select { |name| para_names.count(name) > 1 }.uniq
|
73
|
+
unless duplicate_parameters.empty?
|
74
|
+
return ValidationError.new(:duplicate_parameters, duplicate_parameters: duplicate_parameters)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def missing_keys_error(manifest)
|
79
|
+
missing = REQUIRED_MANIFEST_FIELDS.select do |key|
|
80
|
+
manifest[key].nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
missing_keys_validation_error(missing) if missing.any?
|
84
|
+
end
|
85
|
+
|
86
|
+
def default_locale_error(manifest, package)
|
87
|
+
default_locale = manifest['defaultLocale']
|
88
|
+
unless default_locale.nil?
|
89
|
+
if default_locale !~ Translations::VALID_LOCALE
|
90
|
+
ValidationError.new(:invalid_default_locale, defaultLocale: default_locale)
|
91
|
+
elsif package.translation_files.detect { |file| file.relative_path == "translations/#{default_locale}.json" }.nil?
|
92
|
+
ValidationError.new(:missing_translation_file, defaultLocale: default_locale)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def missing_location_error(package)
|
98
|
+
missing_keys_validation_error(['location']) unless package.has_location?
|
99
|
+
end
|
100
|
+
|
101
|
+
def invalid_location_error(package)
|
102
|
+
errors = []
|
103
|
+
manifest_locations = package.locations
|
104
|
+
manifest_locations.find do |host, locations|
|
105
|
+
error = if !Location.hosts.include?(host)
|
106
|
+
ValidationError.new(:invalid_host, host_name: host)
|
107
|
+
elsif (invalid_locations = locations.keys - Location.names_for(host)).any?
|
108
|
+
ValidationError.new(:invalid_location,
|
109
|
+
invalid_locations: invalid_locations.join(', '),
|
110
|
+
host_name: host,
|
111
|
+
count: invalid_locations.length)
|
112
|
+
end
|
113
|
+
|
114
|
+
# abort early for invalid host or location name
|
115
|
+
if error
|
116
|
+
errors << error
|
117
|
+
break
|
118
|
+
end
|
119
|
+
|
120
|
+
locations.values.each do |path|
|
121
|
+
errors << invalid_location_uri_error(package, path)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
errors
|
125
|
+
end
|
126
|
+
|
127
|
+
def invalid_location_uri_error(package, path)
|
128
|
+
return nil if path == Package::LEGACY_URI_STUB
|
129
|
+
validation_error = ValidationError.new(:invalid_location_uri, uri: path)
|
130
|
+
uri = URI.parse(path)
|
131
|
+
unless uri.absolute? ? valid_absolute_uri?(uri) : valid_relative_uri?(package, uri)
|
132
|
+
validation_error
|
133
|
+
end
|
134
|
+
rescue URI::InvalidURIError => e
|
135
|
+
validation_error
|
136
|
+
end
|
137
|
+
|
138
|
+
def valid_absolute_uri?(uri)
|
139
|
+
uri.scheme == 'https' || uri.host == 'localhost'
|
140
|
+
end
|
141
|
+
|
142
|
+
def valid_relative_uri?(package, uri)
|
143
|
+
uri.path.start_with?('assets/') && package.has_file?(uri.path)
|
144
|
+
end
|
145
|
+
|
146
|
+
def duplicate_location_error(manifest)
|
147
|
+
locations = *manifest['location']
|
148
|
+
duplicate_locations = *locations.select { |location| locations.count(location) > 1 }.uniq
|
149
|
+
|
150
|
+
unless duplicate_locations.empty?
|
151
|
+
ValidationError.new(:duplicate_location, duplicate_locations: duplicate_locations.join(', '), count: duplicate_locations.length)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def missing_framework_version(manifest)
|
156
|
+
missing_keys_validation_error(['frameworkVersion']) if manifest['frameworkVersion'].nil?
|
157
|
+
end
|
158
|
+
|
159
|
+
def invalid_version_error(manifest, package)
|
160
|
+
valid_to_serve = AppVersion::TO_BE_SERVED
|
161
|
+
target_version = manifest['frameworkVersion']
|
162
|
+
|
163
|
+
if target_version == AppVersion::DEPRECATED
|
164
|
+
package.warnings << I18n.t('txt.apps.admin.warning.app_build.deprecated_version')
|
165
|
+
end
|
166
|
+
|
167
|
+
unless valid_to_serve.include?(target_version)
|
168
|
+
return ValidationError.new(:invalid_version, target_version: target_version, available_versions: valid_to_serve.join(', '))
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def name_as_parameter_name_error(manifest)
|
173
|
+
if manifest['parameters'].is_a?(Array)
|
174
|
+
if manifest['parameters'].any? { |p| p['name'] == 'name' }
|
175
|
+
ValidationError.new(:name_as_parameter_name)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def invalid_hidden_parameter_error(manifest)
|
181
|
+
invalid_params = []
|
182
|
+
|
183
|
+
if manifest.key?('parameters')
|
184
|
+
invalid_params = manifest['parameters'].select { |p| p['type'] == 'hidden' && p['required'] }.map { |p| p['name'] }
|
185
|
+
end
|
186
|
+
|
187
|
+
if invalid_params.any?
|
188
|
+
ValidationError.new(:invalid_hidden_parameter, invalid_params: invalid_params.join(', '), count: invalid_params.length)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def invalid_type_error(manifest)
|
193
|
+
return unless manifest['parameters'].is_a?(Array)
|
194
|
+
|
195
|
+
invalid_types = []
|
196
|
+
|
197
|
+
manifest['parameters'].each do |parameter|
|
198
|
+
parameter_type = parameter.fetch('type', '')
|
199
|
+
|
200
|
+
invalid_types << parameter_type unless TYPES_AVAILABLE.include?(parameter_type)
|
201
|
+
end
|
202
|
+
|
203
|
+
if invalid_types.any?
|
204
|
+
ValidationError.new(:invalid_type_parameter, invalid_types: invalid_types.join(', '), count: invalid_types.length)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def missing_keys_validation_error(missing_keys)
|
209
|
+
ValidationError.new('manifest_keys.missing', missing_keys: missing_keys.join(', '), count: missing_keys.length)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ZendeskAppsSupport
|
2
|
+
module Validations
|
3
|
+
module Marketplace
|
4
|
+
class << self
|
5
|
+
def call(package)
|
6
|
+
[no_symlinks(package.root)].compact
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def no_symlinks(path)
|
12
|
+
if Dir["#{path}/**/{*,.*}"].any? { |f| File.symlink?(f) }
|
13
|
+
return ValidationError.new(:symlink_in_zip)
|
14
|
+
end
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'json/stream'
|
3
|
+
|
4
|
+
module ZendeskAppsSupport
|
5
|
+
module Validations
|
6
|
+
module Requirements
|
7
|
+
MAX_REQUIREMENTS = 5000
|
8
|
+
|
9
|
+
class <<self
|
10
|
+
def call(package)
|
11
|
+
requirements_file = package.files.find { |f| f.relative_path == 'requirements.json' }
|
12
|
+
|
13
|
+
return [ValidationError.new(:missing_requirements)] unless requirements_file
|
14
|
+
|
15
|
+
requirements_stream = requirements_file.read
|
16
|
+
duplicates = non_unique_type_keys(requirements_stream)
|
17
|
+
unless duplicates.empty?
|
18
|
+
return [ValidationError.new(:duplicate_requirements, duplicate_keys: duplicates.join(', '), count: duplicates.length)]
|
19
|
+
end
|
20
|
+
|
21
|
+
requirements = JSON.load(requirements_stream)
|
22
|
+
[].tap do |errors|
|
23
|
+
errors << invalid_requirements_types(requirements)
|
24
|
+
errors << excessive_requirements(requirements)
|
25
|
+
errors << invalid_channel_integrations(requirements)
|
26
|
+
errors << invalid_user_fields(requirements)
|
27
|
+
errors << missing_required_fields(requirements)
|
28
|
+
errors.flatten!
|
29
|
+
errors.compact!
|
30
|
+
end
|
31
|
+
rescue JSON::ParserError => e
|
32
|
+
return [ValidationError.new(:requirements_not_json, errors: e)]
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def missing_required_fields(requirements)
|
38
|
+
[].tap do |errors|
|
39
|
+
requirements.each do |requirement_type, requirement|
|
40
|
+
next if requirement_type == 'channel_integrations'
|
41
|
+
requirement.each do |identifier, fields|
|
42
|
+
next if fields.include? 'title'
|
43
|
+
errors << ValidationError.new(:missing_required_fields, field: 'title', identifier: identifier)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def excessive_requirements(requirements)
|
50
|
+
requirement_count = requirements.values.map(&:values).flatten.size
|
51
|
+
if requirement_count > MAX_REQUIREMENTS
|
52
|
+
ValidationError.new(:excessive_requirements, max: MAX_REQUIREMENTS, count: requirement_count)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def invalid_user_fields(requirements)
|
57
|
+
user_fields = requirements['user_fields']
|
58
|
+
return unless user_fields
|
59
|
+
[].tap do |errors|
|
60
|
+
user_fields.each do |identifier, fields|
|
61
|
+
next if fields.include? 'key'
|
62
|
+
errors << ValidationError.new(:missing_required_fields, field: 'key', identifier: identifier)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def invalid_channel_integrations(requirements)
|
68
|
+
channel_integrations = requirements['channel_integrations']
|
69
|
+
return unless channel_integrations
|
70
|
+
[].tap do |errors|
|
71
|
+
if channel_integrations.size > 1
|
72
|
+
errors << ValidationError.new(:multiple_channel_integrations, count: channel_integrations.size)
|
73
|
+
end
|
74
|
+
channel_integrations.each do |identifier, fields|
|
75
|
+
unless fields.include? 'manifest_url'
|
76
|
+
errors << ValidationError.new(:missing_required_fields, field: 'manifest_url', identifier: identifier)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def invalid_requirements_types(requirements)
|
83
|
+
invalid_types = requirements.keys - ZendeskAppsSupport::AppRequirement::TYPES
|
84
|
+
|
85
|
+
unless invalid_types.empty?
|
86
|
+
ValidationError.new(:invalid_requirements_types, invalid_types: invalid_types.join(', '), count: invalid_types.length)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def non_unique_type_keys(requirements)
|
91
|
+
keys = []
|
92
|
+
duplicates = []
|
93
|
+
parser = JSON::Stream::Parser.new do
|
94
|
+
start_object { keys.push({}) }
|
95
|
+
end_object { keys.pop }
|
96
|
+
key { |k| duplicates.push(k) if keys.last.include? k; keys.last[k] = nil }
|
97
|
+
end
|
98
|
+
parser << requirements
|
99
|
+
|
100
|
+
duplicates
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'eslintrb'
|
2
|
+
|
3
|
+
module ZendeskAppsSupport
|
4
|
+
module Validations
|
5
|
+
module Source
|
6
|
+
LINTER_OPTIONS = {
|
7
|
+
rules: {
|
8
|
+
# enforcing options:
|
9
|
+
'semi' => 2,
|
10
|
+
'no-extra-semi' => 2,
|
11
|
+
'no-caller' => 2,
|
12
|
+
'no-undef' => 2,
|
13
|
+
|
14
|
+
# relaxing options:
|
15
|
+
'no-unused-expressions' => 2,
|
16
|
+
'no-redeclare' => 2,
|
17
|
+
'no-eq-null' => 0,
|
18
|
+
'comma-dangle' => 0,
|
19
|
+
'dot-notation' => 0
|
20
|
+
},
|
21
|
+
env: {
|
22
|
+
'browser' => true,
|
23
|
+
'commonjs' => true
|
24
|
+
},
|
25
|
+
parserOptions: {
|
26
|
+
'ecmaVersion': 6,
|
27
|
+
'sourceType': 'module'
|
28
|
+
},
|
29
|
+
# predefined globals:
|
30
|
+
globals: Hash[
|
31
|
+
%w(_ Base64 services helpers moment)
|
32
|
+
.map { |x| [x, false] }]
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
ENFORCED_LINTER_OPTIONS = {
|
36
|
+
rules: {
|
37
|
+
# enforcing options:
|
38
|
+
'no-caller' => 2
|
39
|
+
},
|
40
|
+
env: {
|
41
|
+
'browser' => true,
|
42
|
+
'commonjs' => true
|
43
|
+
},
|
44
|
+
# predefined globals:
|
45
|
+
globals: Hash[
|
46
|
+
%w(_ Base64 services helpers moment)
|
47
|
+
.map { |x| [x, false] }]
|
48
|
+
}.freeze
|
49
|
+
|
50
|
+
class <<self
|
51
|
+
def call(package)
|
52
|
+
files = package.js_files
|
53
|
+
app = files.find { |file| file.relative_path == 'app.js' }
|
54
|
+
eslint_config_path = "#{package.root}/.eslintrc.json"
|
55
|
+
has_eslint_config = File.exists?(eslint_config_path)
|
56
|
+
options = has_eslint_config ? JSON.parse(File.read(eslint_config_path)) : LINTER_OPTIONS
|
57
|
+
|
58
|
+
if package_needs_app_js?(package)
|
59
|
+
return [ ValidationError.new(:missing_source) ] unless app
|
60
|
+
else
|
61
|
+
return (package_has_code?(package) ? [ ValidationError.new(:no_code_for_ifo_notemplate) ] : [])
|
62
|
+
end
|
63
|
+
|
64
|
+
errors = eslint_errors(files, options)
|
65
|
+
errors << eslint_errors(files, ENFORCED_LINTER_OPTIONS) if errors.empty? && has_eslint_config
|
66
|
+
return app ? errors.flatten! : [ValidationError.new(:missing_source)]
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def package_has_code?(package)
|
72
|
+
!(package.js_files.empty? && package.template_files.empty? && package.app_css.empty?)
|
73
|
+
end
|
74
|
+
|
75
|
+
def package_needs_app_js?(package)
|
76
|
+
return false if package.manifest_json['requirementsOnly']
|
77
|
+
return false if package.iframe_only?
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
def eslint_error(file, options)
|
82
|
+
errors = Eslintrb.lint(file.read, options)
|
83
|
+
[ESLintValidationError.new(file.relative_path, errors)] if errors.any?
|
84
|
+
end
|
85
|
+
|
86
|
+
def eslint_errors(files, options)
|
87
|
+
files.each_with_object([]) do |file, errors|
|
88
|
+
error = eslint_error(file, options)
|
89
|
+
errors << error unless error.nil?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|