///|
/// Script info extracted from HTML
priv struct ScriptInfo {
/// Inline script source (empty if external)
source : String
/// External script URL (empty if inline)
src : String
/// Whether script is async
is_async : Bool
/// Whether script is deferred
is_defer : Bool
/// Script type attribute (empty for default JavaScript)
script_type : String
}
///|
/// Check if a script type is executable as JavaScript
fn is_executable_script_type(script_type : String) -> Bool {
// Empty type or module/javascript types are executable
if script_type.length() == 0 {
return true
}
let lower = script_type.to_lower()
// Standard JavaScript MIME types
lower == "text/javascript" ||
lower == "application/javascript" ||
lower == "module"
}
///|
/// Extract script tags from HTML
fn extract_scripts(html : String) -> Array[ScriptInfo] {
let scripts : Array[ScriptInfo] = []
let len = html.length()
let mut i = 0
while i < len {
// Look for
let mut content_end = content_start
while content_end + 8 < len {
if char_at(html, content_end) == '<' &&
char_at(html, content_end + 1) == '/' &&
(
char_at(html, content_end + 2) == 's' ||
char_at(html, content_end + 2) == 'S'
) &&
(
char_at(html, content_end + 3) == 'c' ||
char_at(html, content_end + 3) == 'C'
) &&
(
char_at(html, content_end + 4) == 'r' ||
char_at(html, content_end + 4) == 'R'
) &&
(
char_at(html, content_end + 5) == 'i' ||
char_at(html, content_end + 5) == 'I'
) &&
(
char_at(html, content_end + 6) == 'p' ||
char_at(html, content_end + 6) == 'P'
) &&
(
char_at(html, content_end + 7) == 't' ||
char_at(html, content_end + 7) == 'T'
) {
break
}
content_end = content_end + 1
}
source = html
.unsafe_substring(start=content_start, end=content_end)
.trim()
.to_owned()
i = content_end
}
// Add script info if we have source or src
if source.length() > 0 || src.length() > 0 {
scripts.push({ source, src, is_async, is_defer, script_type })
}
}
i = i + 1
}
scripts
}