Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,466 changes: 889 additions & 577 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mdbook-angular"
version = "0.4.2"
version = "0.4.3"
edition = "2021"
authors = ["Bram Gotink <bram@bram.dev>"]
license = "EUPL-1.2"
Expand All @@ -21,7 +21,7 @@ env_logger = { version = "0.11.5", default-features = false }
log = { version = "0.4.22", features = ["std"] }

# Disable the watch and serve features, we only use mdbook as a library
mdbook = { version = "0.4.40", default-features = false, features = ["search"] }
mdbook = { version = "0.4.52", default-features = false, features = ["search"] }

# Disable unicode features, we don't need them
regex = { version = "1.11.0", default-features = false, features = [
Expand All @@ -44,17 +44,18 @@ anyhow = "1.0.89"

once_cell = "1.20.2"

swc_core = { version = "0.106.4", features = [
swc_core = { version = "55.0.2", features = [
"common",
"ecma_parser_typescript",
"ecma_ast",
] }
bytes-str = "0.2.7"

chrono = { version = "0.4.38", default-features = false, features = ["clock"] }

semver = "1.0.23"

handlebars = "5.0"
handlebars = "6.4.0"

[target.'cfg(unix)'.dependencies]
libc = { version = "0.2.159", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion src/angular/builder/background/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub(super) fn start(config: &Config) -> Result<()> {
.current_dir(&config.angular_root_folder)
.exec();

error!("Failed to exec angular: {}", err);
error!("Failed to exec angular: {err}");

#[allow(clippy::exit)]
exit(1);
Expand Down
42 changes: 26 additions & 16 deletions src/codeblock/parser.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{io, path::Path, rc::Rc};
use std::{io, path::Path, rc::Rc, sync::LazyLock};

use bytes_str::BytesStr;
use log::debug;
use once_cell::sync::Lazy;
use regex::Regex;
use swc_core::{
common::{
Expand All @@ -20,7 +20,7 @@ use crate::{utils::swc::get_decorator, Error, Result};

use super::playground::{parse_playground, Playground};

static TS_EXT: Lazy<Regex> = Lazy::new(|| Regex::new(r"\.([cm]?)ts(x?)$").unwrap());
static TS_EXT: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\.([cm]?)ts(x?)$").unwrap());
static START_OF_FILE: BytePos = BytePos(1);

pub(super) struct ParsedCodeBlock {
Expand All @@ -45,7 +45,7 @@ struct CodeBlockVisitor {

impl CodeBlockVisitor {
fn get_selector(&mut self, decorator: &ast::ObjectLit, name: &str) -> Result<String> {
static INDENTATION: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\s+").unwrap());
static INDENTATION: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^\s+").unwrap());

let selector = decorator
.props
Expand All @@ -61,17 +61,23 @@ impl CodeBlockVisitor {

if let Some(selector) = selector {
let selector = selector.value.as_lit().and_then(|lit| match lit {
ast::Lit::Str(selector) => Some(selector.value.as_ref()),
ast::Lit::Str(ref selector) => Some(&selector.value),
_ => None,
});

return if let Some(selector) = selector {
Ok(selector.to_owned())
} else {
Err(Error::msg(format!(
let Some(selector) = selector else {
return Err(Error::msg(format!(
"Selector isn't a string literal in class {name}"
)))
)));
};

let Some(selector) = selector.as_str() else {
return Err(Error::msg(format!(
"Selector is not a valid string in class {name}"
)));
};

return Ok(selector.to_owned());
}

let Some(generated_selector) = self.index.map(|i| format!("codeblock-{i}")) else {
Expand Down Expand Up @@ -189,7 +195,7 @@ impl CodeBlockVisitor {
fn visit_export_default_decl(&mut self, n: &ast::ExportDefaultDecl) -> Result<()> {
if let Some(n) = n.decl.as_class() {
self.visit_exported_class("default", &n.class)?;
};
}

Ok(())
}
Expand All @@ -208,7 +214,7 @@ impl CodeBlockVisitor {
ast::ModuleDecl::ExportDefaultDecl(n) => self.visit_export_default_decl(n)?,
ast::ModuleDecl::ExportDecl(n) => self.visit_export_decl(n)?,
_ => {}
};
}
}

Ok(())
Expand All @@ -223,13 +229,17 @@ pub(super) fn parse_codeblock(
class_name: Option<&str>,
reexport_path: Option<&Path>,
) -> Result<ParsedCodeBlock> {
let code = Rc::new(code.to_owned());

let handler = Handler::with_emitter_writer(Box::new(io::stderr()), None);

let name: Rc<_> = FileName::Anon.into();

let source_file = SourceFile::new_from(name.clone(), false, name, code.clone(), START_OF_FILE);
let source_file = SourceFile::new(
name.clone(),
false,
name,
BytesStr::from_str_slice(code),
START_OF_FILE,
);

let comments = SingleThreadedComments::default();

Expand All @@ -253,7 +263,7 @@ pub(super) fn parse_codeblock(

let mut visitor = CodeBlockVisitor {
class_name: class_name.map(ToOwned::to_owned),
source: code,
source: Rc::from(code.to_owned()),
source_file,
comments,
index: match reexport_path {
Expand Down
14 changes: 9 additions & 5 deletions src/codeblock/playground/evaluate_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,13 @@ pub(super) fn ts_type_to_input_type<T: AsRef<ast::TsType>>(
.iter()
.filter_map(|t| t.as_ts_lit_type())
.filter_map(|t| t.lit.as_str())
.map(|v| v.value.to_string())
.filter_map(|v| v.value.as_str())
.collect();

if string_types.len() == types.len() {
Some(PlaygroundInputType::Enum(string_types))
Some(PlaygroundInputType::Enum(
string_types.into_iter().map(ToOwned::to_owned).collect(),
))
} else {
None
}
Expand All @@ -276,9 +278,11 @@ pub(super) fn evaluate<T: AsRef<ast::Expr>>(expr: T) -> Option<PlaygroundInputCo
Number::from_f64(value.value).map(Value::Number),
PlaygroundInputType::Number,
)),
ast::Expr::Lit(ast::Lit::Str(value)) => {
Some(PlaygroundInputConfig::from_default(value.value.to_string()))
}
ast::Expr::Lit(ast::Lit::Str(value)) => value
.value
.as_str()
.map(ToOwned::to_owned)
.map(PlaygroundInputConfig::from_default),

ast::Expr::Tpl(_) => Some(PlaygroundInputConfig::string()),

Expand Down
8 changes: 4 additions & 4 deletions src/codeblock/playground/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ fn get_name_from_input_decorator(decorator: &ast::Decorator) -> Option<String> {
.and_then(|call| call.args.first())?;

if let Some(ast::Lit::Str(str)) = arg.expr.as_lit() {
return Some(str.value.as_str().to_owned());
return str.value.as_str().map(ToOwned::to_owned);
}

let alias = arg
Expand All @@ -172,7 +172,7 @@ fn get_name_from_input_decorator(decorator: &ast::Decorator) -> Option<String> {
return None;
};

Some(alias.value.as_str().to_owned())
alias.value.as_str().map(ToOwned::to_owned)
}

fn get_name_from_input_signal(call: &ast::CallExpr) -> Option<String> {
Expand All @@ -190,7 +190,7 @@ fn get_name_from_input_signal(call: &ast::CallExpr) -> Option<String> {
return None;
};

Some(alias.value.as_str().to_owned())
alias.value.as_str().map(ToOwned::to_owned)
}

fn extract_type_from_pat(pat: &ast::Pat) -> Option<PlaygroundInputType> {
Expand Down Expand Up @@ -234,7 +234,7 @@ fn extract_actions<C: comments::Comments>(
fn to_name(prop_name: &ast::PropName) -> Option<&str> {
match prop_name {
ast::PropName::Ident(ast::IdentName { sym, .. }) => Some(sym.as_ref()),
ast::PropName::Str(ast::Str { value, .. }) => Some(value.as_ref()),
ast::PropName::Str(ast::Str { value, .. }) => value.as_str(),
_ => None,
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use mdbook::{
fn validate_version(ctx: &RenderContext) -> Result<()> {
let req = semver::VersionReq::parse(EXPECTED_MDBOOK_VERSION).unwrap();

if semver::Version::parse(&ctx.version).map_or(false, |version| req.matches(&version)) {
if semver::Version::parse(&ctx.version).is_ok_and(|version| req.matches(&version)) {
Ok(())
} else {
bail!("Invalid mdbook version {}, expected {}", &ctx.version, req);
Expand All @@ -60,7 +60,7 @@ pub(crate) use anyhow::{bail, Context, Error, Result};
pub struct AngularRenderer {}

impl Renderer for AngularRenderer {
fn name(&self) -> &str {
fn name(&self) -> &'static str {
"angular"
}

Expand Down Expand Up @@ -108,7 +108,7 @@ impl AngularRenderer {
}
}
Err(error) => result = Err(error),
};
}
}
});

Expand Down
17 changes: 10 additions & 7 deletions src/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
extern crate alloc;

use std::{
fmt::Write,
fs,
ops::Deref,
path::{Path, PathBuf},
rc::Rc,
sync::LazyLock,
};

use anyhow::Context;
use handlebars::Handlebars;
use mdbook::book::Chapter;
use once_cell::sync::Lazy;
use pathdiff::diff_paths;
use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag, TagEnd};
use pulldown_cmark_to_cmark::cmark as markdown_to_string;
Expand Down Expand Up @@ -130,7 +131,7 @@ struct CodeBlockCollector<'a, 'b> {
handlebars: Handlebars<'b>,
}

impl<'a, 'c> CodeBlockCollector<'a, 'c> {
impl<'a> CodeBlockCollector<'a, '_> {
fn new(config: &'a Config, chapter: &'a Chapter) -> Result<Self> {
let mut handlebars = Handlebars::new();

Expand Down Expand Up @@ -159,7 +160,7 @@ impl<'a, 'c> CodeBlockCollector<'a, 'c> {
}

fn process_event<'b>(&mut self, event: Event<'b>) -> ProcessedEvent<'b> {
static TAG_ANGULAR: Lazy<Regex> = Lazy::new(|| {
static TAG_ANGULAR: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"\{\{#angular\s+(?<path>\S+?)(?:#(?<class_name>\S+))?(?<flags>\s+.*?)?\}\}")
.unwrap()
});
Expand Down Expand Up @@ -388,17 +389,19 @@ pub(crate) fn process_markdown(

let ptr = path_to_root(&source_path);

new_content.push_str(&format!(
write!(
new_content,
r#"{}<script id="load-angular" data-path={} type="module" src="{}/browser/main.js"></script>"#,
"\n\n",
serde_json::to_string(&source_path)?,
&ptr,
));
)?;

if code_blocks.iter().any(|b| b.playground.is_some()) {
new_content.push_str(&format!(
write!(
new_content,
r#"<script type="module" src="{ptr}/playground-io.min.js"></script>"#,
));
)?;
}

chapter.content = new_content;
Expand Down
11 changes: 6 additions & 5 deletions src/utils/swc.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::{borrow::Cow, collections::VecDeque};
use std::{borrow::Cow, collections::VecDeque, sync::LazyLock};

use once_cell::sync::Lazy;
use regex::Regex;
use swc_core::{
common::comments::{self, CommentKind},
ecma::ast,
};

pub(crate) fn clean_comment(comment: &comments::Comment) -> String {
static COMMENT_BLOCK_LINE_START: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\s*\*\s?").unwrap());
static LINE_COMMENT_START: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\s*//\s?").unwrap());
static COMMENT_BLOCK_LINE_START: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^\s*\*\s?").unwrap());
static LINE_COMMENT_START: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^\s*//\s?").unwrap());

let start_of_line_regex = match comment.kind {
CommentKind::Block => &COMMENT_BLOCK_LINE_START,
Expand Down Expand Up @@ -55,6 +56,6 @@ pub(crate) fn get_decorator<'a>(
.as_call()
.and_then(|call| call.callee.as_expr())
.and_then(|callee| callee.as_ident())
.map_or(false, |ident| ident.sym.as_ref() == name)
.is_some_and(|ident| ident.sym.as_ref() == name)
})
}