1 |
b590eaa2
|
Wojtek Kosior
|
#!/usr/bin/awk -f
|
2 |
|
|
#
|
3 |
6106c789
|
Wojtek Kosior
|
# SPDX-License-Identifier: CC0-1.0
|
4 |
|
|
#
|
5 |
|
|
# Process javascript files and resolve dependencies between them
|
6 |
|
|
#
|
7 |
|
|
# This file is part of Haketilo
|
8 |
|
|
#
|
9 |
|
|
# Copyright (C) 2021, Wojtek Kosior
|
10 |
|
|
#
|
11 |
|
|
# This program is free software: you can redistribute it and/or modify
|
12 |
|
|
# it under the terms of the CC0 1.0 Universal License as published by
|
13 |
|
|
# the Creative Commons Corporation.
|
14 |
|
|
#
|
15 |
|
|
# This program is distributed in the hope that it will be useful,
|
16 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18 |
|
|
# CC0 1.0 Universal License for more details.
|
19 |
|
|
|
20 |
b590eaa2
|
Wojtek Kosior
|
BEGIN {
|
21 |
|
|
true = 1
|
22 |
|
|
false = 0
|
23 |
|
|
}
|
24 |
|
|
|
25 |
|
|
BEGIN {
|
26 |
c71ebff8
|
Wojtek Kosior
|
identifier_re = "[_a-zA-Z][_a-zA-Z0-9]*"
|
27 |
|
|
path_dir_re = "([-_a-zA-Z0-9][-._a-zA-Z0-9]*/)*"
|
28 |
|
|
path_ext_re = "(\\.[-_.a-zA-Z0-9]*)?"
|
29 |
|
|
path_re_noanchor = path_dir_re identifier_re path_ext_re
|
30 |
|
|
path_re = "^" path_re_noanchor "$"
|
31 |
b590eaa2
|
Wojtek Kosior
|
|
32 |
702eefd2
|
Wojtek Kosior
|
if_clause_re = "!?" identifier_re
|
33 |
|
|
if_AND_re = "([[:space:]]+&&[[:space:]]+" if_clause_re ")*"
|
34 |
|
|
if_OR_re = "([[:space:]]+[|][|][[:space:]]+" if_clause_re ")*"
|
35 |
|
|
|
36 |
|
|
directive_args_patterns["IF"] = ("^" if_clause_re \
|
37 |
|
|
"(" if_AND_re "|" if_OR_re ")$")
|
38 |
b590eaa2
|
Wojtek Kosior
|
directive_args_patterns["ENDIF"] = "^$"
|
39 |
|
|
directive_args_patterns["ELSE"] = "^$"
|
40 |
|
|
directive_args_patterns["ELIF"] = "^(NOT[[:space:]]+)?" identifier_re "$"
|
41 |
448820a1
|
Wojtek Kosior
|
directive_args_patterns["DEFINE"] = "^" identifier_re "$"
|
42 |
|
|
directive_args_patterns["UNDEF"] = "^" identifier_re "$"
|
43 |
b590eaa2
|
Wojtek Kosior
|
directive_args_patterns["ERROR"] = "^.*$"
|
44 |
|
|
directive_args_patterns["COPY"] = "^[^[:space:]]+$"
|
45 |
|
|
directive_args_patterns["INCLUDE"] = "^[^[:space:]]+$"
|
46 |
|
|
directive_args_patterns["INCLUDE_VERBATIM"] = "^[^[:space:]]+$"
|
47 |
|
|
|
48 |
|
|
AS_re = "AS[[:space:]]+" identifier_re
|
49 |
|
|
maybe_AS_re = "([[:space:]]+" AS_re ")?"
|
50 |
|
|
FROM_clause_re = identifier_re maybe_AS_re
|
51 |
|
|
more_FROM_clauses_re = "([[:space:]]*,[[:space:]]*" FROM_clause_re ")*"
|
52 |
|
|
FROM_IMPORT_re = "[^[:space:]]+[[:space:]]+IMPORT[[:space:]]+"
|
53 |
|
|
EXPORT_AS_re = ".*[^[:space:]][[:space:]]+" AS_re
|
54 |
|
|
|
55 |
|
|
directive_args_patterns["IMPORT"] = "^[^[:space:]]+" maybe_AS_re "$"
|
56 |
|
|
directive_args_patterns["FROM"] = ("^" FROM_IMPORT_re FROM_clause_re \
|
57 |
|
|
more_FROM_clauses_re "$")
|
58 |
|
|
directive_args_patterns["EXPORT"] = "^(" EXPORT_AS_re "|" identifier_re ")$"
|
59 |
|
|
|
60 |
|
|
directive_args_patterns["LOADJS"] = "^[^[:space:]]+$"
|
61 |
a00926f1
|
Wojtek Kosior
|
directive_args_patterns["LOADCSS"] = "^[^[:space:]]+$"
|
62 |
448820a1
|
Wojtek Kosior
|
|
63 |
|
|
directive_args_patterns["LOADHTML"] = "^[^[:space:]]+$"
|
64 |
b590eaa2
|
Wojtek Kosior
|
}
|
65 |
|
|
|
66 |
|
|
function validate_path(read_path, path, line) {
|
67 |
|
|
if (path !~ (path_re)) {
|
68 |
|
|
printf "ERROR: File path in %s does not match '%s': %s\n",
|
69 |
|
|
read_path, path_re, line > "/dev/stderr"
|
70 |
|
|
return 1
|
71 |
|
|
}
|
72 |
|
|
|
73 |
|
|
return 0
|
74 |
|
|
}
|
75 |
|
|
|
76 |
|
|
function identifier_from_path(path) {
|
77 |
|
|
sub("^" path_dir_re, "", path)
|
78 |
|
|
sub(path_ext_re "$", "", path)
|
79 |
|
|
|
80 |
|
|
return path
|
81 |
|
|
}
|
82 |
|
|
|
83 |
|
|
function last_token(line) {
|
84 |
|
|
sub("^.*[[:space:]]", "", line)
|
85 |
|
|
|
86 |
|
|
return line
|
87 |
|
|
}
|
88 |
|
|
|
89 |
|
|
function first_token(line) {
|
90 |
|
|
sub("[[:space:]].*$", "", line)
|
91 |
|
|
|
92 |
|
|
return line
|
93 |
|
|
}
|
94 |
|
|
|
95 |
|
|
function is_empty(array, key) {
|
96 |
|
|
for (key in array)
|
97 |
|
|
return false
|
98 |
|
|
return true
|
99 |
|
|
}
|
100 |
6106c789
|
Wojtek Kosior
|
|
101 |
b590eaa2
|
Wojtek Kosior
|
function clear_array(array, key) {
|
102 |
|
|
for (key in array)
|
103 |
|
|
delete array[key]
|
104 |
|
|
}
|
105 |
|
|
|
106 |
|
|
function add_line(path, line, where) {
|
107 |
|
|
if (where != "amalgamation_root_file")
|
108 |
|
|
lines[path,++lines_count[path]] = line
|
109 |
|
|
|
110 |
|
|
if (where != "non_amalgamation_file" &&
|
111 |
|
|
path == js_to_amalgamate)
|
112 |
|
|
main_js_lines[++main_js_lines_count] = line
|
113 |
|
|
}
|
114 |
|
|
|
115 |
|
|
BEGIN {
|
116 |
|
|
delete page_js_deps[0]
|
117 |
|
|
page_js_deps_count = 0
|
118 |
|
|
}
|
119 |
|
|
|
120 |
|
|
function process_file(path, read_path, mode,
|
121 |
|
|
line, result, line_part, directive, directive_args,
|
122 |
5acb2499
|
Wojtek Kosior
|
if_nesting, if_nesting_true, if_branch_processed) {
|
123 |
b590eaa2
|
Wojtek Kosior
|
if (path in modes && modes[path] != mode) {
|
124 |
|
|
printf "ERROR: File %s used multiple times in different contexts\n",
|
125 |
|
|
path > "/dev/stderr"
|
126 |
|
|
return 1
|
127 |
|
|
}
|
128 |
|
|
|
129 |
|
|
if (mode == "html" && path == read_path) {
|
130 |
|
|
clear_array(page_js_deps)
|
131 |
|
|
page_js_deps_count = 0
|
132 |
a00926f1
|
Wojtek Kosior
|
clear_array(page_css_deps)
|
133 |
b590eaa2
|
Wojtek Kosior
|
}
|
134 |
|
|
|
135 |
|
|
modes[path] = mode
|
136 |
|
|
|
137 |
|
|
if (!(path in reading)) {
|
138 |
|
|
if (path in lines_count)
|
139 |
|
|
return 0
|
140 |
|
|
lines_count[path]
|
141 |
|
|
}
|
142 |
|
|
|
143 |
|
|
reading[read_path]
|
144 |
|
|
|
145 |
|
|
if (mode == "js" && path == read_path) {
|
146 |
|
|
add_line(path, "\"use strict\";")
|
147 |
|
|
add_line(path, "this.haketilo_exports = this.haketilo_exports || {};")
|
148 |
|
|
add_line(path, "this.haketilo_exports[\"" path "\"] = {};")
|
149 |
|
|
|
150 |
|
|
add_line(path, "window.globalThis = this", "amalgamation_root_file")
|
151 |
|
|
|
152 |
|
|
add_line(path, "")
|
153 |
|
|
|
154 |
|
|
add_line(path, "(function() {", "non_amalgamation_file")
|
155 |
|
|
add_line(path, "var globalThis = this.haketilo_this",
|
156 |
|
|
"non_amalgamation_file")
|
157 |
|
|
add_line(path, "{", "non_amalgamation_file")
|
158 |
|
|
}
|
159 |
|
|
|
160 |
|
|
while (true) {
|
161 |
|
|
result = (getline line < read_path)
|
162 |
6106c789
|
Wojtek Kosior
|
if (result < 0) {
|
163 |
b590eaa2
|
Wojtek Kosior
|
printf "ERROR: Could not read %s\n", read_path > "/dev/stderr"
|
164 |
|
|
return 1
|
165 |
6106c789
|
Wojtek Kosior
|
}
|
166 |
01e977f9
|
Wojtek Kosior
|
if (result == 0) {
|
167 |
c71ebff8
|
Wojtek Kosior
|
if (!(path in appended_lines_counts) || \
|
168 |
5acb2499
|
Wojtek Kosior
|
additional_line_nr[path] == appended_lines_counts[path])
|
169 |
01e977f9
|
Wojtek Kosior
|
break
|
170 |
|
|
|
171 |
5acb2499
|
Wojtek Kosior
|
line = appended_lines[path,++additional_line_nr[path]]
|
172 |
01e977f9
|
Wojtek Kosior
|
}
|
173 |
6106c789
|
Wojtek Kosior
|
|
174 |
b590eaa2
|
Wojtek Kosior
|
if (line !~ /^#/) {
|
175 |
|
|
if (if_nesting_true == if_nesting)
|
176 |
|
|
add_line(path, line)
|
177 |
|
|
continue
|
178 |
|
|
}
|
179 |
6106c789
|
Wojtek Kosior
|
|
180 |
b590eaa2
|
Wojtek Kosior
|
while (line ~ /\\$/) {
|
181 |
|
|
sub(/\\$/, "", line)
|
182 |
6106c789
|
Wojtek Kosior
|
|
183 |
b590eaa2
|
Wojtek Kosior
|
result = (getline line_part < read_path)
|
184 |
|
|
if (result < 0) {
|
185 |
|
|
printf "ERROR: Could not read %s\n", read_path > "/dev/stderr"
|
186 |
|
|
return 1
|
187 |
|
|
}
|
188 |
|
|
if (result == 0) {
|
189 |
c71ebff8
|
Wojtek Kosior
|
if (path in appended_lines_counts && \
|
190 |
5acb2499
|
Wojtek Kosior
|
additional_line_nr[path] < appended_lines_counts[path]) {
|
191 |
|
|
line_part = appended_lines[path,++additional_line_nr[path]]
|
192 |
01e977f9
|
Wojtek Kosior
|
} else {
|
193 |
|
|
printf "ERROR: Unexpected EOF in %s\n",
|
194 |
|
|
read_path > "/dev/stderr"
|
195 |
|
|
return 1
|
196 |
|
|
}
|
197 |
b590eaa2
|
Wojtek Kosior
|
}
|
198 |
|
|
|
199 |
|
|
line = line " " line_part
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
directive = substr(line, 2)
|
203 |
|
|
sub(/[[:space:]].*$/, "", directive)
|
204 |
|
|
|
205 |
|
|
if (directive !~ \
|
206 |
448820a1
|
Wojtek Kosior
|
/^(IF|ENDIF|ELSE|ELIF|DEFINE|UNDEF|ERROR|INCLUDE|INCLUDE_VERBATIM|COPY_FILE)$/ &&
|
207 |
b590eaa2
|
Wojtek Kosior
|
(mode != "js" || directive !~ /^(IMPORT|FROM|EXPORT)$/) &&
|
208 |
a00926f1
|
Wojtek Kosior
|
(mode != "html" || directive !~ /^(LOADJS|LOADCSS)$/) &&
|
209 |
b590eaa2
|
Wojtek Kosior
|
(mode != "manifest" || directive !~ /^(LOADJS|LOADHTML)$/)) {
|
210 |
|
|
printf "ERROR: Invalid # directive in %s: %s\n",
|
211 |
|
|
read_path, line > "/dev/stderr"
|
212 |
|
|
return 1
|
213 |
|
|
}
|
214 |
|
|
|
215 |
|
|
directive_args = line
|
216 |
|
|
sub(/^#[^[:space:]]*[[:space:]]*/, "", directive_args)
|
217 |
|
|
sub(/[[:space:]]*$/, "", directive_args)
|
218 |
|
|
|
219 |
|
|
if (directive_args !~ directive_args_patterns[directive]) {
|
220 |
|
|
printf "ERROR: #%s arguments in %s do not match '%s': %s\n",
|
221 |
|
|
directive, read_path, directive_args_patterns[directive], line \
|
222 |
|
|
> "/dev/stderr"
|
223 |
|
|
return 1
|
224 |
6106c789
|
Wojtek Kosior
|
}
|
225 |
b590eaa2
|
Wojtek Kosior
|
|
226 |
|
|
if (directive == "IF") {
|
227 |
|
|
if (if_nesting_true == if_nesting) {
|
228 |
448820a1
|
Wojtek Kosior
|
if (if_condition_true(directive_args, path))
|
229 |
b590eaa2
|
Wojtek Kosior
|
if_nesting_true++
|
230 |
|
|
else
|
231 |
|
|
if_branch_processed = false
|
232 |
6106c789
|
Wojtek Kosior
|
}
|
233 |
|
|
|
234 |
b590eaa2
|
Wojtek Kosior
|
if_nesting++
|
235 |
|
|
} else if (directive == "ENDIF") {
|
236 |
|
|
if (if_nesting == 0) {
|
237 |
|
|
printf "ERROR: Spurious #ENDIF in %s\n",
|
238 |
|
|
read_path > "/dev/stderr"
|
239 |
|
|
return 1
|
240 |
|
|
}
|
241 |
|
|
|
242 |
|
|
if (if_nesting_true == if_nesting)
|
243 |
|
|
if_nesting_true--
|
244 |
|
|
|
245 |
|
|
if_nesting--
|
246 |
|
|
} else if (directive == "ELSE") {
|
247 |
|
|
if (if_nesting == 0) {
|
248 |
|
|
printf "ERROR: Spurious #ELSE in %s\n",
|
249 |
|
|
read_path > "/dev/stderr"
|
250 |
|
|
return 1
|
251 |
|
|
}
|
252 |
|
|
|
253 |
|
|
if (if_nesting == if_nesting_true + 1 && !if_branch_processed) {
|
254 |
|
|
if_nesting_true++
|
255 |
|
|
} else if (if_nesting == if_nesting_true) {
|
256 |
|
|
if_branch_processed = true
|
257 |
|
|
if_nesting_true--
|
258 |
|
|
}
|
259 |
|
|
} else if (directive == "ELIF") {
|
260 |
|
|
if (if_nesting == 0) {
|
261 |
|
|
printf "ERROR: Spurious #ELIF in %s\n",
|
262 |
|
|
read_path > "/dev/stderr"
|
263 |
|
|
return 1
|
264 |
|
|
}
|
265 |
|
|
|
266 |
|
|
if (if_nesting == if_nesting_true + 1 && !if_branch_processed &&
|
267 |
448820a1
|
Wojtek Kosior
|
if_condition_true(directive_args, path)) {
|
268 |
b590eaa2
|
Wojtek Kosior
|
if_nesting_true++
|
269 |
|
|
} else if (if_nesting == if_nesting_true) {
|
270 |
|
|
if_branch_processed = true
|
271 |
|
|
if_nesting_true--
|
272 |
|
|
}
|
273 |
|
|
} else if (if_nesting_true != if_nesting) {
|
274 |
|
|
continue
|
275 |
448820a1
|
Wojtek Kosior
|
} else if (directive == "DEFINE") {
|
276 |
|
|
defines[path,directive_args]
|
277 |
|
|
} else if (directive == "UNDEF") {
|
278 |
|
|
delete defines[path,directive_args]
|
279 |
b590eaa2
|
Wojtek Kosior
|
} else if (directive == "ERROR") {
|
280 |
|
|
printf "ERROR: File %s says: %s\n",
|
281 |
|
|
read_path, directive_args > "/dev/stderr"
|
282 |
|
|
return 1
|
283 |
|
|
} else if (directive == "INCLUDE") {
|
284 |
|
|
if (include_file(path, read_path, directive_args, line))
|
285 |
|
|
return 1
|
286 |
|
|
} else if (directive == "INCLUDE_VERBATIM") {
|
287 |
|
|
if (include_file(path, read_path, directive_args, line, true))
|
288 |
|
|
return 1
|
289 |
|
|
} else if (directive == "COPY_FILE") {
|
290 |
|
|
if (mark_copy_file(path, read_path, directive_args, line))
|
291 |
|
|
return 1
|
292 |
|
|
} else if (directive == "IMPORT") {
|
293 |
|
|
if (import_js_file(path, read_path, directive_args, line))
|
294 |
|
|
return 1
|
295 |
|
|
} else if (directive == "FROM") {
|
296 |
|
|
if (import_from_js_file(path, read_path, directive_args, line))
|
297 |
|
|
return 1
|
298 |
|
|
} else if (directive == "EXPORT") {
|
299 |
|
|
if (export_from_js_file(path, read_path, directive_args, line))
|
300 |
|
|
return 1
|
301 |
|
|
} else if (directive == "LOADJS") {
|
302 |
|
|
if (mode == "html") {
|
303 |
|
|
page_js_deps_count = \
|
304 |
|
|
load_js_file(path, read_path, directive_args, line,
|
305 |
|
|
page_js_deps, page_js_deps_count)
|
306 |
|
|
if (page_js_deps_count < 1)
|
307 |
|
|
return 1
|
308 |
|
|
} else if (mode == "manifest") {
|
309 |
|
|
if (load_js_file(path, read_path, directive_args, line) < 1)
|
310 |
|
|
return 1
|
311 |
|
|
}
|
312 |
a00926f1
|
Wojtek Kosior
|
} else if (directive == "LOADCSS") {
|
313 |
|
|
if (load_css_file(path, read_path, directive_args, line,
|
314 |
|
|
page_css_deps))
|
315 |
|
|
return 1
|
316 |
b590eaa2
|
Wojtek Kosior
|
} else if (directive == "LOADHTML") {
|
317 |
|
|
if (load_html_file(path, read_path, directive_args, line))
|
318 |
|
|
return 1
|
319 |
6106c789
|
Wojtek Kosior
|
}
|
320 |
b590eaa2
|
Wojtek Kosior
|
}
|
321 |
|
|
|
322 |
|
|
close(read_path)
|
323 |
6106c789
|
Wojtek Kosior
|
|
324 |
b590eaa2
|
Wojtek Kosior
|
if (if_nesting) {
|
325 |
|
|
printf "ERROR: Unterminated #IF in %s\n", read_path > "/dev/stderr"
|
326 |
|
|
return 1
|
327 |
6106c789
|
Wojtek Kosior
|
}
|
328 |
|
|
|
329 |
b590eaa2
|
Wojtek Kosior
|
if (mode == "js" && path == read_path) {
|
330 |
|
|
add_line(path, "}", "non_amalgamation_file")
|
331 |
|
|
add_line(path, "}).call({", "non_amalgamation_file")
|
332 |
|
|
add_line(path, " haketilo_exports: this.haketilo_exports,",
|
333 |
|
|
"non_amalgamation_file")
|
334 |
|
|
add_line(path, " haketilo_this: this",
|
335 |
|
|
"non_amalgamation_file")
|
336 |
|
|
add_line(path, "});", "non_amalgamation_file")
|
337 |
6106c789
|
Wojtek Kosior
|
}
|
338 |
|
|
|
339 |
b590eaa2
|
Wojtek Kosior
|
delete reading[read_path]
|
340 |
6106c789
|
Wojtek Kosior
|
}
|
341 |
|
|
|
342 |
448820a1
|
Wojtek Kosior
|
function if_condition_true(directive_args, path,
|
343 |
702eefd2
|
Wojtek Kosior
|
result, bool, first_iter, word, negated, alt) {
|
344 |
|
|
first_iter = true
|
345 |
|
|
|
346 |
|
|
while (directive_args) {
|
347 |
|
|
word = first_token(directive_args)
|
348 |
|
|
sub(/^[^[:space:]]+[[:space:]]*/, "", directive_args)
|
349 |
|
|
alt = alt || directive_args ~ /^[|][|]/
|
350 |
|
|
sub(/^[^[:space:]]+[[:space:]]*/, "", directive_args)
|
351 |
|
|
|
352 |
|
|
negated = word ~ /^!/
|
353 |
|
|
sub(/^!/, "", word)
|
354 |
448820a1
|
Wojtek Kosior
|
bool = (word in defines || (path,word) in defines) != negated
|
355 |
702eefd2
|
Wojtek Kosior
|
|
356 |
|
|
if (first_iter) {
|
357 |
|
|
result = bool
|
358 |
|
|
first_iter = false
|
359 |
|
|
continue
|
360 |
|
|
}
|
361 |
|
|
|
362 |
|
|
if (alt)
|
363 |
|
|
result = result || bool
|
364 |
|
|
else # if (directive_args ~ /^AND/)
|
365 |
|
|
result = result && bool
|
366 |
|
|
}
|
367 |
|
|
|
368 |
|
|
return result
|
369 |
|
|
}
|
370 |
|
|
|
371 |
b590eaa2
|
Wojtek Kosior
|
function include_file(root_path, read_path, included_path, line, verbatim,
|
372 |
|
|
read_line, result) {
|
373 |
|
|
if (included_path in reading) {
|
374 |
|
|
printf "ERROR: Inclusion loop when including %s in %s\n",
|
375 |
|
|
included_path, read_path > "/dev/stderr"
|
376 |
|
|
return 1
|
377 |
|
|
}
|
378 |
|
|
|
379 |
|
|
if (verbatim) {
|
380 |
|
|
while(true) {
|
381 |
|
|
result = (getline read_line < included_path)
|
382 |
|
|
if (result > 0)
|
383 |
|
|
add_line(root_path, read_line)
|
384 |
|
|
else
|
385 |
|
|
break
|
386 |
|
|
}
|
387 |
|
|
|
388 |
|
|
if (result == 0) {
|
389 |
|
|
close(included_path)
|
390 |
|
|
return 0
|
391 |
|
|
}
|
392 |
6106c789
|
Wojtek Kosior
|
|
393 |
b590eaa2
|
Wojtek Kosior
|
printf "ERROR: Could not read %s\n", included_path > "/dev/stderr"
|
394 |
|
|
} else {
|
395 |
|
|
if (process_file(root_path, included_path, modes[root_path]) == 0)
|
396 |
|
|
return 0
|
397 |
|
|
}
|
398 |
|
|
|
399 |
|
|
printf " when including %s in %s\n",
|
400 |
|
|
included_path, read_path > "/dev/stderr"
|
401 |
|
|
|
402 |
|
|
return 1
|
403 |
6106c789
|
Wojtek Kosior
|
}
|
404 |
|
|
|
405 |
b590eaa2
|
Wojtek Kosior
|
function mark_copy_file(root_path, read_path, copied_path, line) {
|
406 |
|
|
if (validate_path(read_path, copied_path, line))
|
407 |
|
|
return 1
|
408 |
|
|
|
409 |
|
|
to_copy[copied_path]
|
410 |
|
|
|
411 |
|
|
return 0
|
412 |
|
|
}
|
413 |
|
|
|
414 |
|
|
function satisfy_import(root_path, imported_path, as, what,
|
415 |
|
|
added_line, description, count) {
|
416 |
|
|
if ((root_path,as) in imports_from) {
|
417 |
|
|
printf "ERROR: Multiple items imported under the name '%s' in %s\n",
|
418 |
|
|
as, root_path > "/dev/stderr"
|
419 |
|
|
return 1
|
420 |
6106c789
|
Wojtek Kosior
|
}
|
421 |
b590eaa2
|
Wojtek Kosior
|
|
422 |
|
|
added_line = " " as " = haketilo_exports[\"" imported_path "\"]"
|
423 |
|
|
if (what)
|
424 |
|
|
added_line = added_line "." what
|
425 |
|
|
|
426 |
|
|
add_line(root_path, "const" added_line ";", "non_amalgamation_file")
|
427 |
|
|
add_line(root_path, "let" added_line ";", "amalgamation_root_file")
|
428 |
|
|
|
429 |
|
|
count = ++import_counts[root_path]
|
430 |
|
|
|
431 |
|
|
imports_as [root_path,count] = as
|
432 |
|
|
imports_from[root_path,as] = imported_path
|
433 |
|
|
imports_what[root_path,as] = what
|
434 |
|
|
|
435 |
|
|
if (what)
|
436 |
|
|
description = "'" what "' from " imported_path
|
437 |
|
|
else
|
438 |
|
|
description = imported_path
|
439 |
|
|
|
440 |
|
|
description = description " needed by " root_path
|
441 |
|
|
|
442 |
|
|
if (imported_path in reading) {
|
443 |
|
|
printf "ERROR: dependency loop when importing %s\n",
|
444 |
|
|
description > "/dev/stderr"
|
445 |
|
|
return 1
|
446 |
|
|
} else if (process_file(imported_path, imported_path, "js")) {
|
447 |
|
|
printf " when importing %s\n", description > "/dev/stderr"
|
448 |
|
|
return 1
|
449 |
|
|
}
|
450 |
|
|
|
451 |
|
|
if (what && !((imported_path,what) in exports)) {
|
452 |
|
|
printf "ERROR: %s doesn't export '%s' needed by %s\n",
|
453 |
|
|
imported_path, what, root_path > "/dev/stderr"
|
454 |
|
|
return 1
|
455 |
|
|
}
|
456 |
|
|
|
457 |
|
|
return 0
|
458 |
6106c789
|
Wojtek Kosior
|
}
|
459 |
|
|
|
460 |
b590eaa2
|
Wojtek Kosior
|
function import_js_file(root_path, read_path, directive_args, line,
|
461 |
|
|
imported_path, as) {
|
462 |
|
|
imported_path = first_token(directive_args)
|
463 |
|
|
if (validate_path(read_path, imported_path, line))
|
464 |
|
|
return 1
|
465 |
|
|
|
466 |
|
|
if (line ~ (AS_re "$"))
|
467 |
|
|
as = last_token(directive_args)
|
468 |
|
|
else
|
469 |
|
|
as = identifier_from_path(imported_path)
|
470 |
|
|
|
471 |
|
|
return satisfy_import(root_path, imported_path, as)
|
472 |
|
|
}
|
473 |
|
|
|
474 |
|
|
function import_from_js_file(root_path, read_path, directive_args, line,
|
475 |
|
|
imported_path, args_copy, FROM_clause, as) {
|
476 |
|
|
imported_path = first_token(directive_args)
|
477 |
|
|
if (validate_path(read_path, imported_path, line))
|
478 |
|
|
return 1
|
479 |
|
|
|
480 |
|
|
args_copy = directive_args
|
481 |
|
|
sub("^" FROM_IMPORT_re, "", args_copy)
|
482 |
|
|
args_copy = "," args_copy
|
483 |
|
|
|
484 |
|
|
while (args_copy ~ /,/) {
|
485 |
|
|
sub(/^[^,]*,[[:space:]]*/, "", args_copy)
|
486 |
|
|
|
487 |
|
|
FROM_clause = args_copy
|
488 |
|
|
sub(/[[:space:]]*,.*$/, "", FROM_clause)
|
489 |
|
|
|
490 |
|
|
if (satisfy_import(root_path, imported_path,
|
491 |
|
|
last_token(FROM_clause), first_token(FROM_clause)))
|
492 |
|
|
return 1
|
493 |
6106c789
|
Wojtek Kosior
|
}
|
494 |
b590eaa2
|
Wojtek Kosior
|
|
495 |
|
|
return 0
|
496 |
6106c789
|
Wojtek Kosior
|
}
|
497 |
|
|
|
498 |
b590eaa2
|
Wojtek Kosior
|
function export_from_js_file(root_path, read_path, directive_args, line,
|
499 |
|
|
as, exported_item, added_line) {
|
500 |
|
|
as = last_token(directive_args)
|
501 |
|
|
|
502 |
|
|
if (directive_args ~ ("^" identifier_re "$")) {
|
503 |
|
|
exported_item = as
|
504 |
|
|
} else {
|
505 |
|
|
exported_item = directive_args
|
506 |
|
|
sub("[[:space:]]+" AS_re "$", "", exported_item)
|
507 |
|
|
}
|
508 |
|
|
|
509 |
|
|
if ((root_path,as) in exports) {
|
510 |
|
|
printf "ERROR: Multiple values exported under the name '%s' in %s\n",
|
511 |
|
|
as, root_path > "/dev/stderr"
|
512 |
|
|
return 1
|
513 |
|
|
}
|
514 |
9a7623de
|
Wojtek Kosior
|
|
515 |
b590eaa2
|
Wojtek Kosior
|
added_line = \
|
516 |
|
|
"this.haketilo_exports[\"" root_path "\"]." as " = (" exported_item ");"
|
517 |
|
|
add_line(root_path, added_line)
|
518 |
6106c789
|
Wojtek Kosior
|
|
519 |
b590eaa2
|
Wojtek Kosior
|
exports[root_path,as]
|
520 |
6106c789
|
Wojtek Kosior
|
|
521 |
b590eaa2
|
Wojtek Kosior
|
return 0
|
522 |
93dd7360
|
Wojtek Kosior
|
}
|
523 |
|
|
|
524 |
b590eaa2
|
Wojtek Kosior
|
function compute_deps(js_path, dependencies, count, dependencies_added,
|
525 |
|
|
i_max, i, as, next_path) {
|
526 |
|
|
delete dependencies_added[0]
|
527 |
93dd7360
|
Wojtek Kosior
|
|
528 |
b590eaa2
|
Wojtek Kosior
|
if (process_file(js_path, js_path, "js"))
|
529 |
|
|
return 0
|
530 |
93dd7360
|
Wojtek Kosior
|
|
531 |
b590eaa2
|
Wojtek Kosior
|
i_max = import_counts[js_path]
|
532 |
|
|
for (i = 1; i <= i_max; i++) {
|
533 |
|
|
as = imports_as[js_path,i]
|
534 |
|
|
next_path = imports_from[js_path,as]
|
535 |
|
|
if (next_path in dependencies_added)
|
536 |
|
|
continue
|
537 |
|
|
|
538 |
|
|
count = compute_deps(next_path, dependencies, count, dependencies_added)
|
539 |
|
|
if (count < 1)
|
540 |
|
|
return 0
|
541 |
|
|
}
|
542 |
|
|
|
543 |
|
|
dependencies_added[js_path]
|
544 |
|
|
dependencies[++count] = js_path
|
545 |
|
|
|
546 |
|
|
return count
|
547 |
6106c789
|
Wojtek Kosior
|
}
|
548 |
|
|
|
549 |
b590eaa2
|
Wojtek Kosior
|
# Here js_deps and js_deps_count are optional args, used when loading scripts
|
550 |
a00926f1
|
Wojtek Kosior
|
# into an HTML page to avoid having the same script loaded twice in multiple
|
551 |
b590eaa2
|
Wojtek Kosior
|
# places.
|
552 |
|
|
function load_js_file(root_path, read_path, loaded_path, line,
|
553 |
|
|
js_deps, js_deps_count,
|
554 |
|
|
js_deps_already_added, i, added_line) {
|
555 |
|
|
delete js_deps[""]
|
556 |
|
|
delete js_deps_already_added[0]
|
557 |
|
|
|
558 |
|
|
if (validate_path(read_path, loaded_path, line))
|
559 |
6106c789
|
Wojtek Kosior
|
return 0
|
560 |
|
|
|
561 |
b590eaa2
|
Wojtek Kosior
|
for (i = 1; i <= js_deps_count; i++)
|
562 |
|
|
js_deps_already_added[js_deps[i]]
|
563 |
|
|
|
564 |
|
|
i = js_deps_count
|
565 |
|
|
|
566 |
|
|
js_deps_count = compute_deps(loaded_path, js_deps,
|
567 |
|
|
js_deps_count, js_deps_already_added)
|
568 |
|
|
|
569 |
|
|
if (js_deps_count < 1) {
|
570 |
|
|
printf " when loading %s from %s\n",
|
571 |
|
|
loaded_path, read_path > "/dev/stderr"
|
572 |
|
|
return 0
|
573 |
|
|
}
|
574 |
|
|
|
575 |
|
|
while (++i <= js_deps_count) {
|
576 |
|
|
if (modes[root_path] == "html") {
|
577 |
|
|
added_line = "<script src=\"/" js_deps[i] "\"></script>"
|
578 |
|
|
} else { #if (modes[root_path] == "manifest") {
|
579 |
|
|
added_line = "\"" js_deps[i] "\""
|
580 |
|
|
if (i != js_deps_count)
|
581 |
|
|
added_line = added_line ","
|
582 |
|
|
}
|
583 |
|
|
add_line(root_path, added_line)
|
584 |
|
|
}
|
585 |
|
|
|
586 |
|
|
return js_deps_count
|
587 |
|
|
}
|
588 |
|
|
|
589 |
a00926f1
|
Wojtek Kosior
|
# css_deps is an array used to avoid having the same stylesheet loaded twice in
|
590 |
|
|
# multiple places in a single HTML page.
|
591 |
|
|
function load_css_file(root_path, read_path, loaded_path, line, css_deps) {
|
592 |
|
|
delete css_deps[""]
|
593 |
|
|
|
594 |
|
|
if (validate_path(read_path, loaded_path, line))
|
595 |
|
|
return 1
|
596 |
|
|
|
597 |
|
|
if (!(loaded_path in css_deps)) {
|
598 |
|
|
css_deps[loaded_path]
|
599 |
|
|
to_copy[loaded_path]
|
600 |
|
|
added_line = ("<link rel=\"stylesheet\" type=\"text/css\" " \
|
601 |
|
|
"href=\"/" loaded_path "\" />")
|
602 |
|
|
add_line(root_path, added_line)
|
603 |
|
|
}
|
604 |
|
|
|
605 |
|
|
return 0
|
606 |
|
|
}
|
607 |
|
|
|
608 |
b590eaa2
|
Wojtek Kosior
|
function load_html_file(root_path, read_path, loaded_path, line) {
|
609 |
|
|
if (validate_path(read_path, loaded_path, line))
|
610 |
|
|
return 1
|
611 |
|
|
|
612 |
|
|
if (process_file(loaded_path, loaded_path, "html")) {
|
613 |
|
|
printf " when loading %s from %s\n",
|
614 |
|
|
loaded_path, read_path, line > "/dev/stderr"
|
615 |
6106c789
|
Wojtek Kosior
|
return 1
|
616 |
|
|
}
|
617 |
|
|
|
618 |
b590eaa2
|
Wojtek Kosior
|
return 0
|
619 |
|
|
}
|
620 |
6106c789
|
Wojtek Kosior
|
|
621 |
b590eaa2
|
Wojtek Kosior
|
function print_amalgamation(js_deps, js_deps_count,
|
622 |
|
|
js_dep_nr, path, max_line_nr, line_nr) {
|
623 |
|
|
delete js_deps[0]
|
624 |
6106c789
|
Wojtek Kosior
|
|
625 |
b590eaa2
|
Wojtek Kosior
|
js_deps_count = compute_deps(js_to_amalgamate, js_deps, 0)
|
626 |
|
|
if (js_deps_count < 1)
|
627 |
|
|
return 1
|
628 |
|
|
|
629 |
|
|
# '<' instead of '<=' because we print the main js file below instead
|
630 |
|
|
for (js_dep_nr = 1; js_dep_nr < js_deps_count; js_dep_nr++) {
|
631 |
|
|
path = js_deps[js_dep_nr]
|
632 |
|
|
max_line_nr = lines_count[path]
|
633 |
|
|
|
634 |
|
|
for (line_nr = 1; line_nr <= max_line_nr; line_nr++)
|
635 |
|
|
print lines[path, line_nr]
|
636 |
6106c789
|
Wojtek Kosior
|
}
|
637 |
|
|
|
638 |
b590eaa2
|
Wojtek Kosior
|
for (line_nr = 1; line_nr <= main_js_lines_count; line_nr++)
|
639 |
|
|
print main_js_lines[line_nr]
|
640 |
6106c789
|
Wojtek Kosior
|
|
641 |
|
|
return 0
|
642 |
|
|
}
|
643 |
|
|
|
644 |
|
|
function print_usage() {
|
645 |
5acb2499
|
Wojtek Kosior
|
printf "USAGE: %s compute_scripts.awk -- [-D PREPROCESSOR_DEFINITION]... [-M manifest/to/process/manifest.json]... [-H html/to/process.html]... [-J js/to/process.js]... [-A file/to/append/to.js:appended_code]... [--help|-h] [--output-dir=./build] [--write-js-deps] [--write-html-deps] [--output=files-to-copy|--output=amalgamate-js:js/to/process.js]\n",
|
646 |
6106c789
|
Wojtek Kosior
|
ARGV[0] > "/dev/stderr"
|
647 |
|
|
}
|
648 |
|
|
|
649 |
b590eaa2
|
Wojtek Kosior
|
BEGIN {
|
650 |
|
|
option_arg_patterns["D"] = "^" identifier_re "$"
|
651 |
|
|
option_arg_patterns["M"] = path_re
|
652 |
|
|
option_arg_patterns["H"] = path_re
|
653 |
|
|
option_arg_patterns["J"] = path_re
|
654 |
c71ebff8
|
Wojtek Kosior
|
option_arg_patterns["A"] = "^" path_re_noanchor ":"
|
655 |
6106c789
|
Wojtek Kosior
|
}
|
656 |
|
|
|
657 |
c71ebff8
|
Wojtek Kosior
|
function main(i, j, path, letter, dir, max_line_nr, js_deps, js_deps_count,
|
658 |
3840192d
|
Wojtek Kosior
|
code, tmp_lines) {
|
659 |
b590eaa2
|
Wojtek Kosior
|
output_dir = "./build"
|
660 |
|
|
write_js_deps = false
|
661 |
|
|
write_html_deps = false
|
662 |
6106c789
|
Wojtek Kosior
|
|
663 |
c71ebff8
|
Wojtek Kosior
|
delete appended_lines[0]
|
664 |
|
|
delete appended_lines_counts[0]
|
665 |
3840192d
|
Wojtek Kosior
|
delete tmp_lines[0]
|
666 |
c71ebff8
|
Wojtek Kosior
|
|
667 |
|
|
delete lines[0]
|
668 |
3840192d
|
Wojtek Kosior
|
delete lines_count[0]
|
669 |
c71ebff8
|
Wojtek Kosior
|
|
670 |
b590eaa2
|
Wojtek Kosior
|
output = ""
|
671 |
|
|
js_to_amalgamate = ""
|
672 |
|
|
delete main_js_lines[0]
|
673 |
6106c789
|
Wojtek Kosior
|
|
674 |
b590eaa2
|
Wojtek Kosior
|
delete manifests_to_process[0]
|
675 |
|
|
delete html_to_process[0]
|
676 |
|
|
delete js_to_process[0]
|
677 |
6106c789
|
Wojtek Kosior
|
|
678 |
b590eaa2
|
Wojtek Kosior
|
delete explicitly_requested[0]
|
679 |
6106c789
|
Wojtek Kosior
|
|
680 |
b590eaa2
|
Wojtek Kosior
|
for (i = 1; i < ARGC; i++) {
|
681 |
c71ebff8
|
Wojtek Kosior
|
if (ARGV[i] ~ /^-[DMHJA]$/) {
|
682 |
b590eaa2
|
Wojtek Kosior
|
letter = substr(ARGV[i++], 2)
|
683 |
|
|
if (i == ARGC || ARGV[i] !~ option_arg_patterns[letter]) {
|
684 |
|
|
printf "ERROR: '-%s' option should be followed by an argument matching '%s'\n",
|
685 |
|
|
letter, option_arg_patterns[letter] > "/dev/stderr"
|
686 |
|
|
return 1
|
687 |
|
|
}
|
688 |
6106c789
|
Wojtek Kosior
|
|
689 |
b590eaa2
|
Wojtek Kosior
|
if (letter == "D")
|
690 |
|
|
defines[ARGV[i]]
|
691 |
|
|
else
|
692 |
|
|
explicitly_requested[ARGV[i]]
|
693 |
|
|
|
694 |
|
|
if (letter == "M")
|
695 |
|
|
manifests_to_process[ARGV[i]]
|
696 |
|
|
if (letter == "H")
|
697 |
|
|
html_to_process[ARGV[i]]
|
698 |
|
|
if (letter == "J")
|
699 |
|
|
js_to_process[ARGV[i]]
|
700 |
c71ebff8
|
Wojtek Kosior
|
|
701 |
|
|
if (letter == "A") {
|
702 |
|
|
path = ARGV[i]
|
703 |
|
|
sub(/:.*$/, "", path)
|
704 |
|
|
if (path in appended_lines_counts) {
|
705 |
|
|
printf "ERROR: The same file %s given to the '-A' option multiple times\n",
|
706 |
|
|
path > "/dev/stderr"
|
707 |
|
|
return 1
|
708 |
|
|
}
|
709 |
|
|
|
710 |
3840192d
|
Wojtek Kosior
|
clear_array(tmp_lines)
|
711 |
c71ebff8
|
Wojtek Kosior
|
code = ARGV[i]
|
712 |
|
|
sub(/^[^:]+:/, "", code)
|
713 |
3840192d
|
Wojtek Kosior
|
appended_lines_counts[path] = split(code, tmp_lines, "\n")
|
714 |
c71ebff8
|
Wojtek Kosior
|
for (j = appended_lines_counts[path]; j > 0; j--)
|
715 |
3840192d
|
Wojtek Kosior
|
appended_lines[path,j] = tmp_lines[j]
|
716 |
c71ebff8
|
Wojtek Kosior
|
}
|
717 |
b590eaa2
|
Wojtek Kosior
|
} else if (ARGV[i] ~ /^-(-help|h)$/ ) {
|
718 |
|
|
print_usage()
|
719 |
|
|
return 0
|
720 |
|
|
} else if (ARGV[i] ~ /^--output-dir=/) {
|
721 |
|
|
output_dir = ARGV[i]
|
722 |
|
|
sub(/^--output-dir=/, "", output_dir)
|
723 |
|
|
} else if (ARGV[i] ~ /^--write-js-deps$/) {
|
724 |
|
|
write_js_deps = true
|
725 |
|
|
} else if (ARGV[i] ~ /^--write-html-deps$/) {
|
726 |
|
|
write_html_deps = true
|
727 |
|
|
} else if (ARGV[i] ~ /^--output=files-to-copy$/) {
|
728 |
|
|
output = "files-to-copy"
|
729 |
|
|
} else if (ARGV[i] ~ /^--output=amalgamate-js:/) {
|
730 |
|
|
output = "amalgamate-js"
|
731 |
c71ebff8
|
Wojtek Kosior
|
js_to_amalgamate = ARGV[i]
|
732 |
|
|
sub(/^--output=amalgamate-js:/, "", js_to_amalgamate)
|
733 |
b590eaa2
|
Wojtek Kosior
|
if (js_to_amalgamate !~ path_re) {
|
734 |
|
|
printf "ERROR: amalgamate-js path does not match '%s': %s\n",
|
735 |
|
|
path_re, js_to_amalgamate > "/dev/stderr"
|
736 |
|
|
return 1
|
737 |
|
|
}
|
738 |
|
|
} else {
|
739 |
|
|
printf "ERROR: Unknown option '%s'\n", ARGV[i] > "/dev/stderr"
|
740 |
|
|
print_usage()
|
741 |
|
|
return 1
|
742 |
|
|
}
|
743 |
6106c789
|
Wojtek Kosior
|
}
|
744 |
|
|
|
745 |
b590eaa2
|
Wojtek Kosior
|
if (is_empty(explicitly_requested) && output != "amalgamate-js") {
|
746 |
|
|
explicitly_requested["manifest.json"]
|
747 |
|
|
manifests_to_process["manifest.json"]
|
748 |
6106c789
|
Wojtek Kosior
|
}
|
749 |
b590eaa2
|
Wojtek Kosior
|
|
750 |
|
|
for (path in manifests_to_process) {
|
751 |
|
|
if (process_file(path, path, "manifest"))
|
752 |
|
|
return 1
|
753 |
|
|
}
|
754 |
|
|
for (path in html_to_process) {
|
755 |
|
|
if (process_file(path, path, "html"))
|
756 |
|
|
return 1
|
757 |
|
|
}
|
758 |
|
|
for (path in js_to_process) {
|
759 |
|
|
if (process_file(path, path, "js"))
|
760 |
|
|
return 1
|
761 |
|
|
}
|
762 |
|
|
|
763 |
|
|
for (path in lines_count) {
|
764 |
|
|
if (!(path in explicitly_requested) &&
|
765 |
|
|
!(modes[path] == "js" && write_js_deps) &&
|
766 |
|
|
!(modes[path] == "html" && write_html_deps))
|
767 |
|
|
continue
|
768 |
|
|
|
769 |
|
|
dir = path
|
770 |
|
|
sub(/[^/]*$/, "", dir)
|
771 |
|
|
dir = output_dir "/" dir
|
772 |
|
|
sub("'", "'\\''", dir)
|
773 |
|
|
|
774 |
|
|
system("mkdir -p '" dir "'")
|
775 |
|
|
|
776 |
|
|
printf "" > (output_dir "/" path)
|
777 |
|
|
|
778 |
|
|
max_line_nr = lines_count[path]
|
779 |
|
|
for (i = 1; i <= max_line_nr; i++)
|
780 |
|
|
print lines[path, i] >> (output_dir "/" path)
|
781 |
|
|
}
|
782 |
|
|
|
783 |
|
|
if (output == "files-to-copy") {
|
784 |
|
|
for (path in to_copy)
|
785 |
|
|
print path
|
786 |
|
|
}
|
787 |
|
|
|
788 |
|
|
if (output == "amalgamate-js") {
|
789 |
|
|
if (print_amalgamation())
|
790 |
|
|
return 1
|
791 |
|
|
}
|
792 |
|
|
|
793 |
|
|
return 0
|
794 |
|
|
}
|
795 |
|
|
|
796 |
|
|
BEGIN {
|
797 |
|
|
exit main()
|
798 |
6106c789
|
Wojtek Kosior
|
}
|