-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from BrowserSync/html_support
html_support
- Loading branch information
Showing
43 changed files
with
944 additions
and
149 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<style> | ||
p { | ||
color: red; | ||
} | ||
|
||
abc-element { | ||
color: green; | ||
} | ||
|
||
</style> | ||
|
||
<abc-element></abc-element> | ||
|
||
<script type="module"> | ||
class BSlive extends HTMLElement { | ||
connectedCallback() { | ||
this.innerHTML = "Hello worlds"; | ||
} | ||
} | ||
|
||
customElements.define("abc-element", BSlive); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "bsnext_html" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
bsnext_input = { path = "../bsnext_input" } | ||
unindent = "0.2.3" | ||
indent = "0.1.1" | ||
scraper = "0.21.0" | ||
|
||
[dev-dependencies] | ||
anyhow = { workspace = true } | ||
insta = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
use bsnext_input::playground::Playground; | ||
use bsnext_input::server_config::ServerConfig; | ||
use bsnext_input::{Input, InputWriter}; | ||
|
||
pub struct HtmlWriter; | ||
|
||
impl InputWriter for HtmlWriter { | ||
fn input_to_str(&self, input: &Input) -> String { | ||
if input.servers.is_empty() { | ||
todo!("html requires at least 1 server definition") | ||
} | ||
if input.servers.len() > 1 { | ||
todo!("more than 1 server not supported yet") | ||
} | ||
let server = input.servers.first().expect("must access first"); | ||
let Some(playground) = &server.playground else { | ||
todo!("only playground is supported in HTML for now") | ||
}; | ||
let mut blocks: Vec<String> = vec![]; | ||
if let Some(css) = &playground.css { | ||
blocks.push("<style>".into()); | ||
let indented = indent::indent_all_by(4, css); | ||
blocks.push(indented); | ||
blocks.push("</style>".into()); | ||
} | ||
blocks.push(playground.html.clone()); | ||
if let Some(js) = &playground.js { | ||
blocks.push("<script type=\"module\">".into()); | ||
let indented = indent::indent_all_by(4, js); | ||
blocks.push(indented); | ||
blocks.push("</script>".into()); | ||
} | ||
blocks.join("\n") | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_html_writer_for_playground() { | ||
let css = r#"body { | ||
background: red; | ||
}"#; | ||
let js = r#"console.log("hello world!")"#; | ||
let playground = Playground { | ||
html: "<p>Hello world</p>".to_string(), | ||
js: Some(js.to_string()), | ||
css: Some(css.to_string()), | ||
}; | ||
let mut input = Input::default(); | ||
let mut server = ServerConfig::default(); | ||
server.playground = Some(playground); | ||
input.servers.push(server); | ||
let output = HtmlWriter.input_to_str(&input); | ||
insta::assert_snapshot!(output); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
use bsnext_input::playground::Playground; | ||
use bsnext_input::server_config::{ServerConfig, ServerIdentity}; | ||
use bsnext_input::{Input, InputCreation, InputCtx, InputError}; | ||
use std::fs::read_to_string; | ||
use std::path::Path; | ||
|
||
pub mod html_writer; | ||
|
||
pub struct HtmlFs; | ||
|
||
impl InputCreation for HtmlFs { | ||
fn from_input_path<P: AsRef<Path>>(path: P, ctx: &InputCtx) -> Result<Input, Box<InputError>> { | ||
let str = read_to_string(path).map_err(|e| Box::new(e.into()))?; | ||
let input = playground_html_str_to_input(&str, ctx) | ||
.map_err(|e| Box::new(InputError::HtmlError(e.to_string())))?; | ||
Ok(input) | ||
} | ||
|
||
fn from_input_str<P: AsRef<str>>(content: P, ctx: &InputCtx) -> Result<Input, Box<InputError>> { | ||
let input = playground_html_str_to_input(&content.as_ref(), ctx) | ||
.map_err(|e| Box::new(InputError::HtmlError(e.to_string())))?; | ||
Ok(input) | ||
} | ||
} | ||
|
||
fn playground_html_str_to_input(html: &str, ctx: &InputCtx) -> Result<Input, Box<InputError>> { | ||
use unindent::unindent; | ||
|
||
// parse the HTML | ||
let mut document = scraper::Html::parse_fragment(html); | ||
|
||
let style = scraper::Selector::parse("style:first-of-type").unwrap(); | ||
let script = scraper::Selector::parse("script:first-of-type").unwrap(); | ||
|
||
let mut style_elems = document.select(&style); | ||
let mut script_elems = document.select(&script); | ||
let mut node_ids_to_remove = vec![]; | ||
|
||
// start an empty playground | ||
let mut playground = Playground { | ||
html: "".to_string(), | ||
css: None, | ||
js: None, | ||
}; | ||
|
||
if let Some(style) = style_elems.next() { | ||
node_ids_to_remove.push(style.id()); | ||
let t = style.text().nth(0).unwrap(); | ||
let unindented = unindent(t); | ||
playground.css = Some(unindented); | ||
} | ||
|
||
if let Some(script) = script_elems.next() { | ||
node_ids_to_remove.push(script.id()); | ||
let t = script.text().nth(0).unwrap(); | ||
let unindented = unindent(t); | ||
playground.js = Some(unindented); | ||
} | ||
|
||
for node_id in node_ids_to_remove { | ||
document.tree.get_mut(node_id).unwrap().detach(); | ||
} | ||
|
||
// grab the HTML | ||
let as_html = document.html(); | ||
let trimmed = as_html | ||
.strip_prefix("<html>") | ||
.unwrap() | ||
.strip_suffix("</html>") | ||
.unwrap(); | ||
let un_indented = unindent(trimmed); | ||
playground.html = un_indented; | ||
|
||
// Now start to build up the input | ||
let mut input = Input::default(); | ||
|
||
// 1: first try prev | ||
// 2: next try if 'port' was provided | ||
// 3: finally, make one up | ||
let iden = ctx | ||
.first_id() | ||
.or_else(|| ServerIdentity::from_port_or_named(ctx.port()).ok()) | ||
.unwrap_or_default(); | ||
|
||
// Create the server | ||
let server = ServerConfig { | ||
identity: iden, | ||
playground: Some(playground), | ||
..Default::default() | ||
}; | ||
|
||
// Add it to the input | ||
input.servers.push(server); | ||
|
||
Ok(input) | ||
} |
13 changes: 13 additions & 0 deletions
13
crates/bsnext_html/src/snapshots/bsnext_html__html_writer__html_writer_for_playground.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
source: crates/bsnext_html/src/html_writer.rs | ||
expression: output | ||
--- | ||
<style> | ||
body { | ||
background: red; | ||
} | ||
</style> | ||
<p>Hello world</p> | ||
<script type="module"> | ||
console.log("hello world!") | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
use bsnext_html::HtmlFs; | ||
use bsnext_input::server_config::ServerIdentity; | ||
use bsnext_input::{InputArgs, InputCreation, InputCtx}; | ||
use insta::assert_debug_snapshot; | ||
|
||
const INPUT: &str = r#" | ||
<style> | ||
p { | ||
color: red; | ||
} | ||
abc-shane { | ||
color: red; | ||
} | ||
</style> | ||
<main> | ||
<h1>Test!</h1> | ||
<abc-shane></abc-shane> | ||
</main> | ||
<script type="module"> | ||
class BSlive extends HTMLElement { | ||
connectedCallback() { | ||
this.innerHTML = "Hello world"; | ||
} | ||
} | ||
customElements.define("abc-shane", BSlive); | ||
</script>"#; | ||
|
||
#[test] | ||
fn test_html_playground_content() -> anyhow::Result<()> { | ||
let idens = vec![]; | ||
let ctx = InputCtx::new(&idens, None); | ||
let as_input = HtmlFs::from_input_str(INPUT, &ctx)?; | ||
let Some(server) = as_input.servers.get(0) else { | ||
return Err(anyhow::anyhow!("no server")); | ||
}; | ||
let routes = server.routes(); | ||
let html = routes.get(0).unwrap(); | ||
let js = routes.get(1).unwrap(); | ||
let css = routes.get(2).unwrap(); | ||
assert_debug_snapshot!(html.kind); | ||
assert_debug_snapshot!(js.kind); | ||
assert_debug_snapshot!(css.kind); | ||
Ok(()) | ||
} | ||
#[test] | ||
fn test_html_playground_without_server_id() -> anyhow::Result<()> { | ||
let idens = vec![]; | ||
let ctx = InputCtx::new(&idens, None); | ||
let as_input = HtmlFs::from_input_str(INPUT, &ctx)?; | ||
assert_eq!(as_input.servers.len(), 1); | ||
let first = as_input.servers.get(0).unwrap(); | ||
let is_named = matches!(first.identity, ServerIdentity::Named { .. }); | ||
assert_eq!(is_named, true); | ||
Ok(()) | ||
} | ||
#[test] | ||
fn test_html_playground_with_server_id() -> anyhow::Result<()> { | ||
let ident = ServerIdentity::Address { | ||
bind_address: String::from("127.0.0.1:8080"), | ||
}; | ||
let ctx = InputCtx::new(&[ident.clone()], None); | ||
let as_input = HtmlFs::from_input_str(INPUT, &ctx)?; | ||
|
||
assert_eq!(as_input.servers.len(), 1); | ||
let first = as_input.servers.get(0).unwrap(); | ||
assert_eq!(ident, first.identity); | ||
Ok(()) | ||
} | ||
#[test] | ||
fn test_html_playground_with_port() -> anyhow::Result<()> { | ||
let ident = ServerIdentity::Address { | ||
bind_address: String::from("0.0.0.0:8080"), | ||
}; | ||
let input_args = InputArgs { port: Some(8080) }; | ||
let ctx = InputCtx::new(&[], Some(input_args)); | ||
let as_input = HtmlFs::from_input_str(INPUT, &ctx)?; | ||
let first = as_input.servers.get(0).unwrap(); | ||
assert_eq!(first.identity, ident); | ||
Ok(()) | ||
} |
9 changes: 9 additions & 0 deletions
9
crates/bsnext_html/tests/snapshots/html_playground__html_playground_content-2.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
source: crates/bsnext_html/tests/html_playground.rs | ||
expression: js.kind | ||
--- | ||
Raw( | ||
Raw { | ||
raw: "class BSlive extends HTMLElement {\n connectedCallback() {\n this.innerHTML = \"Hello world\";\n }\n}\n\ncustomElements.define(\"abc-shane\", BSlive);\n", | ||
}, | ||
) |
9 changes: 9 additions & 0 deletions
9
crates/bsnext_html/tests/snapshots/html_playground__html_playground_content-3.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
source: crates/bsnext_html/tests/html_playground.rs | ||
expression: css.kind | ||
--- | ||
Raw( | ||
Raw { | ||
raw: "p {\n color: red;\n}\n\nabc-shane {\n color: red;\n}\n", | ||
}, | ||
) |
9 changes: 9 additions & 0 deletions
9
crates/bsnext_html/tests/snapshots/html_playground__html_playground_content.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
source: crates/bsnext_html/tests/html_playground.rs | ||
expression: html.kind | ||
--- | ||
Raw( | ||
Html { | ||
html: "\n<main>\n <h1>Test!</h1>\n <abc-shane></abc-shane>\n</main>\n", | ||
}, | ||
) |
Oops, something went wrong.