Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a5f85ba97 | ||
|
|
2a8d5d7916 | ||
|
|
95645fcff4 | ||
|
|
b6b358b3bc |
2
.github/workflows/build_gnu_linux.yml
vendored
2
.github/workflows/build_gnu_linux.yml
vendored
@@ -6,9 +6,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'assets/'
|
||||
- 'dist/'
|
||||
- 'docs/'
|
||||
- 'snap/'
|
||||
- '.adr-dir'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- 'Makefile'
|
||||
|
||||
2
.github/workflows/build_macos.yml
vendored
2
.github/workflows/build_macos.yml
vendored
@@ -6,9 +6,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'assets/'
|
||||
- 'dist/'
|
||||
- 'docs/'
|
||||
- 'snap/'
|
||||
- '.adr-dir'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- 'Makefile'
|
||||
|
||||
2
.github/workflows/build_windows.yml
vendored
2
.github/workflows/build_windows.yml
vendored
@@ -6,9 +6,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'assets/'
|
||||
- 'dist/'
|
||||
- 'docs/'
|
||||
- 'snap/'
|
||||
- '.adr-dir'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- 'Makefile'
|
||||
|
||||
4
.github/workflows/cd.yml
vendored
4
.github/workflows/cd.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
run: |
|
||||
sudo mkdir /cross-build
|
||||
sudo touch /etc/apt/sources.list.d/armhf.list
|
||||
echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ bionic main" | sudo tee -a /etc/apt/sources.list.d/armhf.list
|
||||
echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ focal main" | sudo tee -a /etc/apt/sources.list.d/armhf.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-arm-linux-gnueabihf libc6-armhf-cross libc6-dev-armhf-cross
|
||||
sudo apt-get download libssl1.1:armhf libssl-dev:armhf
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
run: |
|
||||
sudo mkdir /cross-build
|
||||
sudo touch /etc/apt/sources.list.d/arm64.list
|
||||
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic main" | sudo tee -a /etc/apt/sources.list.d/arm64.list
|
||||
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ focal main" | sudo tee -a /etc/apt/sources.list.d/arm64.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross
|
||||
sudo apt-get download libssl1.1:arm64 libssl-dev:arm64
|
||||
|
||||
34
.github/workflows/ci-netbsd.yml
vendored
Normal file
34
.github/workflows/ci-netbsd.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# CI NetBSD GitHub Actions workflow for monolith
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'assets/'
|
||||
- 'dist/'
|
||||
- 'snap/'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- 'Makefile'
|
||||
- 'monolith.nuspec'
|
||||
- 'README.md'
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build and test (netbsd)
|
||||
steps:
|
||||
- name: "Checkout repository"
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Test in NetBSD
|
||||
uses: vmactions/netbsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
prepare: |
|
||||
/usr/sbin/pkg_add rust mktools gmake pkgconf cwrappers
|
||||
run: |
|
||||
cargo build --all --locked --verbose --no-default-features
|
||||
cargo test --all --locked --verbose --no-default-features
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -8,9 +8,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'assets/'
|
||||
- 'dist/'
|
||||
- 'docs/'
|
||||
- 'snap/'
|
||||
- '.adr-dir'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- 'Makefile'
|
||||
@@ -19,23 +17,19 @@ on:
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
|
||||
name: Build and test
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- run: git config --global core.autocrlf false
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: "Checkout repository"
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: cargo build --all --locked --verbose
|
||||
|
||||
@@ -51,7 +51,7 @@ scoop install main/monolith
|
||||
#### Via [Winget](https://winstall.app/apps/Y2Z.Monolith) (Windows)
|
||||
|
||||
```console
|
||||
winget install --id=Y2Z.Monolith -e
|
||||
winget install --id=Y2Z.Monolith -e
|
||||
```
|
||||
|
||||
#### Via [MacPorts](https://ports.macports.org/port/monolith/summary) (macOS)
|
||||
|
||||
6
dist/run-in-container.sh
vendored
6
dist/run-in-container.sh
vendored
@@ -1,10 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
DOCKER=docker
|
||||
PROG_NAME=monolith
|
||||
|
||||
if which podman 2>&1 > /dev/null; then
|
||||
DOCKER=podman
|
||||
fi
|
||||
ORG_NAME=y2z
|
||||
PROG_NAME=monolith
|
||||
|
||||
$DOCKER run --rm y2z/$PROG_NAME "$@"
|
||||
$DOCKER run --rm $ORG_NAME/$PROG_NAME "$@"
|
||||
|
||||
65
src/html.rs
65
src/html.rs
@@ -23,6 +23,15 @@ use crate::url::{
|
||||
};
|
||||
use crate::utils::{parse_content_type, retrieve_asset};
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum LinkType {
|
||||
Alternate,
|
||||
DnsPrefetch,
|
||||
Icon,
|
||||
Preload,
|
||||
Stylesheet,
|
||||
}
|
||||
|
||||
struct SrcSetItem<'a> {
|
||||
path: &'a str,
|
||||
descriptor: &'a str,
|
||||
@@ -141,26 +150,6 @@ pub fn create_metadata_tag(url: &Url) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn determine_link_node_type(node: &Handle) -> &str {
|
||||
let mut link_type: &str = "unknown";
|
||||
|
||||
if let Some(link_attr_rel_value) = get_node_attr(node, "rel") {
|
||||
if is_icon(&link_attr_rel_value) {
|
||||
link_type = "icon";
|
||||
} else if link_attr_rel_value.eq_ignore_ascii_case("stylesheet")
|
||||
|| link_attr_rel_value.eq_ignore_ascii_case("alternate stylesheet")
|
||||
{
|
||||
link_type = "stylesheet";
|
||||
} else if link_attr_rel_value.eq_ignore_ascii_case("preload") {
|
||||
link_type = "preload";
|
||||
} else if link_attr_rel_value.eq_ignore_ascii_case("dns-prefetch") {
|
||||
link_type = "dns-prefetch";
|
||||
}
|
||||
}
|
||||
|
||||
link_type
|
||||
}
|
||||
|
||||
pub fn embed_srcset(
|
||||
cache: &mut HashMap<String, Vec<u8>>,
|
||||
client: &Client,
|
||||
@@ -454,6 +443,26 @@ pub fn is_icon(attr_value: &str) -> bool {
|
||||
ICON_VALUES.contains(&attr_value.to_lowercase().as_str())
|
||||
}
|
||||
|
||||
pub fn parse_link_type(link_attr_rel_value: &str) -> Vec<LinkType> {
|
||||
let mut types: Vec<LinkType> = vec![];
|
||||
|
||||
for link_attr_rel_type in link_attr_rel_value.split_whitespace() {
|
||||
if link_attr_rel_type.eq_ignore_ascii_case("alternate") {
|
||||
types.push(LinkType::Alternate);
|
||||
} else if link_attr_rel_type.eq_ignore_ascii_case("dns-prefetch") {
|
||||
types.push(LinkType::DnsPrefetch);
|
||||
} else if link_attr_rel_type.eq_ignore_ascii_case("preload") {
|
||||
types.push(LinkType::Preload);
|
||||
} else if link_attr_rel_type.eq_ignore_ascii_case("stylesheet") {
|
||||
types.push(LinkType::Stylesheet);
|
||||
} else if is_icon(&link_attr_rel_type) {
|
||||
types.push(LinkType::Icon);
|
||||
}
|
||||
}
|
||||
|
||||
types
|
||||
}
|
||||
|
||||
pub fn set_base_url(document: &Handle, desired_base_href: String) -> RcDom {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
serialize(
|
||||
@@ -665,7 +674,10 @@ pub fn retrieve_and_embed_asset(
|
||||
s = String::from_utf8_lossy(&data).to_string();
|
||||
}
|
||||
|
||||
if node_name == "link" && determine_link_node_type(node) == "stylesheet" {
|
||||
if node_name == "link"
|
||||
&& parse_link_type(&get_node_attr(node, "rel").unwrap_or(String::from("")))
|
||||
.contains(&LinkType::Stylesheet)
|
||||
{
|
||||
// Stylesheet LINK elements require special treatment
|
||||
let css: String = embed_css(cache, client, &final_url, &s, options);
|
||||
|
||||
@@ -757,9 +769,10 @@ pub fn walk_and_embed_assets(
|
||||
}
|
||||
}
|
||||
"link" => {
|
||||
let link_type: &str = determine_link_node_type(node);
|
||||
let link_node_types: Vec<LinkType> =
|
||||
parse_link_type(&get_node_attr(node, "rel").unwrap_or(String::from("")));
|
||||
|
||||
if link_type == "icon" {
|
||||
if link_node_types.contains(&LinkType::Icon) {
|
||||
// Find and resolve LINK's href attribute
|
||||
if let Some(link_attr_href_value) = get_node_attr(node, "href") {
|
||||
if !options.no_images && !link_attr_href_value.is_empty() {
|
||||
@@ -776,7 +789,7 @@ pub fn walk_and_embed_assets(
|
||||
set_node_attr(node, "href", None);
|
||||
}
|
||||
}
|
||||
} else if link_type == "stylesheet" {
|
||||
} else if link_node_types.contains(&LinkType::Stylesheet) {
|
||||
// Resolve LINK's href attribute
|
||||
if let Some(link_attr_href_value) = get_node_attr(node, "href") {
|
||||
if options.no_css {
|
||||
@@ -797,7 +810,9 @@ pub fn walk_and_embed_assets(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if link_type == "preload" || link_type == "dns-prefetch" {
|
||||
} else if link_node_types.contains(&LinkType::Preload)
|
||||
|| link_node_types.contains(&LinkType::DnsPrefetch)
|
||||
{
|
||||
// Since all resources are embedded as data URLs, preloading and prefetching are not necessary
|
||||
set_node_attr(node, "rel", None);
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,7 @@ mod get_node_attr;
|
||||
mod get_node_name;
|
||||
mod has_favicon;
|
||||
mod is_icon;
|
||||
mod parse_link_type;
|
||||
mod serialize_document;
|
||||
mod set_node_attr;
|
||||
mod walk_and_embed_assets;
|
||||
|
||||
58
tests/html/parse_link_type.rs
Normal file
58
tests/html/parse_link_type.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||
|
||||
#[cfg(test)]
|
||||
mod passing {
|
||||
use monolith::html;
|
||||
|
||||
#[test]
|
||||
fn icon() {
|
||||
assert!(html::parse_link_type("icon").contains(&html::LinkType::Icon));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shortcut_icon_capitalized() {
|
||||
assert!(html::parse_link_type("Shortcut Icon").contains(&html::LinkType::Icon));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stylesheet() {
|
||||
assert!(html::parse_link_type("stylesheet").contains(&html::LinkType::Stylesheet));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preload_stylesheet() {
|
||||
assert!(html::parse_link_type("preload stylesheet").contains(&html::LinkType::Stylesheet));
|
||||
}
|
||||
}
|
||||
|
||||
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||
|
||||
#[cfg(test)]
|
||||
mod failing {
|
||||
use monolith::html;
|
||||
|
||||
#[test]
|
||||
fn mask_icon() {
|
||||
assert!(html::parse_link_type("mask-icon").is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fluid_icon() {
|
||||
assert!(html::parse_link_type("fluid-icon").is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_string() {
|
||||
assert!(html::parse_link_type("").is_empty());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user