flr 1.0.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/CHANGELOG.md +37 -0
- data/Gemfile.lock +1 -1
- data/lib/flr.rb +11 -3
- data/lib/flr/checker.rb +16 -13
- data/lib/flr/command.rb +447 -137
- data/lib/flr/constant.rb +5 -1
- data/lib/flr/util/asset_util.rb +325 -32
- data/lib/flr/util/code_util.rb +226 -47
- data/lib/flr/util/file_util.rb +154 -22
- data/lib/flr/version.rb +2 -2
- metadata +3 -3
data/lib/flr/constant.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Flr
|
2
|
+
# Flr支持的非SVG类图片文件类型
|
3
|
+
NON_SVG_IMAGE_FILE_TYPES = %w(.png .jpg .jpeg .gif .webp .icon .bmp .wbmp)
|
4
|
+
# Flr支持的SVG类图片文件类型
|
5
|
+
SVG_IMAGE_FILE_TYPES = %w(.svg)
|
2
6
|
# Flr支持的图片文件类型
|
3
|
-
IMAGE_FILE_TYPES =
|
7
|
+
IMAGE_FILE_TYPES = NON_SVG_IMAGE_FILE_TYPES + SVG_IMAGE_FILE_TYPES
|
4
8
|
# Flr支持的文本文件类型
|
5
9
|
TEXT_FILE_TYPES = %w(.txt .json .yaml .xml)
|
6
10
|
# Flr支持的字体文件类型
|
data/lib/flr/util/asset_util.rb
CHANGED
@@ -6,89 +6,382 @@ module Flr
|
|
6
6
|
# 资产相关的工具类方法
|
7
7
|
class AssetUtil
|
8
8
|
|
9
|
-
#
|
9
|
+
# is_asset_variant?(legal_resource_file) -> true or false
|
10
|
+
#
|
11
|
+
# 判断当前的资源文件是不是资产变体(asset_variant)类型
|
12
|
+
#
|
13
|
+
# 判断的核心算法是:
|
14
|
+
# - 获取资源文件的父目录;
|
15
|
+
# - 判断父目录是否符合资产变体目录的特征
|
16
|
+
# 资产变体映射的的资源文件要求存放在“与 main_asset 在同一个目录下的”、“符合指定特征的”子目录中;
|
17
|
+
# 截止目前,Flutter只支持一种变体类型:倍率变体;
|
18
|
+
# 倍率变体只适用于非SVG类图片资源;
|
19
|
+
# 倍率变体目录特征可使用此正则来判断:“^((0\.[0-9]+)|([1-9]+[0-9]*(\.[0-9]+)?))[x]$”;
|
20
|
+
# 倍率变体目录名称示例:“0.5x”、“1.5x”、“2.0x”、“3.0x”,“2x”、“3x”;
|
21
|
+
#
|
22
|
+
def self.is_asset_variant?(legal_resource_file)
|
23
|
+
|
24
|
+
if FileUtil.is_non_svg_image_resource_file?(legal_resource_file)
|
25
|
+
dirname = File.dirname(legal_resource_file)
|
26
|
+
parent_dir_name = File.basename(dirname)
|
27
|
+
|
28
|
+
ratio_regex = /^((0\.[0-9]+)|([1-9]+[0-9]*(\.[0-9]+)?))[x]$/
|
29
|
+
if parent_dir_name =~ ratio_regex
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
|
37
|
+
# is_image_asset?(asset) -> true or false
|
38
|
+
#
|
39
|
+
# 判断当前资产是不是图片类资产
|
40
|
+
#
|
41
|
+
# === Examples
|
42
|
+
#
|
43
|
+
# === Example-1
|
44
|
+
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
45
|
+
# @return true
|
46
|
+
#
|
47
|
+
# === Example-2
|
48
|
+
# asset = "assets/images/test.png"
|
49
|
+
# @return true
|
50
|
+
#
|
51
|
+
def self.is_image_asset?(asset)
|
52
|
+
if FileUtil.is_image_resource_file?(asset)
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
# is_package_asset?(asset) -> true or false
|
60
|
+
#
|
61
|
+
# 判断当前资产是不是package类资产
|
62
|
+
#
|
63
|
+
# === Examples
|
64
|
+
#
|
65
|
+
# === Example-1
|
66
|
+
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
67
|
+
# @return true
|
68
|
+
#
|
69
|
+
# === Example-2
|
70
|
+
# asset = "assets/images/test.png"
|
71
|
+
# @return false
|
72
|
+
#
|
73
|
+
def self.is_package_asset?(asset)
|
74
|
+
package_prefix = "packages/"
|
75
|
+
if asset =~ /\A#{package_prefix}/
|
76
|
+
return true
|
77
|
+
end
|
78
|
+
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
|
82
|
+
# is_specified_package_asset?(package_name, asset) -> true or false
|
83
|
+
#
|
84
|
+
# 判断当前资产是不是指定的package的资产
|
85
|
+
#
|
86
|
+
# === Examples
|
87
|
+
# package_name = "flutter_r_demo"
|
88
|
+
#
|
89
|
+
# === Example-1
|
90
|
+
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
91
|
+
# @return true
|
92
|
+
#
|
93
|
+
# === Example-2
|
94
|
+
# asset = "packages/hello_demo/assets/images/test.png"
|
95
|
+
# @return false
|
96
|
+
#
|
97
|
+
def self.is_specified_package_asset?(package_name, asset)
|
98
|
+
specified_package_prefix = "packages/" + package_name + "/"
|
99
|
+
if asset =~ /\A#{specified_package_prefix}/
|
100
|
+
return true
|
101
|
+
end
|
102
|
+
|
103
|
+
return false
|
104
|
+
end
|
105
|
+
|
106
|
+
# get_main_resource_file(flutter_project_dir, package_name, asset) -> main_resource_file
|
107
|
+
#
|
108
|
+
# 获取指定flutter工程的asset对应的主资源文件
|
109
|
+
# 注意:主资源文件不一定存在,比如图片资产可能只存在变体资源文件
|
110
|
+
#
|
111
|
+
# === Examples
|
112
|
+
# flutter_project_dir = "~/path/to/flutter_r_demo"
|
113
|
+
# package_name = "flutter_r_demo"
|
114
|
+
#
|
115
|
+
# === Example-1
|
116
|
+
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
117
|
+
# main_resource_file = "~/path/to/flutter_r_demo/lib/assets/images/test.png"
|
118
|
+
#
|
119
|
+
# === Example-2
|
120
|
+
# asset = "assets/images/test.png"
|
121
|
+
# main_resource_file = "~/path/to/flutter_r_demo/assets/images/test.png"
|
122
|
+
#
|
123
|
+
def self.get_main_resource_file(flutter_project_dir, package_name, asset)
|
124
|
+
if is_specified_package_asset?(package_name, asset)
|
125
|
+
specified_package_prefix = "packages/" + package_name + "/"
|
126
|
+
|
127
|
+
# asset: packages/flutter_r_demo/assets/images/test.png
|
128
|
+
# to get implied_relative_resource_file: lib/assets/images/test.png
|
129
|
+
implied_relative_resource_file = asset.dup
|
130
|
+
implied_relative_resource_file[specified_package_prefix] = ""
|
131
|
+
implied_relative_resource_file = "lib/" + implied_relative_resource_file
|
132
|
+
|
133
|
+
# main_resource_file: ~/path/to/flutter_r_demo/lib/assets/images/test.png
|
134
|
+
main_resource_file = flutter_project_dir + "/" + implied_relative_resource_file
|
135
|
+
return main_resource_file
|
136
|
+
else
|
137
|
+
# asset: assets/images/test.png
|
138
|
+
# main_resource_file: ~/path/to/flutter_r_demo/assets/images/test.png
|
139
|
+
main_resource_file = flutter_project_dir + "/" + asset
|
140
|
+
return main_resource_file
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# is_asset_existed?(flutter_project_dir, package_name, asset) -> true or false
|
145
|
+
#
|
146
|
+
# 判断指定flutter工程的asset是不是存在;存在的判断标准是:asset需要存在对应的资源文件
|
147
|
+
#
|
148
|
+
# === Examples
|
149
|
+
# flutter_project_dir = "~/path/to/flutter_r_demo"
|
150
|
+
# package_name = "flutter_r_demo"
|
151
|
+
#
|
152
|
+
# === Example-1
|
153
|
+
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
154
|
+
# @return true
|
155
|
+
#
|
156
|
+
# === Example-2
|
157
|
+
# asset = "packages/flutter_r_demo/404/not-existed.png"
|
158
|
+
# @return false
|
159
|
+
#
|
160
|
+
def self.is_asset_existed?(flutter_project_dir, package_name, asset)
|
161
|
+
# 处理指定flutter工程的asset
|
162
|
+
# 1. 获取asset对应的main_resource_file
|
163
|
+
# 2. 若main_resource_file是非SVG类图片资源文件,判断asset是否存在的标准是:主资源文件或者至少一个变体资源文件存在
|
164
|
+
# 3. 若main_resource_file是SVG类图片资源文件或者其他资源文件,判断asset是否存在的标准是:主资源文件存在
|
165
|
+
#
|
166
|
+
main_resource_file = get_main_resource_file(flutter_project_dir, package_name, asset)
|
167
|
+
if FileUtil.is_non_svg_image_resource_file?(main_resource_file)
|
168
|
+
if File.exist?(main_resource_file)
|
169
|
+
return true
|
170
|
+
end
|
171
|
+
|
172
|
+
file_name = File.basename(main_resource_file)
|
173
|
+
file_dir = File.dirname(main_resource_file)
|
174
|
+
did_find_variant_resource_file = false
|
175
|
+
Dir.glob(["#{file_dir}/*/#{file_name}"]).each do |file|
|
176
|
+
if is_asset_variant?(file)
|
177
|
+
did_find_variant_resource_file = true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
if did_find_variant_resource_file
|
182
|
+
return true
|
183
|
+
end
|
184
|
+
else
|
185
|
+
if File.exist?(main_resource_file)
|
186
|
+
return true
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
return false
|
191
|
+
end
|
192
|
+
|
193
|
+
# generate_main_asset(flutter_project_dir, package_name, legal_resource_file) -> main_asset
|
194
|
+
#
|
195
|
+
# 为当前资源文件生成 main_asset
|
196
|
+
#
|
197
|
+
# === Examples
|
198
|
+
# flutter_project_dir = "~/path/to/flutter_r_demo"
|
199
|
+
# package_name = "flutter_r_demo"
|
200
|
+
#
|
201
|
+
# === Example-1
|
202
|
+
# legal_resource_file = "~/path/to/flutter_r_demo/lib/assets/images/test.png"
|
203
|
+
# main_asset = "packages/flutter_r_demo/assets/images/test.png"
|
204
|
+
#
|
205
|
+
# === Example-2
|
206
|
+
# legal_resource_file = "~/path/to/flutter_r_demo/lib/assets/images/3.0x/test.png"
|
207
|
+
# main_asset = "packages/flutter_r_demo/assets/images/test.png"
|
208
|
+
#
|
209
|
+
# === Example-3
|
210
|
+
# legal_resource_file = "~/path/to/flutter_r_demo/lib/assets/texts/3.0x/test.json"
|
211
|
+
# main_asset = "packages/flutter_r_demo/assets/texts/3.0x/test.json"
|
212
|
+
#
|
213
|
+
# === Example-3
|
214
|
+
# legal_resource_file = "~/path/to/flutter_r_demo/lib/assets/fonts/Amiri/Amiri-Regular.ttf"
|
215
|
+
# main_asset = "packages/flutter_r_demo/fonts/Amiri/Amiri-Regular.ttf"
|
216
|
+
#
|
217
|
+
# === Example-4
|
218
|
+
# legal_resource_file = "~/path/to/flutter_r_demo/assets/images/test.png"
|
219
|
+
# main_asset = "assets/images/test.png"
|
220
|
+
#
|
221
|
+
# === Example-5
|
222
|
+
# legal_resource_file = "~/path/to/flutter_r_demo/assets/images/3.0x/test.png"
|
223
|
+
# main_asset = "assets/images/test.png"
|
224
|
+
#
|
225
|
+
def self.generate_main_asset(flutter_project_dir, package_name, legal_resource_file)
|
226
|
+
# legal_resource_file: ~/path/to/flutter_r_demo/lib/assets/images/3.0x/test.png
|
227
|
+
# to get main_resource_file: ~/path/to/flutter_r_demo/lib/assets/images/test.png
|
228
|
+
main_resource_file = legal_resource_file
|
229
|
+
if is_asset_variant?(legal_resource_file)
|
230
|
+
# test.png
|
231
|
+
file_basename = File.basename(legal_resource_file)
|
232
|
+
# ~/path/to/flutter_r_demo/lib/assets/images/3.0x
|
233
|
+
file_dir = File.dirname(legal_resource_file)
|
234
|
+
# ~/path/to/flutter_r_demo/lib/assets/images
|
235
|
+
main_resource_file_dir = File.dirname(file_dir)
|
236
|
+
# ~/path/to/flutter_r_demo/lib/assets/images/test.png
|
237
|
+
main_resource_file = main_resource_file_dir + "/" + file_basename
|
238
|
+
end
|
239
|
+
|
240
|
+
# main_resource_file: ~/path/to/flutter_r_demo/lib/assets/images/test.png
|
241
|
+
# to get main_relative_resource_file: lib/assets/images/test.png
|
242
|
+
flutter_project_dir_prefix = "#{flutter_project_dir}/"
|
243
|
+
main_relative_resource_file = main_resource_file
|
244
|
+
if main_relative_resource_file =~ /\A#{flutter_project_dir_prefix}/
|
245
|
+
main_relative_resource_file["#{flutter_project_dir_prefix}"] = ""
|
246
|
+
end
|
247
|
+
|
248
|
+
# 判断 main_relative_resource_file 是不是 implied_resource_file 类型
|
249
|
+
# implied_resource_file 的定义是:放置在 "lib/" 目录内 resource_file
|
250
|
+
# 具体实现是:main_relative_resource_file 的前缀若是 "lib/" ,则其是 implied_resource_file 类型;
|
251
|
+
#
|
252
|
+
# implied_relative_resource_file 生成 main_asset 的算法是: main_asset = "packages/#{package_name}/#{asset_name}"
|
253
|
+
# non-implied_relative_resource_file 生成 main_asset 的算法是: main_asset = "#{asset_name}"
|
254
|
+
#
|
255
|
+
lib_prefix = "lib/"
|
256
|
+
if main_relative_resource_file =~ /\A#{lib_prefix}/
|
257
|
+
# main_relative_resource_file: lib/assets/images/test.png
|
258
|
+
# to get asset_name: assets/images/test.png
|
259
|
+
asset_name = main_relative_resource_file
|
260
|
+
asset_name[lib_prefix] = ""
|
261
|
+
|
262
|
+
main_asset = "packages/#{package_name}/#{asset_name}"
|
263
|
+
return main_asset
|
264
|
+
else
|
265
|
+
# main_relative_resource_file: assets/images/test.png
|
266
|
+
# to get asset_name: assets/images/test.png
|
267
|
+
asset_name = main_relative_resource_file
|
268
|
+
|
269
|
+
main_asset = asset_name
|
270
|
+
return main_asset
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# generate_image_assets(flutter_project_dir, package_name, legal_image_file_array) -> image_asset_array
|
10
275
|
#
|
11
276
|
# 遍历指定资源目录下扫描找到的legal_image_file数组生成image_asset数组
|
12
277
|
#
|
13
278
|
# === Examples
|
14
|
-
#
|
15
|
-
# resource_dir = "lib/assets/images"
|
279
|
+
# flutter_project_dir = "~/path/to/flutter_r_demo"
|
16
280
|
# package_name = "flutter_r_demo"
|
281
|
+
# legal_image_file_array = ["~/path/to/flutter_r_demo/lib/assets/images/test.png", "~/path/to/flutter_r_demo/lib/assets/images/3.0x/test.png"]
|
17
282
|
# image_asset_array = ["packages/flutter_r_demo/assets/images/test.png"]
|
18
283
|
#
|
19
|
-
def self.generate_image_assets(
|
284
|
+
def self.generate_image_assets(flutter_project_dir, package_name, legal_image_file_array)
|
20
285
|
|
21
286
|
image_asset_array = []
|
22
287
|
|
23
|
-
# implied_resource_dir = "assets/images"
|
24
|
-
implied_resource_dir = resource_dir
|
25
|
-
if resource_dir.include?("lib/")
|
26
|
-
implied_resource_dir = resource_dir.split("lib/")[1]
|
27
|
-
end
|
28
|
-
|
29
288
|
legal_image_file_array.each do |legal_image_file|
|
30
|
-
|
31
|
-
image_asset = "packages/#{package_name}/#{implied_resource_dir}/#{file_basename}"
|
289
|
+
image_asset = generate_main_asset(flutter_project_dir, package_name, legal_image_file)
|
32
290
|
image_asset_array.push(image_asset)
|
33
291
|
end
|
34
292
|
|
293
|
+
image_asset_array.uniq!
|
35
294
|
return image_asset_array
|
36
295
|
end
|
37
296
|
|
38
|
-
# generate_text_assets(
|
297
|
+
# generate_text_assets(flutter_project_dir, package_name, legal_text_file_array) -> text_asset_array
|
39
298
|
#
|
40
299
|
# 遍历指定资源目录下扫描找到的legal_text_file数组生成text_asset数组
|
41
300
|
#
|
42
301
|
# === Examples
|
43
|
-
#
|
44
|
-
# resource_dir = "lib/assets/jsons"
|
302
|
+
# flutter_project_dir = "~/path/to/flutter_r_demo"
|
45
303
|
# package_name = "flutter_r_demo"
|
304
|
+
# legal_text_file_array = ["~path/to/flutter_r_demo/lib/assets/jsons/test.json"]
|
46
305
|
# text_asset_array = ["packages/flutter_r_demo/assets/jsons/test.json"]
|
47
306
|
#
|
48
|
-
def self.generate_text_assets(
|
307
|
+
def self.generate_text_assets(flutter_project_dir, package_name, legal_text_file_array)
|
49
308
|
|
50
309
|
text_asset_array = []
|
51
310
|
|
52
311
|
legal_text_file_array.each do |legal_text_file|
|
53
|
-
|
54
|
-
implied_resource_file = legal_text_file
|
55
|
-
if legal_text_file.include?("lib/")
|
56
|
-
implied_resource_file = legal_text_file.split("lib/")[1]
|
57
|
-
end
|
58
|
-
text_asset = "packages/#{package_name}/#{implied_resource_file}"
|
312
|
+
text_asset = generate_main_asset(flutter_project_dir, package_name, legal_text_file)
|
59
313
|
text_asset_array.push(text_asset)
|
60
314
|
end
|
61
315
|
|
316
|
+
text_asset_array.uniq!
|
62
317
|
return text_asset_array
|
63
318
|
end
|
64
319
|
|
65
|
-
# generate_font_asset_configs(
|
320
|
+
# generate_font_asset_configs(flutter_project_dir, package_name, legal_font_file_array) -> font_asset_config_array
|
66
321
|
#
|
67
322
|
# 遍历指定资源目录下扫描找到的legal_font_file数组生成font_asset_config数组
|
68
323
|
#
|
69
324
|
# === Examples
|
70
|
-
#
|
71
|
-
# resource_dir = "lib/assets/fonts/Amiri"
|
325
|
+
# flutter_project_dir = "~/path/to/flutter_r_demo"
|
72
326
|
# package_name = "flutter_r_demo"
|
327
|
+
# legal_font_file_array = ["~path/to/flutter_r_demo/lib/assets/fonts/Amiri/Amiri-Regular.ttf"]
|
73
328
|
# font_asset_config_array -> [{"asset": "packages/flutter_r_demo/assets/fonts/Amiri/Amiri-Regular.ttf"}]
|
74
329
|
#
|
75
|
-
def self.generate_font_asset_configs(
|
330
|
+
def self.generate_font_asset_configs(flutter_project_dir, package_name, legal_font_file_array)
|
76
331
|
|
77
332
|
font_asset_config_array = []
|
78
333
|
|
79
334
|
legal_font_file_array.each do |legal_font_file|
|
80
|
-
|
81
|
-
implied_resource_file = legal_font_file
|
82
|
-
if legal_font_file.include?("lib/")
|
83
|
-
implied_resource_file = legal_font_file.split("lib/")[1]
|
84
|
-
end
|
85
|
-
font_asset = "packages/#{package_name}/#{implied_resource_file}"
|
335
|
+
font_asset = generate_main_asset(flutter_project_dir, package_name, legal_font_file)
|
86
336
|
font_asset_config = Hash["asset" => font_asset]
|
87
337
|
font_asset_config_array.push(font_asset_config)
|
88
338
|
end
|
89
339
|
|
340
|
+
font_asset_config_array.uniq!{|config| config["asset"]}
|
90
341
|
return font_asset_config_array
|
91
342
|
end
|
92
343
|
|
344
|
+
# mergeFlutterAssets(new_asset_array, old_asset_array) -> merged_asset_array
|
345
|
+
#
|
346
|
+
# 合并新旧2个asset数组:
|
347
|
+
# - old_asset_array - new_asset_array = diff_asset_array,获取old_asset_array与new_asset_array的差异集合
|
348
|
+
# - 遍历diff_asset_array,筛选合法的asset得到legal_old_asset_array;合法的asset标准是:非图片资源 + 存在对应的资源文件
|
349
|
+
# - 按照字典序对legal_old_asset_array进行排序,并追加到new_asset_array
|
350
|
+
# - 返回合并结果merged_asset_array
|
351
|
+
#
|
352
|
+
# === Examples
|
353
|
+
# flutter_project_dir = "~/path/to/flutter_r_demo"
|
354
|
+
# package_name = "flutter_r_demo"
|
355
|
+
# new_asset_array = ["packages/flutter_r_demo/assets/images/test.png", "packages/flutter_r_demo/assets/jsons/test.json"]
|
356
|
+
# old_asset_array = ["packages/flutter_r_demo/assets/htmls/test.html"]
|
357
|
+
# merged_asset_array = ["packages/flutter_r_demo/assets/images/test.png", "packages/flutter_r_demo/assets/jsons/test.json", "packages/flutter_r_demo/assets/htmls/test.html"]
|
358
|
+
def self.mergeFlutterAssets(flutter_project_dir, package_name, new_asset_array, old_asset_array)
|
359
|
+
legal_old_asset_array = []
|
360
|
+
|
361
|
+
diff_asset_array = old_asset_array - new_asset_array;
|
362
|
+
diff_asset_array.each do |asset|
|
363
|
+
# 若是第三方package的资源,则合并到new_asset_array
|
364
|
+
# 引用第三方package的资源的推荐做法是:通过引用第三方package的R类来访问
|
365
|
+
if is_package_asset?(asset)
|
366
|
+
if is_specified_package_asset?(package_name, asset) == false
|
367
|
+
legal_old_asset_array.push(asset)
|
368
|
+
next
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# 处理指定flutter工程的asset
|
373
|
+
# 1. 判断asset是否存在
|
374
|
+
# 2. 若asset存在,则合并到new_asset_array
|
375
|
+
#
|
376
|
+
if is_asset_existed?(flutter_project_dir, package_name, asset)
|
377
|
+
legal_old_asset_array.push(asset)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
legal_old_asset_array.sort!
|
382
|
+
merged_asset_array = new_asset_array + legal_old_asset_array
|
383
|
+
return merged_asset_array
|
384
|
+
end
|
385
|
+
|
93
386
|
end
|
94
387
|
end
|
data/lib/flr/util/code_util.rb
CHANGED
@@ -5,6 +5,36 @@ module Flr
|
|
5
5
|
# 代码生成相关的工具类方法
|
6
6
|
class CodeUtil
|
7
7
|
|
8
|
+
@@should_support_nullsafety = nil
|
9
|
+
|
10
|
+
def self.should_support_nullsafety
|
11
|
+
if @@should_support_nullsafety != nil
|
12
|
+
return @@should_support_nullsafety
|
13
|
+
end
|
14
|
+
|
15
|
+
# $ flutter --version
|
16
|
+
# Flutter 1.12.13+hotfix.5 • channel stable • https://github.com/flutter/flutter.git
|
17
|
+
# Framework • revision 27321ebbad (5 weeks ago) • 2019-12-10 18:15:01 -0800
|
18
|
+
# Engine • revision 2994f7e1e6
|
19
|
+
# Tools • Dart 2.7.0
|
20
|
+
flutter_version_result = `flutter --version`
|
21
|
+
if (flutter_version_result.nil? == true || flutter_version_result.empty? == true)
|
22
|
+
@@should_support_nullsafety = false
|
23
|
+
return @@should_support_nullsafety
|
24
|
+
end
|
25
|
+
|
26
|
+
dart_version_str = flutter_version_result.split("Dart")[1]
|
27
|
+
dart_version_str.strip!
|
28
|
+
|
29
|
+
if Version.new(dart_version_str) >= Version.new("2.12.0")
|
30
|
+
@@should_support_nullsafety = true
|
31
|
+
return @@should_support_nullsafety
|
32
|
+
end
|
33
|
+
|
34
|
+
@@should_support_nullsafety = false
|
35
|
+
return @@should_support_nullsafety
|
36
|
+
end
|
37
|
+
|
8
38
|
# generate_R_class(package_name) -> string
|
9
39
|
#
|
10
40
|
# 根据模板生成 R class 的代码
|
@@ -66,6 +96,58 @@ class R {
|
|
66
96
|
/// - fileBasename:example.png
|
67
97
|
/// - fileBasenameNoExtension:example
|
68
98
|
/// - fileExtname:.png
|
99
|
+
CODE
|
100
|
+
|
101
|
+
if should_support_nullsafety
|
102
|
+
code += <<-CODE
|
103
|
+
class AssetResource {
|
104
|
+
/// Creates an object to hold the asset resource’s metadata.
|
105
|
+
const AssetResource(this.assetName, {this.packageName});
|
106
|
+
|
107
|
+
/// The name of the main asset from the set of asset resources to choose from.
|
108
|
+
final String assetName;
|
109
|
+
|
110
|
+
/// The name of the package from which the asset resource is included.
|
111
|
+
final String? packageName;
|
112
|
+
|
113
|
+
/// The name used to generate the key to obtain the asset resource. For local assets
|
114
|
+
/// this is [assetName], and for assets from packages the [assetName] is
|
115
|
+
/// prefixed 'packages/<package_name>/'.
|
116
|
+
String get keyName => packageName == null ? assetName : "packages/$packageName/$assetName";
|
117
|
+
|
118
|
+
/// The file basename of the asset resource.
|
119
|
+
String get fileBasename {
|
120
|
+
final basename = path.basename(assetName);
|
121
|
+
return basename;
|
122
|
+
}
|
123
|
+
|
124
|
+
/// The no extension file basename of the asset resource.
|
125
|
+
String get fileBasenameNoExtension {
|
126
|
+
final basenameWithoutExtension = path.basenameWithoutExtension(assetName);
|
127
|
+
return basenameWithoutExtension;
|
128
|
+
}
|
129
|
+
|
130
|
+
/// The file extension name of the asset resource.
|
131
|
+
String get fileExtname {
|
132
|
+
final extension = path.extension(assetName);
|
133
|
+
return extension;
|
134
|
+
}
|
135
|
+
|
136
|
+
/// The directory path name of the asset resource.
|
137
|
+
String get fileDirname {
|
138
|
+
var dirname = assetName;
|
139
|
+
if (packageName != null) {
|
140
|
+
final packageStr = "packages/$packageName/";
|
141
|
+
dirname = dirname.replaceAll(packageStr, "");
|
142
|
+
}
|
143
|
+
final filenameStr = "$fileBasename/";
|
144
|
+
dirname = dirname.replaceAll(filenameStr, "");
|
145
|
+
return dirname;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
CODE
|
149
|
+
else
|
150
|
+
code += <<-CODE
|
69
151
|
class AssetResource {
|
70
152
|
/// Creates an object to hold the asset resource’s metadata.
|
71
153
|
const AssetResource(this.assetName, {this.packageName}) : assert(assetName != null);
|
@@ -111,12 +193,13 @@ class AssetResource {
|
|
111
193
|
return dirname;
|
112
194
|
}
|
113
195
|
}
|
114
|
-
|
196
|
+
CODE
|
197
|
+
end
|
115
198
|
|
116
199
|
return code
|
117
200
|
end
|
118
201
|
|
119
|
-
# generate_asset_id (asset, prior_asset_type) -> string
|
202
|
+
# generate_asset_id (asset, used_asset_id_array, prior_asset_type) -> string
|
120
203
|
#
|
121
204
|
# - prior_asset_type: 优先的资源类型;默认值为 ".*",意味当前不存在任何优先的资源类型
|
122
205
|
# 对于优先的资源类型,其 asset_id 不会携带类型信息,详细见例子
|
@@ -126,26 +209,40 @@ class AssetResource {
|
|
126
209
|
# - 处理非法字符:把除了字母(a-z, A-Z)、数字(0-9)、'_' 字符、'$' 字符之外的字符转换为 '_' 字符
|
127
210
|
# - 首字母转化为小写
|
128
211
|
# - 处理首字符异常情况:检测首字符是不是数字、'_'、'$',若是则添加前缀字符"a"
|
212
|
+
# - 处理 asset_id 重名的情况
|
129
213
|
#
|
130
214
|
# === Examples
|
131
215
|
#
|
132
216
|
# ===== Example-1
|
133
|
-
#
|
134
|
-
#
|
217
|
+
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
218
|
+
# asset = "packages/flutter_r_demo/assets/images/test.jpg"
|
219
|
+
# used_asset_id_array = []
|
135
220
|
# prior_asset_type = ".png"
|
136
|
-
#
|
137
|
-
# b_asset_id = "test_jpg"
|
221
|
+
# asset_id = "test"
|
138
222
|
#
|
139
223
|
# ===== Example-2
|
140
|
-
#
|
141
|
-
#
|
224
|
+
# asset = "packages/flutter_r_demo/assets/images/test.jpg"
|
225
|
+
# used_asset_id_array = [test]
|
226
|
+
# prior_asset_type = ".png"
|
227
|
+
# asset_id = "test_jpg"
|
228
|
+
#
|
229
|
+
# ===== Example-3
|
230
|
+
# asset = "packages/flutter_r_demo/assets/home-images/test.jpg"
|
231
|
+
# used_asset_id_array = [test, test_jpg]
|
232
|
+
# prior_asset_type = ".png"
|
233
|
+
# asset_id = "test_jpg_1"
|
234
|
+
#
|
235
|
+
# ===== Example-4
|
236
|
+
# asset = "packages/flutter_r_demo/assets/texts/test.json"
|
237
|
+
# used_asset_id_array = []
|
142
238
|
# prior_asset_type = ".*"
|
143
|
-
#
|
144
|
-
# b_asset_id = "test_yaml"
|
239
|
+
# asset_id = "test_json"
|
145
240
|
#
|
146
|
-
def self.generate_asset_id(asset, prior_asset_type = ".*")
|
241
|
+
def self.generate_asset_id(asset, used_asset_id_array, prior_asset_type = ".*")
|
147
242
|
file_extname = File.extname(asset).downcase
|
148
243
|
|
244
|
+
dirname = File.dirname(asset)
|
245
|
+
parent_dir_name = File.basename(dirname)
|
149
246
|
file_basename = File.basename(asset)
|
150
247
|
|
151
248
|
file_basename_no_extension = File.basename(asset, ".*")
|
@@ -168,6 +265,26 @@ class AssetResource {
|
|
168
265
|
asset_id = "a" + asset_id
|
169
266
|
end
|
170
267
|
|
268
|
+
# 处理 asset_id 重名的情况
|
269
|
+
if used_asset_id_array.include?(asset_id)
|
270
|
+
# 当前asset_id重名次数,初始值为1
|
271
|
+
repeat_count = 1
|
272
|
+
|
273
|
+
# 查找当前asset_id衍生出来的asset_id_brother(id兄弟)
|
274
|
+
# asset_id_brother = #{asset_id}$#{repeat_count}
|
275
|
+
# 其中,repeat_count >= 1
|
276
|
+
#
|
277
|
+
# Example:
|
278
|
+
# asset_id = test
|
279
|
+
# asset_id_brother = test$1
|
280
|
+
#
|
281
|
+
id_brother_regx = /^#{asset_id}\$[1-9][0-9]*$/
|
282
|
+
cur_asset_id_brothers = used_asset_id_array.select{ |id| id =~ id_brother_regx }
|
283
|
+
|
284
|
+
repeat_count += cur_asset_id_brothers.size
|
285
|
+
asset_id = "#{asset_id}$#{repeat_count}"
|
286
|
+
end
|
287
|
+
|
171
288
|
return asset_id
|
172
289
|
end
|
173
290
|
|
@@ -176,54 +293,105 @@ class AssetResource {
|
|
176
293
|
# 为当前asset生成注释
|
177
294
|
#
|
178
295
|
# === Examples
|
179
|
-
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
180
296
|
# package_name = "flutter_r_demo"
|
297
|
+
#
|
298
|
+
# === Example-1
|
299
|
+
# asset = "packages/flutter_r_demo/assets/images/test.png"
|
300
|
+
# asset_comment = "asset: lib/assets/images/test.png"
|
301
|
+
#
|
302
|
+
# === Example-2
|
303
|
+
# asset = "assets/images/test.png"
|
181
304
|
# asset_comment = "asset: assets/images/test.png"
|
182
305
|
#
|
183
306
|
def self.generate_asset_comment (asset, package_name)
|
307
|
+
packages_prefix = "packages/#{package_name}/"
|
308
|
+
|
309
|
+
if asset =~ /\A#{packages_prefix}/
|
310
|
+
# asset: packages/flutter_r_demo/assets/images/test.png
|
311
|
+
# to get assetName: assets/images/test.png
|
312
|
+
asset_name = asset.dup
|
313
|
+
asset_name[packages_prefix] = ""
|
314
|
+
|
315
|
+
asset_comment = "asset: lib/#{asset_name}"
|
316
|
+
return asset_comment
|
317
|
+
else
|
318
|
+
# asset: assets/images/test.png
|
319
|
+
# to get assetName: assets/images/test.png
|
320
|
+
asset_name = asset.dup
|
321
|
+
|
322
|
+
asset_comment = "asset: #{asset_name}"
|
323
|
+
return asset_comment
|
324
|
+
end
|
184
325
|
|
185
|
-
asset_name = asset.dup
|
186
|
-
asset_name["packages/#{package_name}/"] = ""
|
187
|
-
|
188
|
-
asset_comment = "asset: #{asset_name}"
|
189
|
-
|
190
|
-
return asset_comment
|
191
326
|
end
|
192
327
|
|
193
|
-
# generate_AssetResource_property(asset, package_name, prior_asset_type) -> string
|
328
|
+
# generate_AssetResource_property(asset, asset_id_dict, package_name, is_package_project_type, prior_asset_type) -> string
|
194
329
|
#
|
195
330
|
# 为当前 asset 生成 AssetResource property 的代码
|
196
331
|
#
|
197
|
-
def self.generate_AssetResource_property(asset, package_name, prior_asset_type = ".*")
|
198
|
-
|
199
|
-
asset_id = generate_asset_id(asset, prior_asset_type)
|
332
|
+
def self.generate_AssetResource_property(asset, asset_id_dict, package_name, is_package_project_type, prior_asset_type = ".*")
|
333
|
+
asset_id = asset_id_dict[asset]
|
200
334
|
asset_comment = generate_asset_comment(asset, package_name)
|
201
335
|
|
202
|
-
asset_name =
|
203
|
-
|
336
|
+
asset_name = ""
|
337
|
+
needPackage = false
|
338
|
+
|
339
|
+
packages_prefix = "packages/#{package_name}/"
|
340
|
+
if asset =~ /\A#{packages_prefix}/
|
341
|
+
# asset: packages/flutter_r_demo/assets/images/test.png
|
342
|
+
# to get asset_name: assets/images/test.png
|
343
|
+
asset_name = asset.dup
|
344
|
+
asset_name[packages_prefix] = ""
|
345
|
+
|
346
|
+
needPackage = true
|
347
|
+
else
|
348
|
+
# asset: assets/images/test.png
|
349
|
+
# to get asset_name: assets/images/test.png
|
350
|
+
asset_name = asset.dup
|
351
|
+
|
352
|
+
if is_package_project_type
|
353
|
+
needPackage = true
|
354
|
+
else
|
355
|
+
needPackage = false
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
359
|
+
|
204
360
|
# 对字符串中的 '$' 进行转义处理:'$' -> '\$'
|
361
|
+
# asset_name: assets/images/test$.png
|
362
|
+
# to get escaped_asset_name: assets/images/test\$.png
|
205
363
|
escaped_asset_name = asset_name.gsub(/[$]/, "\\$")
|
206
364
|
|
207
|
-
|
365
|
+
if needPackage
|
366
|
+
code = <<-CODE
|
208
367
|
/// #{asset_comment}
|
209
368
|
// ignore: non_constant_identifier_names
|
210
369
|
final #{asset_id} = const AssetResource("#{escaped_asset_name}", packageName: R.package);
|
211
|
-
|
370
|
+
CODE
|
212
371
|
|
213
|
-
|
372
|
+
return code
|
373
|
+
else
|
374
|
+
code = <<-CODE
|
375
|
+
/// #{asset_comment}
|
376
|
+
// ignore: non_constant_identifier_names
|
377
|
+
final #{asset_id} = const AssetResource("#{escaped_asset_name}", packageName: null);
|
378
|
+
CODE
|
379
|
+
|
380
|
+
return code
|
381
|
+
end
|
214
382
|
end
|
215
383
|
|
216
|
-
# generate__R_Image_AssetResource_class(non_svg_image_asset_array, package_name) -> string
|
384
|
+
# generate__R_Image_AssetResource_class(non_svg_image_asset_array, non_svg_image_asset_id_dict, package_name, is_package_project_type) -> string
|
217
385
|
#
|
218
386
|
# 根据模板,为 non_svg_image_asset_array(非svg类的图片资产数组)生成 _R_Image_AssetResource class 的代码
|
219
387
|
#
|
220
|
-
def self.generate__R_Image_AssetResource_class(non_svg_image_asset_array, package_name)
|
388
|
+
def self.generate__R_Image_AssetResource_class(non_svg_image_asset_array, non_svg_image_asset_id_dict, package_name, is_package_project_type)
|
221
389
|
|
222
390
|
all_g_AssetResource_property_code = ""
|
223
391
|
|
224
392
|
non_svg_image_asset_array.each do |image_asset|
|
225
393
|
all_g_AssetResource_property_code += "\n"
|
226
|
-
g_AssetResource_property_code = generate_AssetResource_property(image_asset, package_name, Flr::PRIOR_NON_SVG_IMAGE_FILE_TYPE)
|
394
|
+
g_AssetResource_property_code = generate_AssetResource_property(image_asset, non_svg_image_asset_id_dict, package_name, is_package_project_type, Flr::PRIOR_NON_SVG_IMAGE_FILE_TYPE)
|
227
395
|
all_g_AssetResource_property_code += g_AssetResource_property_code
|
228
396
|
end
|
229
397
|
|
@@ -238,17 +406,17 @@ class _R_Image_AssetResource {
|
|
238
406
|
return code
|
239
407
|
end
|
240
408
|
|
241
|
-
# generate__R_Svg_AssetResource_class(
|
409
|
+
# generate__R_Svg_AssetResource_class(svg_image_asset_array, svg_image_asset_id_dict, package_name, is_package_project_type) -> string
|
242
410
|
#
|
243
411
|
# 根据模板,为 svg_image_asset_array(svg类的图片资产数组)生成 _R_Svg_AssetResource class 的代码
|
244
412
|
#
|
245
|
-
def self.generate__R_Svg_AssetResource_class(svg_image_asset_array, package_name)
|
413
|
+
def self.generate__R_Svg_AssetResource_class(svg_image_asset_array, svg_image_asset_id_dict, package_name, is_package_project_type)
|
246
414
|
|
247
415
|
all_g_AssetResource_property_code = ""
|
248
416
|
|
249
417
|
svg_image_asset_array.each do |image_asset|
|
250
418
|
all_g_AssetResource_property_code += "\n"
|
251
|
-
g_AssetResource_property_code = generate_AssetResource_property(image_asset, package_name, Flr::PRIOR_SVG_IMAGE_FILE_TYPE)
|
419
|
+
g_AssetResource_property_code = generate_AssetResource_property(image_asset, svg_image_asset_id_dict, package_name, is_package_project_type, Flr::PRIOR_SVG_IMAGE_FILE_TYPE)
|
252
420
|
all_g_AssetResource_property_code += g_AssetResource_property_code
|
253
421
|
end
|
254
422
|
|
@@ -263,17 +431,17 @@ class _R_Svg_AssetResource {
|
|
263
431
|
return code
|
264
432
|
end
|
265
433
|
|
266
|
-
# generate__R_Text_AssetResource_class(text_asset_array, package_name) -> string
|
434
|
+
# generate__R_Text_AssetResource_class(text_asset_array, text_asset_id_dict, package_name, is_package_project_typ) -> string
|
267
435
|
#
|
268
436
|
# 根据模板,为 text_asset_array(文本资产数组)生成 _R_Text_AssetResource class 的代码
|
269
437
|
#
|
270
|
-
def self.generate__R_Text_AssetResource_class(text_asset_array, package_name)
|
438
|
+
def self.generate__R_Text_AssetResource_class(text_asset_array, text_asset_id_dict, package_name, is_package_project_type)
|
271
439
|
|
272
440
|
all_g_AssetResource_property_code = ""
|
273
441
|
|
274
442
|
text_asset_array.each do |text_asset|
|
275
443
|
all_g_AssetResource_property_code += "\n"
|
276
|
-
g_AssetResource_property_code = generate_AssetResource_property(text_asset, package_name, Flr::PRIOR_TEXT_FILE_TYPE)
|
444
|
+
g_AssetResource_property_code = generate_AssetResource_property(text_asset, text_asset_id_dict, package_name, is_package_project_type, Flr::PRIOR_TEXT_FILE_TYPE)
|
277
445
|
all_g_AssetResource_property_code += g_AssetResource_property_code
|
278
446
|
end
|
279
447
|
|
@@ -288,18 +456,18 @@ class _R_Text_AssetResource {
|
|
288
456
|
return code
|
289
457
|
end
|
290
458
|
|
291
|
-
# generate__R_Image_class(non_svg_image_asset_array, package_name) -> string
|
459
|
+
# generate__R_Image_class(non_svg_image_asset_array, non_svg_image_asset_id_dict, package_name) -> string
|
292
460
|
#
|
293
461
|
# 根据模板,为 non_svg_image_asset_array(非svg类的图片资产数组)生成 _R_Image class 的代码
|
294
462
|
#
|
295
|
-
def self.generate__R_Image_class(non_svg_image_asset_array, package_name)
|
463
|
+
def self.generate__R_Image_class(non_svg_image_asset_array, non_svg_image_asset_id_dict, package_name)
|
296
464
|
|
297
465
|
all_g_Asset_method_code = ""
|
298
466
|
|
299
467
|
non_svg_image_asset_array.each do |image_asset|
|
300
468
|
all_g_Asset_method_code += "\n"
|
301
469
|
|
302
|
-
asset_id =
|
470
|
+
asset_id = non_svg_image_asset_id_dict[image_asset]
|
303
471
|
asset_comment = generate_asset_comment(image_asset, package_name)
|
304
472
|
|
305
473
|
g_Asset_method_code = <<-CODE
|
@@ -327,28 +495,39 @@ class _R_Image {
|
|
327
495
|
return code
|
328
496
|
end
|
329
497
|
|
330
|
-
# generate__R_Svg_class(
|
498
|
+
# generate__R_Svg_class(svg_image_asset_array, svg_image_asset_id_dict, package_name) -> string
|
331
499
|
#
|
332
500
|
# 根据模板,为 svg_image_asset_array(svg类的图片资产数组)生成 _R_Svg class 的代码
|
333
501
|
#
|
334
|
-
def self.generate__R_Svg_class(svg_image_asset_array, package_name)
|
502
|
+
def self.generate__R_Svg_class(svg_image_asset_array, svg_image_asset_id_dict, package_name)
|
335
503
|
|
336
504
|
all_g_Asset_method_code = ""
|
337
505
|
|
338
506
|
svg_image_asset_array.each do |image_asset|
|
339
507
|
all_g_Asset_method_code += "\n"
|
340
508
|
|
341
|
-
asset_id =
|
509
|
+
asset_id = svg_image_asset_id_dict[image_asset]
|
342
510
|
asset_comment = generate_asset_comment(image_asset, package_name)
|
343
511
|
|
344
|
-
|
512
|
+
if should_support_nullsafety
|
513
|
+
g_Asset_method_code = <<-CODE
|
514
|
+
/// #{asset_comment}
|
515
|
+
// ignore: non_constant_identifier_names
|
516
|
+
AssetSvg #{asset_id}({required double width, required double height}) {
|
517
|
+
final imageProvider = AssetSvg(asset.#{asset_id}.keyName, width: width, height: height);
|
518
|
+
return imageProvider;
|
519
|
+
}
|
520
|
+
CODE
|
521
|
+
else
|
522
|
+
g_Asset_method_code = <<-CODE
|
345
523
|
/// #{asset_comment}
|
346
524
|
// ignore: non_constant_identifier_names
|
347
525
|
AssetSvg #{asset_id}({@required double width, @required double height}) {
|
348
526
|
final imageProvider = AssetSvg(asset.#{asset_id}.keyName, width: width, height: height);
|
349
527
|
return imageProvider;
|
350
528
|
}
|
351
|
-
|
529
|
+
CODE
|
530
|
+
end
|
352
531
|
|
353
532
|
all_g_Asset_method_code += g_Asset_method_code
|
354
533
|
end
|
@@ -367,18 +546,18 @@ class _R_Svg {
|
|
367
546
|
return code
|
368
547
|
end
|
369
548
|
|
370
|
-
# generate__R_Text_class(text_asset_array, package_name) -> string
|
549
|
+
# generate__R_Text_class(text_asset_array, text_asset_id_dict, package_name) -> string
|
371
550
|
#
|
372
551
|
# 根据模板,为 text_asset_array(文本资产数组)生成 _R_Text class 的代码
|
373
552
|
#
|
374
|
-
def self.generate__R_Text_class(text_asset_array, package_name)
|
553
|
+
def self.generate__R_Text_class(text_asset_array, text_asset_id_dict, package_name)
|
375
554
|
|
376
555
|
all_g_Asset_method_code = ""
|
377
556
|
|
378
557
|
text_asset_array.each do |text_asset|
|
379
558
|
all_g_Asset_method_code += "\n"
|
380
559
|
|
381
|
-
asset_id =
|
560
|
+
asset_id = text_asset_id_dict[text_asset]
|
382
561
|
asset_comment = generate_asset_comment(text_asset, package_name)
|
383
562
|
|
384
563
|
g_Asset_method_code = <<-CODE
|