diff --git a/.gitignore b/.gitignore index 599033f..1d195c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # Generated by Cargo # will have compiled files and executables /target/ - +node_modules/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 0b61eec..cb825ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] -resolver = "1" -members = ["server", "cli"] +resolver= "2" +members = ["lykiadb-server", "lykiadb-shell", "lykiadb-connect", "lykiadb-playground"] +edition = "2021" [profile.release] opt-level = 3 diff --git a/README.md b/README.md index e1cc533..bae906a 100644 --- a/README.md +++ b/README.md @@ -47,12 +47,12 @@ To use Lykia, you can download the latest release from the GitHub releases page. Run the server: ```shell -$ cargo run --release --bin lykiadb-server +$ cargo run --release --bin lykiadb-lykiadb-server ``` Run the client: ```shell -$ cargo run --release --bin lykiadb-shell cli/examples/fib.ly +$ cargo run --release --bin lykiadb-shell lykiadb-shell/examples/fib.ly ``` Client transmits the fib.ly in an infinite loop. diff --git a/cli/src/lib.rs b/cli/src/lib.rs deleted file mode 100644 index dfee744..0000000 --- a/cli/src/lib.rs +++ /dev/null @@ -1,25 +0,0 @@ -use lykiadb_server::net::{CommunicationError, Connection, Message}; -use tokio::net::TcpStream; - -pub struct ClientSession { - conn: Connection, -} - -impl ClientSession { - pub fn new(stream: TcpStream) -> Self { - ClientSession { - conn: Connection::new(stream), - } - } - - pub async fn handle(&mut self) -> Result { - match self.conn.read().await.unwrap() { - Some(message) => Ok(message), - None => Err(()), - } - } - - pub async fn send(&mut self, msg: Message) -> Result<(), CommunicationError> { - self.conn.write(msg).await - } -} diff --git a/cli/src/main.rs b/cli/src/main.rs deleted file mode 100644 index 74fffe4..0000000 --- a/cli/src/main.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::{ - fs::File, - io::{stdin, stdout, BufReader, Read, Write}, -}; - -use clap::Parser; -use lykiadb_server::{ - net::{Message, Request, Response}, - runtime::error::report_error, -}; -use lykiadb_shell::ClientSession; -use tokio::net::TcpStream; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - /// Path to the script to be executed - filename: Option, - - #[clap(short, long, default_value = "false")] - print_ast: bool, -} - -async fn run_repl() { - println!("REPL mode"); - let mut line = String::new(); - let socket = TcpStream::connect("localhost:19191").await.unwrap(); - let mut session = ClientSession::new(socket); - loop { - print!("lykia > "); - let _ = stdout().flush(); - stdin().read_line(&mut line).expect("Invalid input"); - if line.is_empty() || line.trim() == ".exit" { - break; - } - session - .send(Message::Request(Request::Run(line.to_string()))) - .await - .unwrap(); - - let response = session.handle().await.unwrap(); - - match response { - Message::Response(Response::Value(result)) => println!("{:?}", result), - Message::Response(Response::Program(value)) => { - println!("{}", serde_json::to_string_pretty(&value).unwrap()) - } - Message::Response(Response::Error(err)) => report_error("prompt", &line, err.clone()), - _ => panic!(""), - } - - line.clear(); - } -} - -async fn run_file(filename: &str, print_ast: bool) { - let file = File::open(filename).expect("File couldn't be opened."); - - let mut content: String = String::new(); - - BufReader::new(file) - .read_to_string(&mut content) - .expect("File couldn't be read."); - - let socket = TcpStream::connect("localhost:19191").await.unwrap(); - - let mut session = ClientSession::new(socket); - let msg = if print_ast { - Message::Request(Request::Ast(content.to_string())) - } else { - Message::Request(Request::Run(content.to_string())) - }; - - session.send(msg).await.unwrap(); - - let response = session.handle().await.unwrap(); - match response { - Message::Response(Response::Value(result)) => println!("{:?}", result), - Message::Response(Response::Program(value)) => { - println!("{}", serde_json::to_string_pretty(&value).unwrap()) - } - Message::Response(Response::Error(err)) => report_error(filename, &content, err.clone()), - _ => panic!(""), - } -} - -#[tokio::main] -async fn main() { - let args = Args::parse(); - match args.filename { - Some(filename) => run_file(&filename, args.print_ast).await, - None => run_repl().await, - }; -} diff --git a/lykiadb-connect/Cargo.toml b/lykiadb-connect/Cargo.toml new file mode 100644 index 0000000..d96db9f --- /dev/null +++ b/lykiadb-connect/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["Vedat Can Keklik "] +name = "lykiadb-connect" +version = "0.1.0" +edition = "2021" + +[dependencies] +bson = { version = "2.9.0" } +clap = { version = "4.4.6", features = ["derive"] } +lykiadb-server = { path = "../lykiadb-server" } +serde_json = "1.0.105" +tokio = { version = "~1.35.1" } +bytes = "1.5.0" +serde = { version = "1.0.188", features=["derive", "rc"] } diff --git a/lykiadb-connect/src/lib.rs b/lykiadb-connect/src/lib.rs new file mode 100644 index 0000000..76b90e0 --- /dev/null +++ b/lykiadb-connect/src/lib.rs @@ -0,0 +1,29 @@ +use tokio::net::TcpStream; +use crate::session::ClientSession; +use crate::tcp::TcpClientSession; + +pub mod session; +mod tcp; + +pub use lykiadb_server::net::{Message, Request, Response}; +pub use lykiadb_server::runtime::error::{report_error}; + +pub enum Protocol { + Tcp, + Http +} + +pub async fn get_session(addr: &str, protocol: Protocol) -> impl ClientSession { + match protocol { + Protocol::Tcp => { + let socket = TcpStream::connect(addr).await.unwrap(); + TcpClientSession::new(socket) + } + Protocol::Http => { + panic!("Http not implemented!") + } + } +} +pub async fn connect(addr: &str) -> impl ClientSession { + get_session(addr, Protocol::Tcp).await +} \ No newline at end of file diff --git a/lykiadb-connect/src/session.rs b/lykiadb-connect/src/session.rs new file mode 100644 index 0000000..8870737 --- /dev/null +++ b/lykiadb-connect/src/session.rs @@ -0,0 +1,6 @@ +use lykiadb_server::net::Message; + +pub trait ClientSession { + async fn send_receive(&mut self, msg: Message) -> Result; + async fn execute(&mut self, query: &str) -> Result; +} \ No newline at end of file diff --git a/lykiadb-connect/src/tcp.rs b/lykiadb-connect/src/tcp.rs new file mode 100644 index 0000000..c358c49 --- /dev/null +++ b/lykiadb-connect/src/tcp.rs @@ -0,0 +1,38 @@ +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::TcpStream; +use lykiadb_server::net::{CommunicationError, Message, Request}; +use lykiadb_server::net::tcp::TcpConnection; +use crate::session::ClientSession; + +pub(crate) struct TcpClientSession { + conn: TcpConnection, +} + +impl TcpClientSession { + pub fn new(stream: TcpStream) -> Self { + TcpClientSession { + conn: TcpConnection::new(stream), + } + } + + async fn handle(&mut self) -> Result { + match self.conn.read().await.unwrap() { + Some(message) => Ok(message), + None => Err(()), + } + } + + async fn send(&mut self, msg: Message) -> Result<(), CommunicationError> { + self.conn.write(msg).await + } +} +impl ClientSession for TcpClientSession { + async fn send_receive(&mut self, msg: Message) -> Result { + self.send(msg).await.unwrap(); + self.handle().await + } + + async fn execute(&mut self, query: &str) -> Result { + self.send_receive(Message::Request(Request::Run(query.to_string()))).await + } +} diff --git a/lykiadb-playground/Cargo.toml b/lykiadb-playground/Cargo.toml new file mode 100644 index 0000000..9b245fd --- /dev/null +++ b/lykiadb-playground/Cargo.toml @@ -0,0 +1,96 @@ +[package] +name = "lykiadb-playground" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +actix-files = { version = "0.6", optional = true } +actix-web = { version = "4", optional = true, features = ["macros"] } +console_error_panic_hook = "0.1" +http = { version = "1.0.0", optional = true } +leptos = { version = "0.6" } +leptos_meta = { version = "0.6" } +leptos_actix = { version = "0.6", optional = true } +leptos_router = { version = "0.6" } +wasm-bindgen = "=0.2.92" +lykiadb-connect = { path = "../lykiadb-connect", optional = true } + +[features] +csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"] +hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"] +ssr = [ + "dep:actix-files", + "dep:actix-web", + "dep:leptos_actix", + "dep:lykiadb-connect", + "leptos/ssr", + "leptos_meta/ssr", + "leptos_router/ssr", +] + +# Defines a size-optimized profile for the WASM bundle in release mode +[profile.wasm-release] +inherits = "release" +opt-level = 'z' +lto = true +codegen-units = 1 +panic = "abort" + +[package.metadata.leptos] +# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name +output-name = "lykiadb-playground" +# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup. +site-root = "target/site" +# The site-root relative folder where all compiled output (JS, WASM and CSS) is written +# Defaults to pkg +site-pkg-dir = "pkg" +# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to //app.css +# style-file = "style/main.scss" +tailwind-input-file = "style/tailwind.css" +tailwind-config-file = "tailwind.config.js" + +# Assets source dir. All files found here will be copied and synchronized to site-root. +# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir. +# +# Optional. Env: LEPTOS_ASSETS_DIR. +assets-dir = "assets" +# The IP and port (ex: 127.0.0.1:8888) where the server serves the content. Use it in your server setup. +site-addr = "127.0.0.1:8888" +# The port to use for automatic reload monitoring +reload-port = 8889 +# [Optional] Command to use when running end2end tests. It will run in the end2end dir. +# [Windows] for non-WSL use "npx.cmd playwright test" +# This binary name can be checked in Powershell with Get-Command npx +end2end-cmd = "npx playwright test" +end2end-dir = "end2end" +# The browserlist query used for optimizing the CSS. +browserquery = "defaults" +# The environment Leptos will run in, usually either "DEV" or "PROD" +env = "DEV" +# The features to use when compiling the bin target +# +# Optional. Can be over-ridden with the command line parameter --bin-features +bin-features = ["ssr"] + +# If the --no-default-features flag should be used when compiling the bin target +# +# Optional. Defaults to false. +bin-default-features = false + +# The features to use when compiling the lib target +# +# Optional. Can be over-ridden with the command line parameter --lib-features +lib-features = ["hydrate"] + +# If the --no-default-features flag should be used when compiling the lib target +# +# Optional. Defaults to false. +lib-default-features = false + +# The profile to use for the lib target when compiling for release +# +# Optional. Defaults to "release". +lib-profile-release = "wasm-release" diff --git a/lykiadb-playground/LICENSE b/lykiadb-playground/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/lykiadb-playground/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/lykiadb-playground/README.md b/lykiadb-playground/README.md new file mode 100644 index 0000000..44cc974 --- /dev/null +++ b/lykiadb-playground/README.md @@ -0,0 +1,72 @@ + + + Leptos Logo + + +# Leptos Starter Template + +This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool. + +## Creating your template repo + +If you don't have `cargo-leptos` installed you can install it with + +`cargo install cargo-leptos` + +Then run + +`cargo leptos new --git leptos-rs/start` + +to generate a new project template (you will be prompted to enter a project name). + +`cd {projectname}` + +to go to your newly created project. + +Of course, you should explore around the project structure, but the best place to start with your application code is in `src/app.rs`. + +## Running your project + +`cargo leptos watch` +By default, you can access your local project at `http://localhost:3000` + +## Installing Additional Tools + +By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools. + +1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly +2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly +3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future) +4. `npm install -g sass` - install `dart-sass` (should be optional in future) + +## Executing a Server on a Remote Machine Without the Toolchain +After running a `cargo leptos build --release` the minimum files needed are: + +1. The server binary located in `target/server/release` +2. The `site` directory and all files within located in `target/site` + +Copy these files to your remote server. The directory structure should be: +```text +leptos_start +site/ +``` +Set the following environment variables (updating for your project as needed): +```sh +export LEPTOS_OUTPUT_NAME="leptos_start" +export LEPTOS_SITE_ROOT="site" +export LEPTOS_SITE_PKG_DIR="pkg" +export LEPTOS_SITE_ADDR="127.0.0.1:3000" +export LEPTOS_RELOAD_PORT="3001" +``` +Finally, run the server binary. + +## Notes about CSR and Trunk: +Although it is not recommended, you can also run your project without server integration using the feature `csr` and `trunk serve`: + +`trunk serve --open --features csr` + +This may be useful for integrating external tools which require a static site, e.g. `tauri`. + +## Licensing + +This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly. diff --git a/lykiadb-playground/assets/favicon.ico b/lykiadb-playground/assets/favicon.ico new file mode 100644 index 0000000..2ba8527 Binary files /dev/null and b/lykiadb-playground/assets/favicon.ico differ diff --git a/lykiadb-playground/end2end/package-lock.json b/lykiadb-playground/end2end/package-lock.json new file mode 100644 index 0000000..f12af44 --- /dev/null +++ b/lykiadb-playground/end2end/package-lock.json @@ -0,0 +1,74 @@ +{ + "name": "end2end", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "end2end", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.28.0" + } + }, + "node_modules/@playwright/test": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", + "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.28.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "node_modules/playwright-core": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", + "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", + "dev": true, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + } + }, + "dependencies": { + "@playwright/test": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", + "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", + "dev": true, + "requires": { + "@types/node": "*", + "playwright-core": "1.28.0" + } + }, + "@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "playwright-core": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", + "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", + "dev": true + } + } +} diff --git a/lykiadb-playground/end2end/package.json b/lykiadb-playground/end2end/package.json new file mode 100644 index 0000000..ed78585 --- /dev/null +++ b/lykiadb-playground/end2end/package.json @@ -0,0 +1,13 @@ +{ + "name": "end2end", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.28.0" + } +} diff --git a/lykiadb-playground/end2end/playwright.config.ts b/lykiadb-playground/end2end/playwright.config.ts new file mode 100644 index 0000000..e9891c0 --- /dev/null +++ b/lykiadb-playground/end2end/playwright.config.ts @@ -0,0 +1,107 @@ +import type { PlaywrightTestConfig } from "@playwright/test"; +import { devices } from "@playwright/test"; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +const config: PlaywrightTestConfig = { + testDir: "./tests", + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: "html", + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://localhost:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: "on-first-retry", + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: "chromium", + use: { + ...devices["Desktop Chrome"], + }, + }, + + { + name: "firefox", + use: { + ...devices["Desktop Firefox"], + }, + }, + + { + name: "webkit", + use: { + ...devices["Desktop Safari"], + }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { + // ...devices['Pixel 5'], + // }, + // }, + // { + // name: 'Mobile Safari', + // use: { + // ...devices['iPhone 12'], + // }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // port: 3000, + // }, +}; + +export default config; diff --git a/lykiadb-playground/end2end/tests/example.spec.ts b/lykiadb-playground/end2end/tests/example.spec.ts new file mode 100644 index 0000000..a461f35 --- /dev/null +++ b/lykiadb-playground/end2end/tests/example.spec.ts @@ -0,0 +1,9 @@ +import { test, expect } from "@playwright/test"; + +test("homepage has title and links to intro page", async ({ page }) => { + await page.goto("http://localhost:3000/"); + + await expect(page).toHaveTitle("Welcome to Leptos"); + + await expect(page.locator("h1")).toHaveText("Welcome to Leptos!"); +}); diff --git a/lykiadb-playground/package.json b/lykiadb-playground/package.json new file mode 100644 index 0000000..77a37c4 --- /dev/null +++ b/lykiadb-playground/package.json @@ -0,0 +1,7 @@ +{ + "devDependencies": { + "tailwindcss": "^3.4.3", + "@tailwindcss/typography": "^0.5.13", + "daisyui": "^4.11.1" + } +} diff --git a/lykiadb-playground/pnpm-lock.yaml b/lykiadb-playground/pnpm-lock.yaml new file mode 100644 index 0000000..e808775 --- /dev/null +++ b/lykiadb-playground/pnpm-lock.yaml @@ -0,0 +1,794 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +devDependencies: + '@tailwindcss/typography': + specifier: ^0.5.13 + version: 0.5.13(tailwindcss@3.4.3) + daisyui: + specifier: ^4.11.1 + version: 4.11.1(postcss@8.4.38) + tailwindcss: + specifier: ^3.4.3 + version: 3.4.3 + +packages: + + /@alloc/quick-lru@5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + dev: true + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + + /@tailwindcss/typography@0.5.13(tailwindcss@3.4.3): + resolution: {integrity: sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.3 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + dev: true + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: true + + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /css-selector-tokenizer@0.8.0: + resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} + dependencies: + cssesc: 3.0.0 + fastparse: 1.1.2 + dev: true + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /culori@3.3.0: + resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /daisyui@4.11.1(postcss@8.4.38): + resolution: {integrity: sha512-obT9CUbQdW6eoHwSeT5VwaRrWlwrM4OT5qlfdJ0oQlSIEYhwnEl2+L2fwu5PioLbitwuMdYC2X8I1cyy8Pf6LQ==} + engines: {node: '>=16.9.0'} + dependencies: + css-selector-tokenizer: 0.8.0 + culori: 3.3.0 + picocolors: 1.0.1 + postcss-js: 4.0.1(postcss@8.4.38) + transitivePeerDependencies: + - postcss + dev: true + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 + dev: true + + /fastparse@1.1.2: + resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} + dev: true + + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + dev: true + + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@10.4.1: + resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} + engines: {node: '>=16 || 14 >=14.18'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.1.2 + minimatch: 9.0.4 + minipass: 7.1.2 + path-scurry: 1.11.1 + dev: true + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.2 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /jackspeak@3.1.2: + resolution: {integrity: sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + + /jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + dev: true + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + + /lilconfig@3.1.1: + resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} + engines: {node: '>=14'} + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + dev: true + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + dev: true + + /minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + dependencies: + lru-cache: 10.2.2 + minipass: 7.1.2 + dev: true + + /picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + + /postcss-import@15.1.0(postcss@8.4.38): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + dev: true + + /postcss-js@4.0.1(postcss@8.4.38): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.38 + dev: true + + /postcss-load-config@4.0.2(postcss@8.4.38): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.1 + postcss: 8.4.38 + yaml: 2.4.2 + dev: true + + /postcss-nested@6.0.1(postcss@8.4.38): + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.38 + postcss-selector-parser: 6.1.0 + dev: true + + /postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-selector-parser@6.1.0: + resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + + /postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.4.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /tailwindcss@3.4.3: + resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.0 + lilconfig: 2.1.0 + micromatch: 4.0.7 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-import: 15.1.0(postcss@8.4.38) + postcss-js: 4.0.1(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + postcss-nested: 6.0.1(postcss@8.4.38) + postcss-selector-parser: 6.1.0 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + dev: true + + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /yaml@2.4.2: + resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} + engines: {node: '>= 14'} + hasBin: true + dev: true diff --git a/lykiadb-playground/src/app.rs b/lykiadb-playground/src/app.rs new file mode 100644 index 0000000..0e73d3a --- /dev/null +++ b/lykiadb-playground/src/app.rs @@ -0,0 +1,107 @@ +use leptos::*; +use leptos_meta::*; +use leptos_router::*; + +#[component] +pub fn App() -> impl IntoView { + // Provides context that manages stylesheets, titles, meta tags, etc. + provide_meta_context(); + + view! { + // injects a stylesheet into the document + // id=leptos means cargo-leptos will hot-reload this stylesheet + + + // sets the document title + + + // content for this welcome page + <Router> + <main> + <Routes> + <Route path="" view=HomePage/> + <Route path="/*any" view=NotFound/> + </Routes> + </main> + </Router> + } +} + +#[server(ExecuteCode, "/api")] +pub async fn execute_code(code: String) -> Result<String, ServerFnError> { + use lykiadb_connect::session::ClientSession; + use lykiadb_connect::{Message, Response, connect}; + + let mut conn = connect("localhost:19191").await; + let resp = conn.execute(&code).await; + + if let Ok(Message::Response(Response::Value(val))) = resp { + Ok(format!("{:?}", val)) + } else { + Err(ServerFnError::new("Failed to execute query")) + } +} + +/// Renders the home page of your application. +#[component] +fn HomePage() -> impl IntoView { + // Creates a reactive value to update the button + let (code, set_code) = create_signal("Controlled".to_string()); + + let executor = create_action(|c: &String| { + let q = c.to_owned(); + async move { + execute_code(q).await + } + }); + let result = executor.value(); + + view! { + <div class="w-full bg-gradient-to-tl p-6 justify-center from-blue-800 to-blue-500 text-white font-mono flex flex-col min-h-screen"> + <div class="w-full flex justify-center justify-end font-bold"> + <div class="card sm:w-96 w-full bg-base-100 shadow-xl"> + <div class="card-body"> + <textarea + class="text-black" + on:input=move |ev| { + set_code.set(event_target_value(&ev)); + } + prop:value=code + /> + <div class="card-actions justify-end"> + <button class="btn btn-primary" on:click=move |_| { + let c = code.get().clone(); + executor.dispatch(c); + }> + "Execute" + </button> + </div> + <div class="text-black border">{move || format!("{:#?}", result.get())}</div> + </div> + </div> + </div> + </div> + } +} + +/// 404 - Not Found +#[component] +fn NotFound() -> impl IntoView { + // set an HTTP status code 404 + // this is feature gated because it can only be done during + // initial server-side rendering + // if you navigate to the 404 page subsequently, the status + // code will not be set because there is not a new HTTP request + // to the server + #[cfg(feature = "ssr")] + { + // this can be done inline because it's synchronous + // if it were async, we'd use a server function + let resp = expect_context::<leptos_actix::ResponseOptions>(); + resp.set_status(actix_web::http::StatusCode::NOT_FOUND); + } + + view! { + <h1>"Not Found"</h1> + } +} diff --git a/lykiadb-playground/src/lib.rs b/lykiadb-playground/src/lib.rs new file mode 100644 index 0000000..daa8cfb --- /dev/null +++ b/lykiadb-playground/src/lib.rs @@ -0,0 +1,12 @@ +pub mod app; + +#[cfg(feature = "hydrate")] +#[wasm_bindgen::prelude::wasm_bindgen] +pub fn hydrate() { + use app::*; + use leptos::*; + + console_error_panic_hook::set_once(); + + mount_to_body(App); +} diff --git a/lykiadb-playground/src/main.rs b/lykiadb-playground/src/main.rs new file mode 100644 index 0000000..bb6b3f2 --- /dev/null +++ b/lykiadb-playground/src/main.rs @@ -0,0 +1,66 @@ +#[cfg(feature = "ssr")] +#[actix_web::main] +async fn main() -> std::io::Result<()> { + use actix_files::Files; + use actix_web::*; + use leptos::*; + use leptos_actix::{generate_route_list, LeptosRoutes}; + use lykiadb_playground::app::*; + + let conf = get_configuration(None).await.unwrap(); + let addr = conf.leptos_options.site_addr; + // Generate the list of routes in your Leptos App + let routes = generate_route_list(App); + println!("listening on http://{}", &addr); + + HttpServer::new(move || { + let leptos_options = &conf.leptos_options; + let site_root = &leptos_options.site_root; + + App::new() + // serve JS/WASM/CSS from `pkg` + .service(Files::new("/pkg", format!("{site_root}/pkg"))) + // serve other assets from the `assets` directory + .service(Files::new("/assets", site_root)) + // serve the favicon from /favicon.ico + .service(favicon) + .leptos_routes(leptos_options.to_owned(), routes.to_owned(), App) + .app_data(web::Data::new(leptos_options.to_owned())) + //.wrap(middleware::Compress::default()) + }) + .bind(&addr)? + .run() + .await +} + +#[cfg(feature = "ssr")] +#[actix_web::get("favicon.ico")] +async fn favicon( + leptos_options: actix_web::web::Data<leptos::LeptosOptions>, +) -> actix_web::Result<actix_files::NamedFile> { + let leptos_options = leptos_options.into_inner(); + let site_root = &leptos_options.site_root; + Ok(actix_files::NamedFile::open(format!( + "{site_root}/favicon.ico" + ))?) +} + +#[cfg(not(any(feature = "ssr", feature = "csr")))] +pub fn main() { + // no client-side main function + // unless we want this to work with e.g., Trunk for pure client-side testing + // see lib.rs for hydration function instead + // see optional feature `csr` instead +} + +#[cfg(all(not(feature = "ssr"), feature = "csr"))] +pub fn main() { + // a client-side main function is required for using `trunk serve` + // prefer using `cargo leptos serve` instead + // to run: `trunk serve --open --features csr` + use lykiadb_playground::app::*; + + console_error_panic_hook::set_once(); + + leptos::mount_to_body(App); +} diff --git a/lykiadb-playground/style/main.scss b/lykiadb-playground/style/main.scss new file mode 100644 index 0000000..e4538e1 --- /dev/null +++ b/lykiadb-playground/style/main.scss @@ -0,0 +1,4 @@ +body { + font-family: sans-serif; + text-align: center; +} \ No newline at end of file diff --git a/lykiadb-playground/style/tailwind.css b/lykiadb-playground/style/tailwind.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/lykiadb-playground/style/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/lykiadb-playground/tailwind.config.js b/lykiadb-playground/tailwind.config.js new file mode 100644 index 0000000..6607314 --- /dev/null +++ b/lykiadb-playground/tailwind.config.js @@ -0,0 +1,13 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: { + files: ["*.html", "*/src/**/*.rs"], + }, + theme: { + extend: {}, + }, + plugins: [require('daisyui')], + daisyui: { + logs: false, + }, +}; diff --git a/server/Cargo.toml b/lykiadb-server/Cargo.toml similarity index 100% rename from server/Cargo.toml rename to lykiadb-server/Cargo.toml diff --git a/server/benches/interpreter.rs b/lykiadb-server/benches/interpreter.rs similarity index 100% rename from server/benches/interpreter.rs rename to lykiadb-server/benches/interpreter.rs diff --git a/server/benches/scripts/fib.ly b/lykiadb-server/benches/scripts/fib.ly similarity index 100% rename from server/benches/scripts/fib.ly rename to lykiadb-server/benches/scripts/fib.ly diff --git a/server/benches/scripts/for.ly b/lykiadb-server/benches/scripts/for.ly similarity index 100% rename from server/benches/scripts/for.ly rename to lykiadb-server/benches/scripts/for.ly diff --git a/server/benches/scripts/while.ly b/lykiadb-server/benches/scripts/while.ly similarity index 100% rename from server/benches/scripts/while.ly rename to lykiadb-server/benches/scripts/while.ly diff --git a/server/benches/scripts/while.short.ly b/lykiadb-server/benches/scripts/while.short.ly similarity index 100% rename from server/benches/scripts/while.short.ly rename to lykiadb-server/benches/scripts/while.short.ly diff --git a/server/src/lang/ast/expr.rs b/lykiadb-server/src/lang/ast/expr.rs similarity index 100% rename from server/src/lang/ast/expr.rs rename to lykiadb-server/src/lang/ast/expr.rs diff --git a/server/src/lang/ast/mod.rs b/lykiadb-server/src/lang/ast/mod.rs similarity index 100% rename from server/src/lang/ast/mod.rs rename to lykiadb-server/src/lang/ast/mod.rs diff --git a/server/src/lang/ast/sql.rs b/lykiadb-server/src/lang/ast/sql.rs similarity index 100% rename from server/src/lang/ast/sql.rs rename to lykiadb-server/src/lang/ast/sql.rs diff --git a/server/src/lang/ast/stmt.rs b/lykiadb-server/src/lang/ast/stmt.rs similarity index 100% rename from server/src/lang/ast/stmt.rs rename to lykiadb-server/src/lang/ast/stmt.rs diff --git a/server/src/lang/ast/visitor.rs b/lykiadb-server/src/lang/ast/visitor.rs similarity index 100% rename from server/src/lang/ast/visitor.rs rename to lykiadb-server/src/lang/ast/visitor.rs diff --git a/server/src/lang/mod.rs b/lykiadb-server/src/lang/mod.rs similarity index 100% rename from server/src/lang/mod.rs rename to lykiadb-server/src/lang/mod.rs diff --git a/server/src/lang/parser/mod.rs b/lykiadb-server/src/lang/parser/mod.rs similarity index 100% rename from server/src/lang/parser/mod.rs rename to lykiadb-server/src/lang/parser/mod.rs diff --git a/server/src/lang/parser/program.rs b/lykiadb-server/src/lang/parser/program.rs similarity index 100% rename from server/src/lang/parser/program.rs rename to lykiadb-server/src/lang/parser/program.rs diff --git a/server/src/lang/parser/resolver.rs b/lykiadb-server/src/lang/parser/resolver.rs similarity index 100% rename from server/src/lang/parser/resolver.rs rename to lykiadb-server/src/lang/parser/resolver.rs diff --git a/server/src/lang/tokenizer/mod.rs b/lykiadb-server/src/lang/tokenizer/mod.rs similarity index 100% rename from server/src/lang/tokenizer/mod.rs rename to lykiadb-server/src/lang/tokenizer/mod.rs diff --git a/server/src/lang/tokenizer/scanner.rs b/lykiadb-server/src/lang/tokenizer/scanner.rs similarity index 100% rename from server/src/lang/tokenizer/scanner.rs rename to lykiadb-server/src/lang/tokenizer/scanner.rs diff --git a/server/src/lang/tokenizer/token.rs b/lykiadb-server/src/lang/tokenizer/token.rs similarity index 100% rename from server/src/lang/tokenizer/token.rs rename to lykiadb-server/src/lang/tokenizer/token.rs diff --git a/server/src/lib.rs b/lykiadb-server/src/lib.rs similarity index 100% rename from server/src/lib.rs rename to lykiadb-server/src/lib.rs diff --git a/server/src/main.rs b/lykiadb-server/src/main.rs similarity index 100% rename from server/src/main.rs rename to lykiadb-server/src/main.rs diff --git a/lykiadb-server/src/net/mod.rs b/lykiadb-server/src/net/mod.rs new file mode 100644 index 0000000..194e263 --- /dev/null +++ b/lykiadb-server/src/net/mod.rs @@ -0,0 +1,47 @@ +pub mod tcp; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, +}; + +use crate::runtime::{error::ExecutionError, types::RV}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Request { + Run(String), + Ast(String), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Response { + Value(RV), + Program(Value), + Error(ExecutionError), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Message { + Request(Request), + Response(Response), +} + +#[derive(Debug)] +pub enum CommunicationError { + BsonError(bson::ser::Error), + IoError(std::io::Error), + GenericError(String), +} + +impl From<std::io::Error> for CommunicationError { + fn from(value: std::io::Error) -> Self { + CommunicationError::IoError(value) + } +} + +impl From<bson::ser::Error> for CommunicationError { + fn from(value: bson::ser::Error) -> Self { + CommunicationError::BsonError(value) + } +} diff --git a/server/src/net/mod.rs b/lykiadb-server/src/net/tcp.rs similarity index 52% rename from server/src/net/mod.rs rename to lykiadb-server/src/net/tcp.rs index 75d5079..73c2b58 100644 --- a/server/src/net/mod.rs +++ b/lykiadb-server/src/net/tcp.rs @@ -1,59 +1,16 @@ use bytes::BytesMut; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use tokio::{ - io::{copy, AsyncReadExt, AsyncWriteExt, BufWriter}, - net::TcpStream, -}; +use tokio::io::{BufWriter, AsyncReadExt, AsyncWriteExt, copy}; +use tokio::net::TcpStream; +use crate::net::{CommunicationError, Message}; -use crate::runtime::{error::ExecutionError, types::RV}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum Request { - Run(String), - Ast(String), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum Response { - Value(RV), - Program(Value), - Error(ExecutionError), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum Message { - Request(Request), - Response(Response), -} - -#[derive(Debug)] -pub enum CommunicationError { - BsonError(bson::ser::Error), - IoError(std::io::Error), - GenericError(String), -} - -impl From<std::io::Error> for CommunicationError { - fn from(value: std::io::Error) -> Self { - CommunicationError::IoError(value) - } -} - -impl From<bson::ser::Error> for CommunicationError { - fn from(value: bson::ser::Error) -> Self { - CommunicationError::BsonError(value) - } -} - -pub struct Connection { +pub struct TcpConnection { pub stream: BufWriter<TcpStream>, pub read_buffer: BytesMut, } -impl Connection { - pub fn new(stream: TcpStream) -> Connection { - Connection { +impl TcpConnection { + pub fn new(stream: TcpStream) -> TcpConnection { + TcpConnection { stream: BufWriter::new(stream), read_buffer: BytesMut::with_capacity(4096), } diff --git a/server/src/runtime/environment.rs b/lykiadb-server/src/runtime/environment.rs similarity index 100% rename from server/src/runtime/environment.rs rename to lykiadb-server/src/runtime/environment.rs diff --git a/server/src/runtime/error.rs b/lykiadb-server/src/runtime/error.rs similarity index 100% rename from server/src/runtime/error.rs rename to lykiadb-server/src/runtime/error.rs diff --git a/server/src/runtime/interpreter.rs b/lykiadb-server/src/runtime/interpreter.rs similarity index 100% rename from server/src/runtime/interpreter.rs rename to lykiadb-server/src/runtime/interpreter.rs diff --git a/server/src/runtime/mod.rs b/lykiadb-server/src/runtime/mod.rs similarity index 94% rename from server/src/runtime/mod.rs rename to lykiadb-server/src/runtime/mod.rs index 8e4cb8e..b4bea59 100644 --- a/server/src/runtime/mod.rs +++ b/lykiadb-server/src/runtime/mod.rs @@ -11,7 +11,8 @@ use self::std::stdlib; use crate::lang::parser::Parser; use crate::lang::tokenizer::scanner::Scanner; -use crate::net::{CommunicationError, Connection, Message, Request, Response}; +use crate::net::{CommunicationError, Message, Request, Response}; +use crate::net::tcp::TcpConnection; use crate::runtime::interpreter::Interpreter; use crate::runtime::types::RV; use crate::util::{alloc_shared, Shared}; @@ -23,14 +24,14 @@ mod std; pub mod types; pub struct ServerSession { - conn: Connection, + conn: TcpConnection, runtime: Runtime, } impl ServerSession { pub fn new(stream: TcpStream) -> Self { ServerSession { - conn: Connection::new(stream), + conn: TcpConnection::new(stream), runtime: Runtime::new(RuntimeMode::File, None), } } diff --git a/server/src/runtime/std/fib.rs b/lykiadb-server/src/runtime/std/fib.rs similarity index 100% rename from server/src/runtime/std/fib.rs rename to lykiadb-server/src/runtime/std/fib.rs diff --git a/server/src/runtime/std/json.rs b/lykiadb-server/src/runtime/std/json.rs similarity index 100% rename from server/src/runtime/std/json.rs rename to lykiadb-server/src/runtime/std/json.rs diff --git a/server/src/runtime/std/mod.rs b/lykiadb-server/src/runtime/std/mod.rs similarity index 100% rename from server/src/runtime/std/mod.rs rename to lykiadb-server/src/runtime/std/mod.rs diff --git a/server/src/runtime/std/out.rs b/lykiadb-server/src/runtime/std/out.rs similarity index 100% rename from server/src/runtime/std/out.rs rename to lykiadb-server/src/runtime/std/out.rs diff --git a/server/src/runtime/std/time.rs b/lykiadb-server/src/runtime/std/time.rs similarity index 100% rename from server/src/runtime/std/time.rs rename to lykiadb-server/src/runtime/std/time.rs diff --git a/server/src/runtime/types.rs b/lykiadb-server/src/runtime/types.rs similarity index 100% rename from server/src/runtime/types.rs rename to lykiadb-server/src/runtime/types.rs diff --git a/server/src/util/mod.rs b/lykiadb-server/src/util/mod.rs similarity index 100% rename from server/src/util/mod.rs rename to lykiadb-server/src/util/mod.rs diff --git a/server/tests/lang/generic/array_literal.rs b/lykiadb-server/tests/lang/generic/array_literal.rs similarity index 100% rename from server/tests/lang/generic/array_literal.rs rename to lykiadb-server/tests/lang/generic/array_literal.rs diff --git a/server/tests/lang/generic/binary.rs b/lykiadb-server/tests/lang/generic/binary.rs similarity index 100% rename from server/tests/lang/generic/binary.rs rename to lykiadb-server/tests/lang/generic/binary.rs diff --git a/server/tests/lang/generic/function_call.rs b/lykiadb-server/tests/lang/generic/function_call.rs similarity index 100% rename from server/tests/lang/generic/function_call.rs rename to lykiadb-server/tests/lang/generic/function_call.rs diff --git a/server/tests/lang/generic/grouping.rs b/lykiadb-server/tests/lang/generic/grouping.rs similarity index 100% rename from server/tests/lang/generic/grouping.rs rename to lykiadb-server/tests/lang/generic/grouping.rs diff --git a/server/tests/lang/generic/loops.rs b/lykiadb-server/tests/lang/generic/loops.rs similarity index 100% rename from server/tests/lang/generic/loops.rs rename to lykiadb-server/tests/lang/generic/loops.rs diff --git a/server/tests/lang/generic/mod.rs b/lykiadb-server/tests/lang/generic/mod.rs similarity index 100% rename from server/tests/lang/generic/mod.rs rename to lykiadb-server/tests/lang/generic/mod.rs diff --git a/server/tests/lang/generic/number_literal.rs b/lykiadb-server/tests/lang/generic/number_literal.rs similarity index 100% rename from server/tests/lang/generic/number_literal.rs rename to lykiadb-server/tests/lang/generic/number_literal.rs diff --git a/server/tests/lang/generic/object_literal.rs b/lykiadb-server/tests/lang/generic/object_literal.rs similarity index 100% rename from server/tests/lang/generic/object_literal.rs rename to lykiadb-server/tests/lang/generic/object_literal.rs diff --git a/server/tests/lang/generic/other_literals.rs b/lykiadb-server/tests/lang/generic/other_literals.rs similarity index 100% rename from server/tests/lang/generic/other_literals.rs rename to lykiadb-server/tests/lang/generic/other_literals.rs diff --git a/server/tests/lang/generic/unary.rs b/lykiadb-server/tests/lang/generic/unary.rs similarity index 100% rename from server/tests/lang/generic/unary.rs rename to lykiadb-server/tests/lang/generic/unary.rs diff --git a/server/tests/lang/generic/variable.rs b/lykiadb-server/tests/lang/generic/variable.rs similarity index 100% rename from server/tests/lang/generic/variable.rs rename to lykiadb-server/tests/lang/generic/variable.rs diff --git a/server/tests/lang/mod.rs b/lykiadb-server/tests/lang/mod.rs similarity index 100% rename from server/tests/lang/mod.rs rename to lykiadb-server/tests/lang/mod.rs diff --git a/server/tests/lang/sql/insert_values.rs b/lykiadb-server/tests/lang/sql/insert_values.rs similarity index 100% rename from server/tests/lang/sql/insert_values.rs rename to lykiadb-server/tests/lang/sql/insert_values.rs diff --git a/server/tests/lang/sql/mod.rs b/lykiadb-server/tests/lang/sql/mod.rs similarity index 100% rename from server/tests/lang/sql/mod.rs rename to lykiadb-server/tests/lang/sql/mod.rs diff --git a/server/tests/lang/sql/select_compound.rs b/lykiadb-server/tests/lang/sql/select_compound.rs similarity index 100% rename from server/tests/lang/sql/select_compound.rs rename to lykiadb-server/tests/lang/sql/select_compound.rs diff --git a/server/tests/lang/sql/select_distinct.rs b/lykiadb-server/tests/lang/sql/select_distinct.rs similarity index 100% rename from server/tests/lang/sql/select_distinct.rs rename to lykiadb-server/tests/lang/sql/select_distinct.rs diff --git a/server/tests/lang/sql/select_from.rs b/lykiadb-server/tests/lang/sql/select_from.rs similarity index 100% rename from server/tests/lang/sql/select_from.rs rename to lykiadb-server/tests/lang/sql/select_from.rs diff --git a/server/tests/lang/sql/select_group_by.rs b/lykiadb-server/tests/lang/sql/select_group_by.rs similarity index 100% rename from server/tests/lang/sql/select_group_by.rs rename to lykiadb-server/tests/lang/sql/select_group_by.rs diff --git a/server/tests/lang/sql/select_join.rs b/lykiadb-server/tests/lang/sql/select_join.rs similarity index 100% rename from server/tests/lang/sql/select_join.rs rename to lykiadb-server/tests/lang/sql/select_join.rs diff --git a/server/tests/lang/sql/select_limit.rs b/lykiadb-server/tests/lang/sql/select_limit.rs similarity index 100% rename from server/tests/lang/sql/select_limit.rs rename to lykiadb-server/tests/lang/sql/select_limit.rs diff --git a/server/tests/lang/sql/select_order.rs b/lykiadb-server/tests/lang/sql/select_order.rs similarity index 100% rename from server/tests/lang/sql/select_order.rs rename to lykiadb-server/tests/lang/sql/select_order.rs diff --git a/server/tests/lang/sql/select_projection.rs b/lykiadb-server/tests/lang/sql/select_projection.rs similarity index 100% rename from server/tests/lang/sql/select_projection.rs rename to lykiadb-server/tests/lang/sql/select_projection.rs diff --git a/server/tests/lang/sql/select_where.rs b/lykiadb-server/tests/lang/sql/select_where.rs similarity index 100% rename from server/tests/lang/sql/select_where.rs rename to lykiadb-server/tests/lang/sql/select_where.rs diff --git a/server/tests/lang/sql/sql_expr.rs b/lykiadb-server/tests/lang/sql/sql_expr.rs similarity index 100% rename from server/tests/lang/sql/sql_expr.rs rename to lykiadb-server/tests/lang/sql/sql_expr.rs diff --git a/server/tests/runtime/blocks.rs b/lykiadb-server/tests/runtime/blocks.rs similarity index 100% rename from server/tests/runtime/blocks.rs rename to lykiadb-server/tests/runtime/blocks.rs diff --git a/server/tests/runtime/functions.rs b/lykiadb-server/tests/runtime/functions.rs similarity index 100% rename from server/tests/runtime/functions.rs rename to lykiadb-server/tests/runtime/functions.rs diff --git a/server/tests/runtime/ifs.rs b/lykiadb-server/tests/runtime/ifs.rs similarity index 100% rename from server/tests/runtime/ifs.rs rename to lykiadb-server/tests/runtime/ifs.rs diff --git a/server/tests/runtime/loops.rs b/lykiadb-server/tests/runtime/loops.rs similarity index 100% rename from server/tests/runtime/loops.rs rename to lykiadb-server/tests/runtime/loops.rs diff --git a/server/tests/runtime/mod.rs b/lykiadb-server/tests/runtime/mod.rs similarity index 100% rename from server/tests/runtime/mod.rs rename to lykiadb-server/tests/runtime/mod.rs diff --git a/server/tests/tests.rs b/lykiadb-server/tests/tests.rs similarity index 100% rename from server/tests/tests.rs rename to lykiadb-server/tests/tests.rs diff --git a/cli/Cargo.toml b/lykiadb-shell/Cargo.toml similarity index 83% rename from cli/Cargo.toml rename to lykiadb-shell/Cargo.toml index 9cd1c2c..dde8576 100644 --- a/cli/Cargo.toml +++ b/lykiadb-shell/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" [dependencies] clap = { version = "4.4.6", features = ["derive"] } -lykiadb-server = { path = "../server" } +lykiadb-connect = { path = "../lykiadb-connect" } serde_json = "1.0.105" tokio = { version = "~1.35.1" } diff --git a/cli/examples/compute.lyql b/lykiadb-shell/examples/compute.lyql similarity index 100% rename from cli/examples/compute.lyql rename to lykiadb-shell/examples/compute.lyql diff --git a/cli/examples/fib.lyql b/lykiadb-shell/examples/fib.lyql similarity index 100% rename from cli/examples/fib.lyql rename to lykiadb-shell/examples/fib.lyql diff --git a/cli/examples/fn.lyql b/lykiadb-shell/examples/fn.lyql similarity index 100% rename from cli/examples/fn.lyql rename to lykiadb-shell/examples/fn.lyql diff --git a/cli/examples/hof.lyql b/lykiadb-shell/examples/hof.lyql similarity index 100% rename from cli/examples/hof.lyql rename to lykiadb-shell/examples/hof.lyql diff --git a/cli/examples/objects.lyql b/lykiadb-shell/examples/objects.lyql similarity index 100% rename from cli/examples/objects.lyql rename to lykiadb-shell/examples/objects.lyql diff --git a/cli/examples/scan_err.lyql b/lykiadb-shell/examples/scan_err.lyql similarity index 100% rename from cli/examples/scan_err.lyql rename to lykiadb-shell/examples/scan_err.lyql diff --git a/cli/examples/sql.lyql b/lykiadb-shell/examples/sql.lyql similarity index 100% rename from cli/examples/sql.lyql rename to lykiadb-shell/examples/sql.lyql diff --git a/lykiadb-shell/src/main.rs b/lykiadb-shell/src/main.rs new file mode 100644 index 0000000..7bef694 --- /dev/null +++ b/lykiadb-shell/src/main.rs @@ -0,0 +1,81 @@ +use std::{ + fs::File, + io::{stdin, stdout, BufReader, Read, Write}, +}; + +use clap::Parser; +use lykiadb_connect::{get_session, Message, Protocol, report_error, Request, Response}; +use lykiadb_connect::session::ClientSession; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Path to the script to be executed + filename: Option<String>, + + #[clap(short, long, default_value = "false")] + print_ast: bool, +} + +struct Shell; + +impl Shell { + async fn run_repl(&mut self, session: &mut impl ClientSession) { + println!("REPL mode"); + let mut line = String::new(); + + loop { + print!("lykia > "); + let _ = stdout().flush(); + stdin().read_line(&mut line).expect("Invalid input"); + if line.is_empty() || line.trim() == ".exit" { + break; + } + + let response = session.send_receive(Message::Request(Request::Run(line.to_string()))).await.unwrap(); + self.handle_response("prompt", &line, response); + line.clear(); + } + } + + async fn run_file(&mut self, session: &mut impl ClientSession, filename: &str, print_ast: bool) { + let file = File::open(filename).expect("File couldn't be opened."); + + let mut content: String = String::new(); + + BufReader::new(file) + .read_to_string(&mut content) + .expect("File couldn't be read."); + + let msg = if print_ast { + Message::Request(Request::Ast(content.to_string())) + } else { + Message::Request(Request::Run(content.to_string())) + }; + + let response = session.send_receive(msg).await.unwrap(); + self.handle_response(filename, &content, response); + } + + fn handle_response(&mut self, filename: &str, content: &str, response: Message) { + match response { + Message::Response(Response::Value(result)) => println!("{:?}", result), + Message::Response(Response::Program(value)) => { + println!("{}", serde_json::to_string_pretty(&value).unwrap()) + } + Message::Response(Response::Error(err)) => report_error(filename, &content, err.clone()), + _ => panic!(""), + } + } +} + +#[tokio::main] +async fn main() { + let args = Args::parse(); + let mut session = get_session("localhost:19191", Protocol::Tcp).await; + let mut shell = Shell; + match args.filename { + Some(filename) => shell.run_file(&mut session, &filename, args.print_ast).await, + None => shell.run_repl(&mut session).await, + }; +}