forked from sproutit/sproutcore-abbot
-
Notifications
You must be signed in to change notification settings - Fork 1
/
entry_sorter.rb
139 lines (113 loc) · 4.5 KB
/
entry_sorter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# ===========================================================================
# Project: Abbot - SproutCore Build Tools
# Copyright: ©2009 Apple Inc.
# portions copyright @2006-2009 Sprout Systems, Inc.
# and contributors
# ===========================================================================
module SC
module Helpers
# Sorts a set of entries, respecting any "requires" found in the entries.
# To use the sorter, just call the class method EntrySorter.sort() passing
# the entries to sort along with any filenames you prefer to have added to
# the top. If you don't specify any filenames, then the entries will be
# sorted alphabetically except for requires.
#
# When bundle_info.js is present, it will always be sorted first.
# When bundle_loaded.js is present, it will always be sorted last.
class EntrySorter
def self.sort(entries, preferred_filenames = [])
self.new(preferred_filenames).sort(entries)
end
def initialize(preferred_filenames = [])
@preferred_filenames = preferred_filenames
end
attr_reader :preferred_filenames
def sort(entries)
bundleInfoEntry = []
bundleLoadedEntry = []
# first remove bundle entries which MUST be first or last
entries = entries.select do |entry|
if entry.filename == 'bundle_info.js'
bundleInfoEntry = [entry]
false
elsif entry.filename == 'bundle_loaded.js'
bundleLoadedEntry = [entry]
false
else
true
end
end
# then sort remaining entries by filename - ignoring case
entries = entries.sort do |a,b|
a = (a.filename || '').to_s.downcase
b = (b.filename || '').to_s.downcase
# lproj/foo_page.js and main.js are loaded last
a_kind = (a =~ /lproj\/.+_page\.js$/) ? 1 : -1
a_kind = 2 if a =~ /main.js$/
b_kind = (b =~ /lproj\/.+_page\.js$/) ? 1 : -1
b_kind = 2 if b =~ /main.js$/
if a_kind != b_kind
a_kind <=> b_kind
else
a <=> b
end
end
all_entries = entries.dup # needed for sort...
# now process each entry to handle requires
seen = []
ret = []
while cur = next_entry(entries)
add_entry_to_set(cur, ret, seen, entries, all_entries)
end
return bundleInfoEntry + ret + bundleLoadedEntry
end
protected
# Converts a passed set of requires into entries
def required_entries(required, entries, requiring_entry, all_entries)
return [] if required.nil?
required.map do |filename|
filename = filename.to_s.downcase.ext('')
source_filename = "source/#{filename}"
entry = all_entries.find do |e|
e.filename.to_s.downcase.ext('') == source_filename
end
# try localized version...
if entry.nil? && !(filename =~ /^lproj\//)
source_filename = "source/lproj/#{filename}"
entry = all_entries.find do |e|
e.filename.to_s.downcase.ext('') == source_filename
end
end
if entry.nil?
SC.logger.warn "Could not find entry '#{filename}' required in #{requiring_entry.target.target_name.to_s.sub(/^\//,'')}:#{requiring_entry.filename}"
end
entry
end
end
# Returns the next entry from the set of entries based on required order.
# Removed entry from array.
def next_entry(entries)
ret = nil
# look for preferred entries first...
@preferred_filenames.each do |filename|
ret = entries.find { |e| e.filename.to_s.downcase == filename }
break if ret
end
ret ||= entries.first # else fallback to first entry in set
entries.delete(ret) if ret
return ret
end
# Adds the specified entry to the ordered array, adding required first
def add_entry_to_set(entry, ret, seen, entries, all_entries)
return if seen.include?(entry)
seen << entry
req = required_entries(entry.required, entries, entry, all_entries)
req.each do |required|
next if required.nil?
add_entry_to_set(required, ret, seen, entries, all_entries)
end
ret << entry
end
end
end
end