Skip to content

Commit

Permalink
feat: add WASM build
Browse files Browse the repository at this point in the history
  • Loading branch information
frytg committed Nov 13, 2024
1 parent 088eb1a commit 6306ccc
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 89 deletions.
58 changes: 7 additions & 51 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,13 @@
# 4.0.0 / 2023-07-18
# Changelog

* [BUGFIX] Update GithubStats dep to use new Github.com format for table
## 5.1.0 / 2024-11-13

# 3.4.0 / 2023-01-08
- feat: add WASM build

* [ENHANCEMENT] Update GithubStats dep
## 5.0.0 / 2024-11-12

# 3.3.1 / 2021-02-06
- feat: migrate to Rust

* [BUGFIX] Actually bump githubstats dep

# 3.3.0 / 2021-02-06

* [ENHANCEMENT] Update GithubStats dep

# 3.2.0 / 2020-10-06

* [ENHANCEMENT] Update GithubStats dep

# 3.1.1 / 2020-08-13

* [ENHANCEMENT] Update GithubStats dep

# 3.1.0 / 2017-10-03

* [ENHANCEMENT] GitHub updated their styling; this updated matches that change

# 3.0.0 / 2017-09-29

* [ENHANCEMENT] Upgrade to latest githubstats with better error messages

# 2.1.0 / 2017-08-25

* [ENHANCEMENT] Upgrade to latest githubstats

# 2.0.1 / 2016-11-08

* [BUGFIX] Actually update changelog in release

# 2.0.0 / 2016-11-07

* [FEATURE] Add support for svg_square as a rendering type, thanks @blerchin

# 1.1.0 / 2016-05-19

* [BUGFIX] Upgrade to newer GithubStats that fixes streak parsing

# 1.0.1 / 2015-10-20

* [BUGFIX] Fix month labels for parity with GitHub
* [ENHANCEMENT] Link to @2016rshah's awesome service for hosted SVGs

# 1.0.0 / 2015-01-25

* [ENHANCEMENT] Stabilized API
## 4.0.0 / 2023-07-18

See [upstream repo](https://github.com/akerl/githubchart) for previouschangelog.
45 changes: 34 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 22 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
[package]
name = "githubchart"
version = "5.0.0"
name = "githubchart-rust"
version = "5.1.0"
authors = ["frytg"]
edition = "2021"
license = "MIT"
repository = "https://github.com/frytg/githubchart-rust"
description = "GitHub contribution graph generator in Rust/WASM"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
regex = "1.11.1"
reqwest = { version = "0.11", features = ["blocking", "json"] }
reqwest = { version = "0.11", features = ["json"] }
scraper = "0.17"
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.5"
getrandom = { version = "0.2", features = ["js"] }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = "0.3"
tokio = { version = "1.0", features = ["sync", "macros"] }
getrandom = { version = "0.2", features = ["js"] }

[profile.release]
# optimizations from https://github.com/johnthagen/min-sized-rust
Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ Test the binary with:
./target/release/githubchart release.svg -u frytg
```

## Build for Web

See [_Compiling from Rust to WebAssembly_](https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_Wasm) for a full guide on compiling Rust to WebAssembly (WASM).

This project is already configured to build for Web with `wasm-pack`. Run this command to build:

```sh
wasm-pack build --target web
```

There's also an example in [`web/example.html`](./web/example.html) that you can run locally.

More docs about this:

- [WebAssembly in Deno](https://docs.deno.com/runtime/reference/wasm/)
- [`wasm-pack` docs](https://rustwasm.github.io/docs/wasm-pack/)

## License

This `githubchart-rust` fork (like the upstream repo) is released under the MIT License. See the bundled [LICENSE](./LICENSE) file for details.
This `githubchart-rust` fork (like the upstream repository) is released under the MIT License. See the bundled [LICENSE](./LICENSE) file for details.
35 changes: 24 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use reqwest;
use scraper::{Html, Selector};
use wasm_bindgen::prelude::*;

pub mod svg;

Expand Down Expand Up @@ -37,20 +38,18 @@ pub const COLOR_SCHEMES: &[(&str, &[&str])] = &[
),
];

pub fn fetch_github_stats(
pub async fn fetch_github_stats(
username: &str,
) -> Result<Vec<(String, i32)>, Box<dyn std::error::Error>> {
// GitHub's contribution graph data endpoint
let url = format!("https://github.com/users/{}/contributions", username);

// Fetch the HTML content
let client = reqwest::blocking::Client::new();
let client = reqwest::Client::new();
let response = client
.get(&url)
.header("User-Agent", "githubchart-rust")
.send()?;
.send()
.await?;

// Check status code
if !response.status().is_success() {
return Err(format!(
"Failed loading data from GitHub: {} {}",
Expand All @@ -60,10 +59,8 @@ pub fn fetch_github_stats(
.into());
}

let html_content = response.text()?;
let html_content = response.text().await?;
let document = Html::parse_document(&html_content);

// Select contribution calendar cells
let cell_selector = Selector::parse("td.ContributionCalendar-day").unwrap();

let mut stats = Vec::new();
Expand All @@ -74,13 +71,11 @@ pub fn fetch_github_stats(
element.value().attr("data-level"),
) {
if let Ok(count) = count_str.parse::<i32>() {
// println!("fetch_github_stats > date: {}, count: {}", date, count);
stats.push((date.to_string(), count));
}
}
}

// Sort by date
stats.sort_by(|a, b| a.0.cmp(&b.0));

if stats.is_empty() {
Expand All @@ -92,3 +87,21 @@ pub fn fetch_github_stats(

#[cfg(test)]
mod tests;

#[wasm_bindgen]
pub async fn generate_github_chart(username: &str, color_scheme: Option<String>) -> Result<String, JsValue> {
let stats = fetch_github_stats(username)
.await
.map_err(|e| JsValue::from_str(&e.to_string()))?;

let colors = match color_scheme.as_deref() {
Some(scheme) => COLOR_SCHEMES
.iter()
.find(|&&(name, _)| name == scheme)
.map(|&(_, colors)| colors.to_vec()),
None => None,
};

let chart = Chart::new(stats, colors);
chart.render().map_err(|e| JsValue::from_str(&e))
}
8 changes: 4 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

use githubchart::{fetch_github_stats, Chart, COLOR_SCHEMES};
use githubchart_rust::{fetch_github_stats, Chart, COLOR_SCHEMES};

fn main() {
#[tokio::main]
async fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!(
Expand Down Expand Up @@ -49,8 +50,7 @@ fn main() {
}

let stats = if let Some(username) = username {
// Fetch stats from GitHub API
match fetch_github_stats(&username) {
match fetch_github_stats(&username).await {
Ok(stats) => stats,
Err(e) => {
eprintln!("Error fetching GitHub stats: {}", e);
Expand Down
12 changes: 4 additions & 8 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
use regex::Regex;
use githubchart_rust::{fetch_github_stats, Chart, COLOR_SCHEMES};

use githubchart::{fetch_github_stats, Chart, COLOR_SCHEMES};

#[test]
fn test_github_stats_fetching() {
// Note: This test requires internet connection
match fetch_github_stats("frytg") {
#[tokio::test]
async fn test_github_stats_fetching() {
match fetch_github_stats("frytg").await {
Ok(stats) => {
assert!(!stats.is_empty());
// Check date format
assert!(Regex::new(r"^\d{4}-\d{2}-\d{2}$")
.unwrap()
.is_match(&stats[0].0));
// Check contribution count is non-negative
assert!(stats[0].1 >= 0);
}
Err(e) => panic!("Failed to fetch stats: {}", e),
Expand Down
21 changes: 21 additions & 0 deletions web/example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>GitHub Chart Demo</title>
</head>
<body>
<div id="chart"></div>
<script type="module">
import { initWasm, generateGitHubChart } from "./index.js";

async function init() {
await initWasm();
const svg = await generateGitHubChart("frytg", "default");
document.getElementById("chart").innerHTML = svg;
}

init();
</script>
</body>
</html>
15 changes: 15 additions & 0 deletions web/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import init, { generate_github_chart } from '../pkg/githubchart.js'

export async function initWasm() {
await init()
}

export async function generateGitHubChart(username, colorScheme) {
return generate_github_chart(username, colorScheme)
}

export const COLOR_SCHEMES = {
default: ['#eeeeee', '#c6e48b', '#7bc96f', '#239a3b', '#196127'],
old: ['#eeeeee', '#d6e685', '#8cc665', '#44a340', '#1e6823'],
halloween: ['#EEEEEE', '#FFEE4A', '#FFC501', '#FE9600', '#03001C'],
}

0 comments on commit 6306ccc

Please sign in to comment.