add common crate

This commit is contained in:
Michael Zhang 2024-11-30 17:52:06 -06:00
parent 14cd99448a
commit 2427daef4e
15 changed files with 745 additions and 94 deletions

178
.gitignore vendored Normal file
View file

@ -0,0 +1,178 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Caches
.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist/*
# Gatsby files
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store
/target

View file

@ -35,6 +35,70 @@ version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
version = "1.0.93"
@ -81,6 +145,7 @@ checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
dependencies = [
"async-trait",
"axum-core",
"axum-macros",
"bytes",
"futures-util",
"http",
@ -128,6 +193,31 @@ dependencies = [
"tracing",
]
[[package]]
name = "axum-embed"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "077959a7f8cf438676af90b483304528eb7e16eadadb7f44e9ada4f9dceb9e62"
dependencies = [
"axum-core",
"chrono",
"http",
"mime_guess",
"rust-embed",
"tower-service",
]
[[package]]
name = "axum-macros"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "backend"
version = "0.1.0"
@ -221,6 +311,80 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.52.6",
]
[[package]]
name = "clap"
version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
[[package]]
name = "cli"
version = "0.1.0"
dependencies = [
"anyhow",
"axum",
"axum-embed",
"backend",
"clap",
"rust-embed",
"tokio",
"tower-http",
]
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "concurrent-queue"
version = "2.5.0"
@ -372,7 +536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -688,6 +852,12 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "http-range-header"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
[[package]]
name = "httparse"
version = "1.9.5"
@ -773,6 +943,29 @@ dependencies = [
"tracing",
]
[[package]]
name = "iana-time-zone"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "icu_collections"
version = "1.5.0"
@ -928,6 +1121,12 @@ version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.14"
@ -1032,6 +1231,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
dependencies = [
"mime",
"unicase",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@ -1426,6 +1635,40 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rust-embed"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
dependencies = [
"sha2",
"walkdir",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -1496,6 +1739,15 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.27"
@ -1903,6 +2155,12 @@ dependencies = [
"unicode-properties",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
@ -1977,7 +2235,7 @@ dependencies = [
"fastrand",
"once_cell",
"rustix",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -2115,6 +2373,31 @@ dependencies = [
"tracing",
]
[[package]]
name = "tower-http"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697"
dependencies = [
"bitflags",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"http-range-header",
"httpdate",
"mime",
"mime_guess",
"percent-encoding",
"pin-project-lite",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
@ -2171,6 +2454,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicase"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
[[package]]
name = "unicode-bidi"
version = "0.3.17"
@ -2233,6 +2522,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vcpkg"
version = "0.2.15"
@ -2245,6 +2540,16 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"
@ -2367,6 +2672,24 @@ dependencies = [
"wasite",
]
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-registry"
version = "0.2.0"

2
Cargo.toml Normal file
View file

@ -0,0 +1,2 @@
workspace.resolver = "2"
workspace.members = ["backend", "cli"]

114
backend/src/lib.rs Normal file
View file

@ -0,0 +1,114 @@
#[macro_use]
extern crate serde;
#[macro_use]
extern crate serde_json;
mod block;
mod error;
mod worker;
use anyhow::Result;
use axum::{
routing::{delete, get, post},
Router,
};
use sqlx::{
migrate,
sqlite::{SqliteConnectOptions, SqlitePoolOptions, UpdateHookResult},
SqlitePool,
};
use tokio::{
net::TcpListener,
sync::{
mpsc::{self, UnboundedSender},
oneshot,
},
};
use crate::block::{
create_block, delete_block, get_block, list_blocks, update_block,
};
pub use crate::worker::worker;
pub type ExitSender = oneshot::Sender<()>;
pub type ExitListener = oneshot::Receiver<()>;
#[derive(Clone)]
pub struct AppState {
pub db: SqlitePool,
}
#[derive(Debug)]
pub struct DatabaseUpdate {}
pub async fn prepare_database(
tx: UnboundedSender<DatabaseUpdate>,
) -> Result<SqlitePool> {
let options = SqliteConnectOptions::new()
.filename("test.db")
.create_if_missing(true);
let tx = tx.clone();
let db = SqlitePoolOptions::new()
.after_connect(move |c, md| {
let tx = tx.clone();
Box::pin(async {
let mut c = c.lock_handle().await?;
c.set_update_hook(move |u: UpdateHookResult<'_>| {
if u.table == "blocks" {
tx.send(DatabaseUpdate {}).unwrap();
}
});
Ok(())
})
})
.connect_with(options)
.await?;
migrate!().run(&db).await?;
Ok(db)
}
pub async fn router(
tx: UnboundedSender<DatabaseUpdate>,
) -> Result<(AppState, Router)> {
let db = prepare_database(tx).await?;
let state = AppState { db };
let state2 = state.clone();
Ok((
state2,
Router::new()
// Block CRUD
.route("/block", get(list_blocks))
.route("/block", post(create_block))
.route("/block/:id", get(get_block))
.route("/block/:id", post(update_block))
.route("/block/:id", delete(delete_block))
.with_state(state),
))
}
// async fn main() -> Result<()> {
// let (mut tx, database_updates) = mpsc::unbounded_channel();
// let state = AppState { db };
// tokio::spawn(worker(state.clone(), database_updates));
// tx.send(DatabaseUpdate {});
// let app = Router::new()
// // Block CRUD
// .route("/block", get(list_blocks))
// .route("/block", post(create_block))
// .route("/block/:id", get(get_block))
// .route("/block/:id", post(update_block))
// .route("/block/:id", delete(delete_block))
// .with_state(state);
// let listener = TcpListener::bind("0.0.0.0:3000").await?;
// axum::serve(listener, app).await?;
// Ok(())
// }

View file

@ -1,92 +0,0 @@
#[macro_use]
extern crate serde;
#[macro_use]
extern crate serde_json;
mod block;
mod error;
mod worker;
use anyhow::Result;
use axum::{
routing::{delete, get, post},
Router,
};
use sqlx::{
migrate,
sqlite::{SqliteConnectOptions, SqlitePoolOptions, UpdateHookResult},
SqlitePool,
};
use tokio::{
net::TcpListener,
sync::{
mpsc::{self},
oneshot,
},
};
use crate::block::{
create_block, delete_block, get_block, list_blocks, update_block,
};
use crate::worker::worker;
pub type ExitSender = oneshot::Sender<()>;
pub type ExitListener = oneshot::Receiver<()>;
#[derive(Clone)]
pub struct AppState {
pub db: SqlitePool,
}
#[derive(Debug)]
pub struct DatabaseUpdate {}
#[tokio::main]
async fn main() -> Result<()> {
let (mut tx, database_updates) = mpsc::unbounded_channel();
let db = {
let options = SqliteConnectOptions::new()
.filename("test.db")
.create_if_missing(true);
let tx = tx.clone();
SqlitePoolOptions::new()
.after_connect(move |c, md| {
let tx = tx.clone();
Box::pin(async {
let mut c = c.lock_handle().await?;
c.set_update_hook(move |u: UpdateHookResult<'_>| {
if u.table == "blocks" {
tx.send(DatabaseUpdate {}).unwrap();
}
});
Ok(())
})
})
.connect_with(options)
.await?
};
migrate!().run(&db).await?;
let state = AppState { db };
tokio::spawn(worker(state.clone(), database_updates));
tx.send(DatabaseUpdate {});
let app = Router::new()
// Block CRUD
.route("/block", get(list_blocks))
.route("/block", post(create_block))
.route("/block/:id", get(get_block))
.route("/block/:id", post(update_block))
.route("/block/:id", delete(delete_block))
.with_state(state);
let listener = TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, app).await?;
Ok(())
}

BIN
bun.lockb Normal file

Binary file not shown.

2
cli/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
dist/*
!dist/.gitkeep

15
cli/Cargo.toml Normal file
View file

@ -0,0 +1,15 @@
[package]
name = "cli"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.93"
axum = { version = "0.7.9", features = ["json", "macros"] }
clap = { version = "4.5.21", features = ["derive", "env"] }
tokio = { version = "1.41.1", features = ["full"] }
backend = { path = "../backend" }
tower-http = { version = "0.6.2", features = ["fs"] }
axum-embed = "0.1.0"
rust-embed = "8.5.0"

0
cli/dist/.gitkeep vendored Normal file
View file

55
cli/src/main.rs Normal file
View file

@ -0,0 +1,55 @@
use anyhow::Result;
use axum::{
routing::{delete, get, post},
Router,
};
use axum_embed::ServeEmbed;
use backend::{prepare_database, worker, AppState};
use clap::{Parser, Subcommand};
use rust_embed::Embed;
use tokio::{net::TcpListener, sync::mpsc};
use tower_http::services::ServeDir;
#[derive(Debug, Parser)]
struct Opt {
#[clap(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
Server(ServerOpts),
}
#[derive(Debug, Parser)]
struct ServerOpts {
#[clap(default_value = "3000")]
port: u16,
}
#[derive(Embed, Clone)]
#[folder = "dist"]
struct Frontend;
#[tokio::main]
async fn main() -> Result<()> {
let opt = Opt::parse();
match opt.command {
Command::Server(server_opts) => {
let (mut tx, database_updates) = mpsc::unbounded_channel();
let (state, router) = backend::router(tx).await?;
// spawn the router
tokio::spawn(worker(state, database_updates));
let app = Router::new()
.nest("/api", router)
.nest_service("/", ServeEmbed::<Frontend>::new());
let listener = TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, app).await?;
}
}
Ok(())
}

1
index.ts Normal file
View file

@ -0,0 +1 @@
console.log("Hello via Bun!");

12
package.json Normal file
View file

@ -0,0 +1,12 @@
{
"name": "mzautomate",
"module": "index.ts",
"type": "module",
"scripts": {"build":"bun run scripts/build.ts"},
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}

14
scripts/build.ts Normal file
View file

@ -0,0 +1,14 @@
import { $ } from "bun";
async function buildFrontend() {
await $`bun run vite build`.cwd("frontend");
}
async function buildBackend() {
await $`cargo build --release`.cwd("backend");
}
await Promise.all([buildBackend(), buildFrontend()]);
await $`mv frontend/dist/* cli/dist`;
await $`cargo build --release -p cli`;

27
tsconfig.json Normal file
View file

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}