///|
pub(all) enum Source {
InlineHtml(String)
LocalPath(String)
PackagedAssets(String)
RemoteUrl(String)
Localhost(LocalhostSource)
RabbitaCell(Cell)
} derive(Debug, Eq)
///|
pub struct ProtocolMapping {
scheme : String
root : String
} derive(Debug, Eq)
///|
pub fn ProtocolMapping::new(
scheme~ : String,
root~ : String,
) -> ProtocolMapping {
{ scheme, root }
}
///|
pub fn ProtocolMapping::scheme(self : ProtocolMapping) -> String {
self.scheme
}
///|
pub fn ProtocolMapping::root(self : ProtocolMapping) -> String {
self.root
}
///|
pub struct VirtualFile {
path : String
content : String
} derive(Debug, Eq)
///|
pub fn VirtualFile::new(path~ : String, content~ : String) -> VirtualFile {
{ path, content }
}
///|
pub fn VirtualFile::path(self : VirtualFile) -> String {
self.path
}
///|
pub fn VirtualFile::content(self : VirtualFile) -> String {
self.content
}
///|
pub(all) enum ResolvedSourceKind {
ResolvedInlineHtml
ResolvedLocalPath
ResolvedPackagedAssets
ResolvedRemoteUrl
ResolvedLocalhost
ResolvedRabbitaMount
} derive(Debug, Eq)
///|
pub struct ResolvedSource {
kind : ResolvedSourceKind
url : String
protocol_mappings : Array[ProtocolMapping]
virtual_files : Array[VirtualFile]
local_services : Array[LocalService]
} derive(Debug, Eq)
///|
pub fn ResolvedSource::kind(self : ResolvedSource) -> ResolvedSourceKind {
self.kind
}
///|
pub fn ResolvedSource::url(self : ResolvedSource) -> String {
self.url
}
///|
pub fn ResolvedSource::protocol_mappings(
self : ResolvedSource,
) -> Array[ProtocolMapping] {
self.protocol_mappings.copy()
}
///|
pub fn ResolvedSource::virtual_files(
self : ResolvedSource,
) -> Array[VirtualFile] {
self.virtual_files.copy()
}
///|
pub fn ResolvedSource::local_services(
self : ResolvedSource,
) -> Array[LocalService] {
self.local_services.copy()
}
///|
pub fn Source::html(content : String) -> Source {
InlineHtml(content)
}
///|
pub fn Source::local_path(path : String) -> Source {
LocalPath(path)
}
///|
pub fn Source::packaged(path : String) -> Source {
PackagedAssets(path)
}
///|
pub fn Source::url(url : String) -> Source {
RemoteUrl(url)
}
///|
pub fn Source::localhost(
port~ : Int,
host? : String = "127.0.0.1",
path? : String = "/",
readiness_path? : String,
command? : Array[String] = [],
) -> Source {
Localhost(
LocalhostSource::new(port~, host~, path~, readiness_path?, command~),
)
}
///|
pub fn Source::localhost_source(source : LocalhostSource) -> Source {
Localhost(source)
}
///|
pub fn Source::rabbita(cell : Cell) -> Source {
RabbitaCell(cell)
}
///|
pub fn Source::is_empty(self : Source) -> Bool {
match self {
InlineHtml(content) => content == ""
LocalPath(path) => path == ""
PackagedAssets(path) => path == ""
RemoteUrl(url) => url == ""
Localhost(_) => false
RabbitaCell(cell) => cell.id() == ""
}
}
///|
pub fn Source::resolve(
self : Source,
window_label~ : String,
asset_protocol? : String = "lepusa",
) -> Result[ResolvedSource, String] {
if self.is_empty() {
return Err("source must not be empty")
}
if asset_protocol == "" {
return Err("asset protocol is required")
}
let safe_label = window_label.to_asset_segment()
match self {
InlineHtml(content) =>
Ok({
kind: ResolvedInlineHtml,
url: "\{asset_protocol}://inline/\{safe_label}/index.html",
protocol_mappings: [
ProtocolMapping::new(
scheme=asset_protocol,
root="memory:\{safe_label}",
),
],
virtual_files: [VirtualFile::new(path="index.html", content~)],
local_services: [],
})
LocalPath(path) =>
Ok({
kind: ResolvedLocalPath,
url: "\{asset_protocol}://local/\{safe_label}/index.html",
protocol_mappings: [
ProtocolMapping::new(scheme=asset_protocol, root=path),
],
virtual_files: [],
local_services: [],
})
PackagedAssets(path) =>
Ok({
kind: ResolvedPackagedAssets,
url: "\{asset_protocol}://packaged/\{safe_label}/index.html",
protocol_mappings: [
ProtocolMapping::new(scheme=asset_protocol, root="package:\{path}"),
],
virtual_files: [],
local_services: [],
})
RemoteUrl(url) =>
Ok({
kind: ResolvedRemoteUrl,
url,
protocol_mappings: [],
virtual_files: [],
local_services: [],
})
Localhost(source) =>
match source.validate() {
[] =>
Ok({
kind: ResolvedLocalhost,
url: source.url(),
protocol_mappings: [],
virtual_files: [],
local_services: match source.local_service(window_label) {
Some(service) => [service]
None => []
},
})
problems => Err(problems[0])
}
RabbitaCell(cell) =>
Ok({
kind: ResolvedRabbitaMount,
url: "\{asset_protocol}://rabbita/\{safe_label}/index.html",
protocol_mappings: [
ProtocolMapping::new(
scheme=asset_protocol,
root="memory:\{safe_label}",
),
],
virtual_files: [
VirtualFile::new(path="index.html", content=cell.rabbita_document()),
],
local_services: [],
})
}
}
///|
fn Cell::rabbita_document(self : Cell) -> String {
[
"",
"",
"",
"",
"",
"",
"",
"",
self.html().content(),
"",
"",
"",
].join("")
}
///|
fn String::html_attr_escape(self : String) -> String {
self
.replace_all(old="&", new="&")
.replace_all(old="\"", new=""")
.replace_all(old="<", new="<")
.replace_all(old=">", new=">")
.replace_all(old="'", new="'")
}
///|
fn String::to_asset_segment(self : String) -> String {
let mut segment = ""
for char in self.to_lower() {
if (char >= 'a' && char <= 'z') ||
(char >= '0' && char <= '9') ||
char == '-' ||
char == '_' {
segment = segment + char.to_string()
} else {
segment = segment + "-"
}
}
if segment == "" {
"window"
} else {
segment
}
}