Skip to content

Commit

Permalink
wip: specta-jsdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
oscartbeaumont committed Aug 1, 2024
1 parent 5e3a8c5 commit de9d96e
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 24 deletions.
28 changes: 28 additions & 0 deletions specta-jsdoc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "specta-jsdoc"
description = "Export your Rust types to JSDoc"
version = "0.0.3"
authors = ["Oscar Beaumont <[email protected]>"]
edition = "2021"
license = "MIT"
repository = "https://github.com/oscartbeaumont/specta"
documentation = "https://docs.rs/specta-jsdoc/latest/specta-jsdoc"
keywords = ["async", "specta", "jsdoc", "rspc", "typescript", "typesafe"]
categories = ["web-programming", "asynchronous"]

# /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features
[package.metadata."docs.rs"]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = []

[lints]
workspace = true

[dependencies]
specta = { version = "=2.0.0-rc.16", path = "../specta" }
specta-typescript = { version = "=0.0.3", path = "../specta-typescript" }
# TODO: Don't depend on serde
specta-serde = { version = "=0.0.3", path = "../specta-serde" }
109 changes: 109 additions & 0 deletions specta-jsdoc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//! [JSDoc](https://jsdoc.app) language exporter.

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-zod` is missing `package.readme` metadata

warning: package `specta-zod` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-util` is missing `package.readme` metadata

warning: package `specta-util` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-swift` is missing `package.readme` metadata

warning: package `specta-swift` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-rust` is missing `package.readme` metadata

warning: package `specta-rust` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-openapi` is missing `package.readme` metadata

warning: package `specta-openapi` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-kotlin` is missing `package.readme` metadata

warning: package `specta-kotlin` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-typescript` is missing `package.readme` metadata

warning: package `specta-typescript` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-serde` is missing `package.readme` metadata

warning: package `specta-serde` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-jsdoc` is missing `package.readme` metadata

warning: package `specta-jsdoc` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-go` is missing `package.readme` metadata

warning: package `specta-go` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta-datatype-from` is missing `package.readme` metadata

warning: package `specta-datatype-from` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata

Check warning on line 1 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

package `specta` is missing `package.readme` metadata

warning: package `specta` is missing `package.readme` metadata | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata = note: `-W clippy::cargo-common-metadata` implied by `-W clippy::cargo` = help: to override `-W clippy::cargo` add `#[allow(clippy::cargo_common_metadata)]`
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(
html_logo_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png",
html_favicon_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png"
)]

use std::{borrow::Cow, path::Path};

use specta::{Language, TypeMap};
use specta_typescript::{BigIntExportBehavior, CommentFormatterFn, FormatterFn};

// TODO: Ensure this is up to our `Typescript` exporters standards.

/// JSDoc language exporter.
#[derive(Debug, Clone, Default)]
pub struct JSDoc(pub specta_typescript::Typescript);

impl From<specta_typescript::Typescript> for JSDoc {
fn from(ts: specta_typescript::Typescript) -> Self {
Self(ts)
}
}

impl JSDoc {
/// Construct a new JSDoc exporter with the default options configured.
pub fn new() -> Self {
Default::default()
}

/// Configure a header for the file.
///
/// This is perfect for configuring lint ignore rules or other file-level comments.
pub fn header(mut self, header: impl Into<Cow<'static, str>>) -> Self {
self.0.header = header.into();
self
}

// TODO: Only keep this is TS stays responsible for exporting which it probs won't.
/// Removes the default Specta header from the output.
pub fn remove_default_header(mut self) -> Self {
self.0.remove_default_header = true;
self
}

/// Configure the BigInt handling behaviour
pub fn bigint(mut self, bigint: BigIntExportBehavior) -> Self {
self.0.bigint = bigint;
self
}

/// Configure a function which is responsible for styling the comments to be exported
///
/// Implementations:
/// - [`js_doc`](crate::lang::ts::js_doc)
///
/// Not calling this method will default to the [`js_doc`](crate::lang::ts::js_doc) exporter.
/// `None` will disable comment exporting.
/// `Some(exporter)` will enable comment exporting using the provided exporter.
pub fn comment_style(mut self, exporter: CommentFormatterFn) -> Self {
self.0.comment_exporter = Some(exporter);
self
}

/// Configure a function which is responsible for formatting the result file or files
///
///
/// Built-in implementations:
/// - [`prettier`](specta_typescript:formatter:::prettier)
/// - [`ESLint`](specta_typescript::formatter::eslint)
/// - [`Biome`](specta_typescript::formatter::biome)e
pub fn formatter(mut self, formatter: FormatterFn) -> Self {
self.0.formatter = Some(formatter);
self
}
}

impl Language for JSDoc {
type Error = specta_typescript::ExportError; // TODO: Custom error type

// TODO: Make this properly export JSDoc
fn export(&self, type_map: TypeMap) -> Result<String, Self::Error> {

Check warning on line 82 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `type_map`

warning: unused variable: `type_map` --> specta-jsdoc/src/lib.rs:82:22 | 82 | fn export(&self, type_map: TypeMap) -> Result<String, Self::Error> { | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_type_map` | = note: `#[warn(unused_variables)]` on by default
todo!("Coming soon...");

Check warning on line 83 in specta-jsdoc/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

`todo` should not be present in production code

warning: `todo` should not be present in production code --> specta-jsdoc/src/lib.rs:83:9 | 83 | todo!("Coming soon..."); | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#todo = note: requested on the command line with `-W clippy::todo`
// let mut out = self.0.header.to_string();
// if !self.0.remove_default_header {
// out += "// This file has been generated by Specta. DO NOT EDIT.\n\n";
// }

// if let Some((ty_name, l0, l1)) = detect_duplicate_type_names(&type_map).into_iter().next() {
// return Err(ExportError::DuplicateTypeName(ty_name, l0, l1));
// }

// for (_, ty) in type_map.iter() {
// is_valid_ty(&ty.inner, &type_map)?;

// out += &export_named_datatype(&self.0, ty, &type_map)?;
// out += "\n\n";
// }

// Ok(out)
}

fn format(&self, path: &Path) -> Result<(), Self::Error> {
if let Some(formatter) = self.0.formatter {
formatter(path)?;
}
Ok(())
}
}
8 changes: 4 additions & 4 deletions specta-typescript/src/formatter.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::{io, path::PathBuf, process::Command};
use std::{io, path::Path, process::Command};

use crate::typescript::FormatterFn;

/// Format the specified file using [ESLint](https://eslint.org).
pub fn eslint(file: PathBuf) -> io::Result<()> {
pub fn eslint(file: &Path) -> io::Result<()> {
Command::new("eslint")
.arg("--fix")
.arg(file)
Expand All @@ -16,7 +16,7 @@ pub fn eslint(file: PathBuf) -> io::Result<()> {
const _: FormatterFn = eslint;

/// Format the specified file using [Prettier](https://prettier.io).
pub fn prettier(file: PathBuf) -> io::Result<()> {
pub fn prettier(file: &Path) -> io::Result<()> {
Command::new("prettier")
.arg("--write")
.arg(file)
Expand All @@ -29,7 +29,7 @@ pub fn prettier(file: PathBuf) -> io::Result<()> {
const _: FormatterFn = prettier;

/// Format the specified file using [Biome](https://prettier.io).
pub fn biome(file: PathBuf) -> io::Result<()> {
pub fn biome(file: &Path) -> io::Result<()> {
Command::new("biome")
.arg("format")
.arg(file)
Expand Down
33 changes: 13 additions & 20 deletions specta-typescript/src/typescript.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::{borrow::Cow, io, path::PathBuf};
use std::{
borrow::Cow,
io,
path::{Path, PathBuf},

Check warning on line 4 in specta-typescript/src/typescript.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `PathBuf`

warning: unused import: `PathBuf` --> specta-typescript/src/typescript.rs:4:18 | 4 | path::{Path, PathBuf}, | ^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
};

use specta::{datatype::DeprecatedType, Language, TypeMap};
use specta_serde::is_valid_ty;
Expand All @@ -16,7 +20,7 @@ pub struct CommentFormatterArgs<'a> {
pub type CommentFormatterFn = fn(CommentFormatterArgs) -> String; // TODO: Returning `Cow`???

/// The signature for a function responsible for formatter a Typescript file.
pub type FormatterFn = fn(PathBuf) -> io::Result<()>;
pub type FormatterFn = fn(&Path) -> io::Result<()>;

/// Allows you to configure how Specta's Typescript exporter will deal with BigInt types ([i64], [i128] etc).
///
Expand Down Expand Up @@ -58,8 +62,6 @@ pub struct Typescript {
pub comment_exporter: Option<CommentFormatterFn>,
/// How the resulting file should be formatted.
pub formatter: Option<FormatterFn>,
/// The path to export the resulting bindings to.
pub path: Option<PathBuf>,
}

impl Default for Typescript {
Expand All @@ -70,7 +72,6 @@ impl Default for Typescript {
bigint: Default::default(),
comment_exporter: Some(comments::js_doc),
formatter: None,
path: None,
}
}
}
Expand Down Expand Up @@ -126,21 +127,6 @@ impl Typescript {
self.formatter = Some(formatter);
self
}

/// TODO
pub fn path(mut self, path: impl Into<PathBuf>) -> Self {
self.path = Some(path.into());
self
}

// TODO: Should this take a `path` or should it use `self.path`???
/// Run the specified formatter on the given path.
pub fn run_format(&self, path: PathBuf) -> io::Result<()> {
if let Some(formatter) = self.formatter {
formatter(path)?;
}
Ok(())
}
}

impl Language for Typescript {
Expand All @@ -165,4 +151,11 @@ impl Language for Typescript {

Ok(out)
}

fn format(&self, path: &Path) -> Result<(), Self::Error> {
if let Some(formatter) = self.formatter {
formatter(path)?;
}
Ok(())
}
}
19 changes: 19 additions & 0 deletions specta/src/language.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::path::Path;

use crate::TypeMap;

/// TODO
Expand All @@ -10,4 +12,21 @@ pub trait Language {

/// TODO
fn export(&self, type_map: TypeMap) -> Result<String, Self::Error>;

/// TODO
// TODO: Not sure I love this here but it's for Tauri Specta.
// TODO: Really a formatter can support multiple languages so it would be nice if we don't need `specta_typescript::eslint`, `specta_jsdoc::eslint`, etc.
fn format(&self, path: &Path) -> Result<(), Self::Error>;
}

impl<T: Language> Language for &T {
type Error = T::Error;

fn export(&self, type_map: TypeMap) -> Result<String, Self::Error> {
(*self).export(type_map)
}

fn format(&self, path: &Path) -> Result<(), Self::Error> {
(*self).format(path)
}
}
4 changes: 4 additions & 0 deletions specta/src/type_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ impl TypeMap {
self.map.remove(&sid).flatten()
}

pub fn append(&mut self, type_map: &mut TypeMap) {
self.map.append(&mut type_map.map);
}

// TODO: It would be nice if this would a proper `Iterator` or `IntoIterator` implementation!
pub fn iter(&self) -> impl Iterator<Item = (SpectaID, &NamedDataType)> {
#[allow(clippy::unnecessary_filter_map)]
Expand Down

0 comments on commit de9d96e

Please sign in to comment.