diff options
author | kotontrion <[email protected]> | 2024-10-29 13:50:41 +0100 |
---|---|---|
committer | kotontrion <[email protected]> | 2024-10-29 13:50:41 +0100 |
commit | 57f20666e716fde56579b8aa638eed1264f793de (patch) | |
tree | 59b2ebbd770c80049cea4df82109d28f617675fe | |
parent | 4d9ae88b0bab75779876d465f986791d052414ca (diff) | |
parent | 7e484188e7492ac7945c854bcc3f26cec1863c91 (diff) |
Merge branch 'main' into feat/cava
174 files changed, 8272 insertions, 3034 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 11aaf39..46f45a4 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: [aylur, kotontrion] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: aylur diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6c097e..e09c3dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,7 @@ # Contributing You can contribute by: + - [Suggesting new features](https://github.com/Aylur/astal/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.md&title=) - [Reporting bugs](https://github.com/Aylur/astal/issues/new?assignees=&labels=bug&projects=&template=bug_report.md&title=) - Improving docs with additional contexts and examples @@ -18,9 +19,11 @@ Write libraries preferably in Vala. Only choose C if some dependency is only ava ## Todo Planned features, you could help with: + - [niri ipc library](https://github.com/Aylur/astal/issues/8) - sway ipc library - greetd ipc library -- core: http request library, abstraction over libsoup included (mostly to be used in gjs and lua) -- core: notification sending, libnotify clone [#26](https://github.com/Aylur/astal/issues/26) +- http request library abstraction over libsoup (mostly to be used in gjs and lua) +- notification sending libnotify clone [#26](https://github.com/Aylur/astal/issues/26) - setting up [uncrustify](https://github.com/uncrustify/uncrustify) for Vala +- bluetooth custom errordomains, currently every error is simply Error diff --git a/core/gjs/index.ts b/core/gjs/index.ts deleted file mode 100644 index 901b264..0000000 --- a/core/gjs/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Gtk } from "./src/imports.js" - -export * from "./src/imports.js" -export * from "./src/process.js" -export * from "./src/time.js" -export * from "./src/file.js" -export { bind, default as Binding } from "./src/binding.js" -export { Variable } from "./src/variable.js" -export * as Widget from "./src/widgets.js" -export { default as App } from "./src/application.js" - -// gjs crashes if a widget is constructed before Gtk.init -Gtk.init(null) diff --git a/core/gjs/src/imports.ts b/core/gjs/src/imports.ts deleted file mode 100644 index cbed004..0000000 --- a/core/gjs/src/imports.ts +++ /dev/null @@ -1,10 +0,0 @@ -// this file's purpose is to have glib versions in one place -// this is only really needed for Gtk/Astal because -// ts-gir might generate gtk4 versions too - -export { default as Astal } from "gi://Astal?version=0.1" -export { default as GObject } from "gi://GObject?version=2.0" -export { default as Gio } from "gi://Gio?version=2.0" -export { default as Gtk } from "gi://Gtk?version=3.0" -export { default as Gdk } from "gi://Gdk?version=3.0" -export { default as GLib } from "gi://GLib?version=2.0" diff --git a/core/gjs/tsconfig.json b/core/gjs/tsconfig.json deleted file mode 100644 index b535a07..0000000 --- a/core/gjs/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "experimentalDecorators": true, - "target": "ESNext", - "module": "ESNext", - "lib": [ - "ESNext" - ], - "outDir": "dist", - "declaration": true, - "strict": true, - "moduleResolution": "Bundler", - "skipLibCheck": true, - "checkJs": true, - "allowJs": true, - "jsx": "react-jsx", - "jsxImportSource": "src/jsx", - "baseUrl": ".", - }, - "include": [ - "@girs", - "src/**/*", - "index.ts" - ] -} diff --git a/core/meson_options.txt b/core/meson_options.txt deleted file mode 100644 index a60ff42..0000000 --- a/core/meson_options.txt +++ /dev/null @@ -1,17 +0,0 @@ -option( - 'lib', - type: 'boolean', - value: true, -) - -option( - 'cli', - type: 'boolean', - value: true, -) - -option( - 'gjs', - type: 'boolean', - value: true, -) diff --git a/core/src/astal.vala b/core/src/astal.vala deleted file mode 100644 index 134293b..0000000 --- a/core/src/astal.vala +++ /dev/null @@ -1,375 +0,0 @@ -namespace Astal { -[DBus (name="io.Astal.Application")] -public class Application : Gtk.Application { - private List<Gtk.CssProvider> css_providers = new List<Gtk.CssProvider>(); - private SocketService service; - private DBusConnection conn; - private string _instance_name; - - public string socket_path { get; private set; } - - [DBus (visible=false)] - public signal void monitor_added(Gdk.Monitor monitor); - - [DBus (visible=false)] - public signal void monitor_removed(Gdk.Monitor monitor); - - [DBus (visible=false)] - public List<weak Gdk.Monitor> monitors { - owned get { - var display = Gdk.Display.get_default(); - var list = new List<weak Gdk.Monitor>(); - for (var i = 0; i <= display.get_n_monitors(); ++i) { - var mon = display.get_monitor(i); - if (mon != null) { - list.append(mon); - } - } - return list; - } - } - - [DBus (visible=false)] - public string instance_name { - get { return _instance_name; } - set { - application_id = "io.Astal." + value; - _instance_name = value; - } - } - - [DBus (visible=false)] - public List<Gtk.Window> windows { - get { return get_windows(); } - } - - [DBus (visible=false)] - public Gtk.Settings settings { - get { return Gtk.Settings.get_default(); } - } - - [DBus (visible=false)] - public Gdk.Screen screen { - get { return Gdk.Screen.get_default(); } - } - - [DBus (visible=false)] - public string gtk_theme { - owned get { return settings.gtk_theme_name; } - set { settings.gtk_theme_name = value; } - } - - [DBus (visible=false)] - public string icon_theme { - owned get { return settings.gtk_icon_theme_name; } - set { settings.gtk_icon_theme_name = value; } - } - - [DBus (visible=false)] - public string cursor_theme { - owned get { return settings.gtk_cursor_theme_name; } - set { settings.gtk_cursor_theme_name = value; } - } - - [DBus (visible=false)] - public void reset_css() { - foreach(var provider in css_providers) { - Gtk.StyleContext.remove_provider_for_screen(screen, provider); - } - css_providers = new List<Gtk.CssProvider>(); - } - - public void inspector() throws DBusError, IOError { - Gtk.Window.set_interactive_debugging(true); - } - - [DBus (visible=false)] - public Gtk.Window? get_window(string name) { - foreach(var win in windows) { - if (win.name == name) - return win; - } - - critical("no window with name \"%s\"".printf(name)); - return null; - } - - public void toggle_window(string window) throws DBusError, IOError { - var win = get_window(window); - if (win != null) { - win.visible = !win.visible; - } else { - throw new IOError.FAILED("window not found"); - } - } - - [DBus (visible=false)] - public void apply_css(string style, bool reset = false) { - var provider = new Gtk.CssProvider(); - - if (reset) - reset_css(); - - try { - if (FileUtils.test(style, FileTest.EXISTS)) - provider.load_from_path(style); - else - provider.load_from_data(style); - } catch (Error err) { - critical(err.message); - } - - Gtk.StyleContext.add_provider_for_screen( - screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_USER); - - css_providers.append(provider); - } - - [DBus (visible=false)] - public void add_icons(string? path) { - if (path != null) - Gtk.IconTheme.get_default().prepend_search_path(path); - } - - private async void _socket_request(SocketConnection conn) { - string message = yield read_sock(conn); - request(message != null ? message.strip() : "", conn); - } - - [DBus (visible=false)] - public virtual void request(string msg, SocketConnection conn) { - write_sock.begin(conn, @"missing response implementation on $application_id"); - } - - /** - * should be called before `run()` - * the return value indicates if instance is already running - */ - [DBus (visible=false)] - public bool acquire_socket() { - foreach (var instance in get_instances()) { - if (instance == instance_name) { - return false; - } - } - - var rundir = GLib.Environment.get_user_runtime_dir(); - socket_path = @"$rundir/$instance_name.sock"; - - if (FileUtils.test(socket_path, GLib.FileTest.EXISTS)) { - try { - File.new_for_path(socket_path).delete(null); - } catch (Error err) { - critical(err.message); - } - } - - try { - service = new SocketService(); - service.add_address( - new UnixSocketAddress(socket_path), - SocketType.STREAM, - SocketProtocol.DEFAULT, - null, - null); - - service.incoming.connect((conn) => { - _socket_request.begin(conn, (_, res) => _socket_request.end(res)); - return false; - }); - - Bus.own_name( - BusType.SESSION, - "io.Astal." + instance_name, - BusNameOwnerFlags.NONE, - (conn) => { - try { - this.conn = conn; - conn.register_object("/io/Astal/Application", this); - } catch (Error err) { - critical(err.message); - } - }, - () => {}, - () => {}); - - info("socket acquired: %s\n", socket_path); - return true; - } catch (Error err) { - critical("could not acquire socket %s\n", application_id); - critical(err.message); - return false; - } - } - - public string message(string? msg) throws DBusError, IOError { - var rundir = GLib.Environment.get_user_runtime_dir(); - var socket_path = @"$rundir/$instance_name.sock"; - var client = new SocketClient(); - - if (msg == null) - msg = ""; - - try { - var conn = client.connect(new UnixSocketAddress(socket_path), null); - conn.output_stream.write(msg.concat("\x04").data); - - var stream = new DataInputStream(conn.input_stream); - return stream.read_upto("\x04", -1, null, null); - } catch (Error err) { - printerr(err.message); - return ""; - } - } - - public new void quit() throws DBusError, IOError { - if (service != null) { - if (FileUtils.test(socket_path, GLib.FileTest.EXISTS)){ - try { - File.new_for_path(socket_path).delete(null); - } catch (Error err) { - warning(err.message); - } - } - } - - base.quit(); - } - - construct { - if (instance_name == null) - instance_name = "astal"; - - activate.connect(() => { - var display = Gdk.Display.get_default(); - display.monitor_added.connect((mon) => { - monitor_added(mon); - notify_property("monitors"); - }); - display.monitor_removed.connect((mon) => { - monitor_removed(mon); - notify_property("monitors"); - }); - }); - - shutdown.connect(() => { try { quit(); } catch(Error err) {} }); - Unix.signal_add(1, () => { try { quit(); } catch(Error err) {} }, Priority.HIGH); - Unix.signal_add(2, () => { try { quit(); } catch(Error err) {} }, Priority.HIGH); - Unix.signal_add(15, () => { try { quit(); } catch(Error err) {} }, Priority.HIGH); - } - - public static List<string> get_instances() { - var list = new List<string>(); - var prefix = "io.Astal."; - - try { - DBusImpl dbus = Bus.get_proxy_sync( - BusType.SESSION, - "org.freedesktop.DBus", - "/org/freedesktop/DBus" - ); - - foreach (var busname in dbus.list_names()) { - if (busname.has_prefix(prefix)) - list.append(busname.replace(prefix, "")); - } - } catch (Error err) { - critical(err.message); - } - - return list; - } - - public static void quit_instance(string instance) { - try { - IApplication proxy = Bus.get_proxy_sync( - BusType.SESSION, - "io.Astal." + instance, - "/io/Astal/Application" - ); - - proxy.quit(); - } catch (Error err) { - critical(err.message); - } - } - - public static void open_inspector(string instance) { - try { - IApplication proxy = Bus.get_proxy_sync( - BusType.SESSION, - "io.Astal." + instance, - "/io/Astal/Application" - ); - - proxy.inspector(); - } catch (Error err) { - critical(err.message); - } - } - - public static void toggle_window_by_name(string instance, string window) { - try { - IApplication proxy = Bus.get_proxy_sync( - BusType.SESSION, - "io.Astal." + instance, - "/io/Astal/Application" - ); - - proxy.toggle_window(window); - } catch (Error err) { - critical(err.message); - } - } - - public static string send_message(string instance_name, string msg) { - var rundir = GLib.Environment.get_user_runtime_dir(); - var socket_path = @"$rundir/$instance_name.sock"; - var client = new SocketClient(); - - try { - var conn = client.connect(new UnixSocketAddress(socket_path), null); - conn.output_stream.write(msg.concat("\x04").data); - - var stream = new DataInputStream(conn.input_stream); - return stream.read_upto("\x04", -1, null, null); - } catch (Error err) { - printerr(err.message); - return ""; - } - } -} - -[DBus (name="org.freedesktop.DBus")] -private interface DBusImpl : DBusProxy { - public abstract string[] list_names() throws GLib.Error; -} - -[DBus (name="io.Astal.Application")] -private interface IApplication : DBusProxy { - public abstract void quit() throws GLib.Error; - public abstract void inspector() throws GLib.Error; - public abstract void toggle_window(string window) throws GLib.Error; - public abstract string message(string window) throws GLib.Error; -} - -public async string read_sock(SocketConnection conn) { - try { - var stream = new DataInputStream(conn.input_stream); - return yield stream.read_upto_async("\x04", -1, Priority.DEFAULT, null, null); - } catch (Error err) { - critical(err.message); - return err.message; - } -} - -public async void write_sock(SocketConnection conn, string response) { - try { - yield conn.output_stream.write_async( - response.concat("\x04").data, - Priority.DEFAULT); - } catch (Error err) { - critical(err.message); - } -} -} diff --git a/docs/default.nix b/docs/default.nix index 3a75834..0d79ce1 100644 --- a/docs/default.nix +++ b/docs/default.nix @@ -7,47 +7,45 @@ toTOML = (pkgs.formats.toml {}).generate; - genRefForPkg = { - name, - pkg, - outPath, - metaData, - }: let - data = toTOML name metaData; - output = self.packages.${pkgs.system}.${pkg}.dev; - in '' - mkdir -p $out/${outPath} - cat ${urlmap} > urlmap.js - gi-docgen generate -C ${data} ${output}/share/gir-1.0/${name}-0.1.gir - cp -r ${name}-0.1/* $out/${outPath} - ''; + docgen = pkgs.gi-docgen.overrideAttrs { + patches = [../nix/doc/gi-docgen.patch]; + }; - genLib = name: namespace: { - description, + genLib = { + flakepkg, + gir, version, + description, + api-ver ? "0.1", authors ? "Aylur", dependencies ? {}, - out ? "libastal/${name}", - }: - genRefForPkg { - name = "Astal${namespace}"; - pkg = name; - outPath = out; - metaData = { - library = { - inherit description authors; - version = readVer version; - license = "LGPL-2.1"; - browse_url = "https://github.com/aylur/astal"; - repository_url = "https://github.com/aylur/aylur.git"; - website_url = "https://aylur.github.io/astal"; - dependencies = ["GObject-2.0"] ++ (builtins.attrNames dependencies); - }; + out ? "libastal/${flakepkg}", + browse ? flakepkg, + website ? flakepkg, + }: let + name = "Astal${gir}-${api-ver}"; + src = self.packages.${pkgs.system}.${flakepkg}.dev; - extra.urlmap_file = "urlmap.js"; - dependencies = {inherit (dependency) "GObject-2.0";} // dependencies; + data = toTOML gir { + library = { + inherit description authors; + version = readVer version; + license = "LGPL-2.1"; + browse_url = "https://github.com/Aylur/astal/tree/main/lib/${browse}"; + repository_url = "https://github.com/aylur/aylur.git"; + website_url = "https://aylur.github.io/astal/guide/libraries/${website}"; + dependencies = ["GObject-2.0"] ++ (builtins.attrNames dependencies); }; + + extra.urlmap_file = "urlmap.js"; + dependencies = {inherit (dependency) "GObject-2.0";} // dependencies; }; + in '' + mkdir -p $out/${out} + cat ${urlmap} > urlmap.js + gi-docgen generate -C ${data} ${src}/share/gir-1.0/${name}.gir + cp -r ${name}/* $out/${out} + ''; dependency = { "GObject-2.0" = { @@ -60,6 +58,11 @@ description = "The GTK toolkit"; docs_url = "https://docs.gtk.org/gtk3/"; }; + "AstalIO-0.1" = { + name = "AstalIO"; + description = "Astal Core library"; + docs_url = "https://aylur.github.io/libastal/io"; + }; "NM-1.0" = { name = "NetworkManager"; description = "The standard Linux network configuration tool suite"; @@ -80,6 +83,7 @@ ["Gdk" "https://docs.gtk.org/gdk3/"] ["Gtk" "https://docs.gtk.org/gtk3/"] ["GdkPixbuf" "https://docs.gtk.org/gdk-pixbuf/"] + ["AstalIO" "https://aylur.github.io/libastal/io"] # FIXME: these are not gi-docgen generated, therefore links are broken ["NM" "https://networkmanager.dev/docs/libnm/latest/"] @@ -88,11 +92,11 @@ ''; in pkgs.stdenvNoCC.mkDerivation { - name = "library-reference"; + name = "reference"; src = ./.; nativeBuildInputs = with pkgs; [ - gi-docgen + docgen glib json-glib gobject-introspection @@ -102,65 +106,101 @@ in libdbusmenu-gtk3 wireplumber networkmanager + self.packages.${system}.io ]; installPhase = '' runHook preInstall - ${genLib "astal" "" { - out = "libastal"; - description = "Astal core library"; - version = ../core/version; - dependencies = {inherit (dependency) "Gtk-3.0";}; + ${genLib { + flakepkg = "io"; + gir = "IO"; + api-ver = "0.1"; + browse = "astal/io"; + description = "Astal Core library"; + version = ../lib/astal/io/version; + }} + ${genLib { + flakepkg = "astal3"; + gir = ""; + api-ver = "3.0"; + browse = "astal/gtk3"; + description = "Astal GTK3 widget library"; + version = ../lib/astal/gtk3/version; + dependencies = {inherit (dependency) "AstalIO-0.1" "Gtk-3.0";}; }} - ${genLib "apps" "Apps" { + ${genLib { + flakepkg = "apps"; + gir = "Apps"; description = "Application query library"; version = ../lib/apps/version; }} - ${genLib "auth" "Auth" { + ${genLib { + flakepkg = "auth"; + gir = "Auth"; authors = "kotontrion"; description = "Authentication using pam"; version = ../lib/auth/version; }} - ${genLib "battery" "Battery" { + ${genLib { + flakepkg = "battery"; + gir = "Battery"; description = "DBus proxy for upowerd devices"; version = ../lib/battery/version; }} - ${genLib "bluetooth" "Bluetooth" { + ${genLib { + flakepkg = "bluetooth"; + gir = "Bluetooth"; description = "DBus proxy for bluez"; version = ../lib/bluetooth/version; }} - ${genLib "hyprland" "Hyprland" { + ${genLib { + flakepkg = "hyprland"; + gir = "Hyprland"; description = "IPC client for Hyprland"; version = ../lib/hyprland/version; }} - ${genLib "mpris" "Mpris" { + ${genLib { + flakepkg = "mpris"; + gir = "Mpris"; description = "Control mpris players"; version = ../lib/mpris/version; }} - ${genLib "network" "Network" { + ${genLib { + flakepkg = "network"; + gir = "Network"; description = "NetworkManager wrapper library"; version = ../lib/network/version; dependencies = {inherit (dependency) "NM-1.0";}; # FIXME: why does this not work? }} - ${genLib "notifd" "Notifd" { + ${genLib { + flakepkg = "notifd"; + gir = "Notifd"; description = "Notification daemon library"; version = ../lib/notifd/version; }} - ${genLib "powerprofiles" "PowerProfiles" { + ${genLib { + flakepkg = "powerprofiles"; + gir = "PowerProfiles"; description = "DBus proxy for upowerd profiles"; version = ../lib/powerprofiles/version; }} - ${genLib "river" "River" { + ${genLib { + flakepkg = "river"; + gir = "River"; description = "IPC client for River"; version = ../lib/river/version; authors = "kotontrion"; }} - ${genLib "tray" "Tray" { + ${genLib { + flakepkg = "tray"; + gir = "Tray"; description = "StatusNotifierItem implementation"; version = ../lib/tray/version; authors = "kotontrion"; }} - ${genLib "wireplumber" "Wp" { + ${genLib { + flakepkg = "wireplumber"; + gir = "Wp"; description = "Wrapper library over the wireplumber API"; version = ../lib/wireplumber/version; authors = "kotontrion"; diff --git a/docs/eslint.config.js b/docs/eslint.config.js new file mode 100644 index 0000000..847a9dc --- /dev/null +++ b/docs/eslint.config.js @@ -0,0 +1,30 @@ +import eslint from "@eslint/js" +import tseslint from "typescript-eslint" +import stylistic from "@stylistic/eslint-plugin" +import pluginVue from "eslint-plugin-vue" + +export default tseslint.config({ + ignores: [".vitepress/cache/*"], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommended, + ...pluginVue.configs["flat/recommended"], + stylistic.configs.customize({ + semi: false, + indent: 4, + quotes: "double", + }), + ], + rules: { + "vue/multi-word-component-names": ["off"], + "vue/html-indent": ["error", 4], + "vue/max-attributes-per-line": ["error", { + singleline: { + max: 2, + }, + multiline: { + max: 1, + }, + }], + }, +}) diff --git a/docs/guide/ags/installation.md b/docs/guide/ags/installation.md deleted file mode 100644 index 0adcf68..0000000 --- a/docs/guide/ags/installation.md +++ /dev/null @@ -1,65 +0,0 @@ -# Installation - -## Nix - -maintainer: [@Aylur](https://github.com/Aylur) - -Read more about it on the [nix page](../getting-started/nix#ags) - -You can try without installing. - -<!--TODO: remove v2 after merge--> -```sh -nix run github:aylur/ags/v2 -- --help -``` - -## Bulding AGS from source - -1. [Install Astal](../getting-started/installation.md) if you have not already - -2. Install the following dependencies - -:::code-group - -```sh [<i class="devicon-archlinux-plain"></i> Arch] -sudo pacman -Syu go npm gjs -``` - -```sh [<i class="devicon-fedora-plain"></i> Fedora] -sudo dnf install golang npm gjs -``` - -```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] -sudo apt install golang-go npm gjs -``` - -::: - -3. Clone the repo and Install - -<!--TODO: remove v2 after merge--> -```sh -git clone https://github.com/aylur/ags.git -cd ags/src -git checkout v2 # https://github.com/Aylur/ags/pull/504 -go install -``` - -:::info -If you have installed Astal **not** in `/usr` make sure to set its path. - -```sh -go install -ldflags "-X main.astalGjs=$(pkg-config --variable prefix astal-0.1)/share/astal/gjs" -``` - -::: - -:::tip -`go install` installs the `ags` binary to `$GOPATH/bin` so make sure its in your `$PATH`. -You can move it to another directory if you like. For example - -```sh -mv $GOPATH/bin/ags ~/.local/bin/ags -``` - -::: diff --git a/docs/guide/getting-started/installation.md b/docs/guide/getting-started/installation.md index ef5c6e8..844de25 100644 --- a/docs/guide/getting-started/installation.md +++ b/docs/guide/getting-started/installation.md @@ -13,7 +13,7 @@ maintainer: [@kotontrion](https://github.com/kotontrion) :::code-group ```sh [Core Library] -yay -S libastal-git +yay -S libastal-io-git libastal-git ``` ```sh [Every Library] @@ -24,14 +24,7 @@ yay -S libastal-meta ## Bulding libastal from source -1. Clone the repo - -```sh -git clone https://github.com/aylur/astal.git -cd astal/core -``` - -2. Install the following dependencies +1. Install the following dependencies :::code-group @@ -44,26 +37,31 @@ sudo dnf install meson gcc valac gtk3-devel gtk-layer-shell-devel gobject-intros ``` ```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] -sudo apt install meson valac libgtk3-dev libgtk-layer-shell-dev gobject-introspection +sudo apt install meson valac libgtk-3-dev libgtk-layer-shell-dev gobject-introspection libgirepository1.0-dev ``` ::: +2. Clone the repo + +```sh +git clone https://github.com/aylur/astal.git /tmp/astal +``` + 3. Build and install with `meson` +- astal-io + ```sh -meson setup build +cd /tmp/astal/lib/astal/io +meson setup --prefix /usr build meson install -C build ``` -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: +- astal3 ```sh +cd /tmp/astal/lib/astal/gtk3 meson setup --prefix /usr build meson install -C build ``` - -::: diff --git a/docs/guide/getting-started/introduction.md b/docs/guide/getting-started/introduction.md index 92d2ff1..782c069 100644 --- a/docs/guide/getting-started/introduction.md +++ b/docs/guide/getting-started/introduction.md @@ -2,22 +2,25 @@ ## What is Astal? -Astal (_meaning "desk"_) is a bundle of libraries built using [GLib](https://docs.gtk.org/glib/) in Vala and C. -The core library [libastal](https://aylur.github.io/libastal) has some Gtk widgets that come packaged, -the most important one is the [Window](https://aylur.github.io/libastal/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). +Astal (_meaning "desk"_) is a suite of libraries in Vala and C. +The core library [astal3](https://aylur.github.io/libastal/astal3) and +[astal4](https://aylur.github.io/libastal/astal4) (not yet available) +has some Gtk widgets that come packaged, +the most important one being the [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). This is what allows us to use Gtk as shell components on Wayland. -libastal also comes with some utility functions such as running external processes, -reading, writing and monitoring files. +The other part of the core library [astal-io](https://aylur.github.io/libastal/astal-io) +which contains some utility GLib shortcut for running external processes, +reading, writing and monitoring files, timeout and interval functions. ## Why Astal? -What makes Astal convenient to use is not the core library, as it could easily be replaced +What makes Astal convenient to use is not the core libraries, as they can easily be replaced by the standard library of any of your favorite language that has bindings to Gtk, it is the -accompanying libraries (_formerly known as "services" in AGS_) +accompanying libraries (_formerly known as "services" in AGS_). Have you ever wanted to write a custom bar, custom notification popups or an applauncher, but gave up because writing a workspace widget, implementing the notification daemon or handling a search filter was too much of a hassle? -Astal libraries have you [covered](/guide/libraries/references), you don't have to worry about these, +Astal libraries have you [covered](../libraries/references#astal-libraries), you don't have to worry about these, you just define the layout, style it with CSS and that's it. diff --git a/docs/guide/getting-started/nix.md b/docs/guide/getting-started/nix.md index c9ed270..1e0572e 100644 --- a/docs/guide/getting-started/nix.md +++ b/docs/guide/getting-started/nix.md @@ -1,3 +1,8 @@ +--- +next: + link: '/guide/getting-started/supported-languages' + text: 'Supported Languages' +--- # Nix ## Astal @@ -20,7 +25,7 @@ Using Astal on Nix will require you to package your project. system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; in { - packages.${system}.default = astal.lib.mkLuaPacakge { + packages.${system}.default = astal.lib.mkLuaPackage { inherit pkgs; src = ./path/to/project; # should contain init.lua @@ -74,11 +79,16 @@ Using Astal on Nix will require you to package your project. } ``` +```nix [<i class="devicon-typescript-plain"></i> TypeScript] +# The usage of AGS (read below) is recommended +# Usage without AGS is not yet documented +``` + ::: ## AGS -The recommended way to use AGS on NixOS is through the home-manager module. +The recommended way to use [AGS](../typescript/first-widgets#first-widgets) on NixOS is through the home-manager module. Example content of a `flake.nix` file that contains your `homeConfigurations`. @@ -144,7 +154,7 @@ Example content of `home.nix` file ::: -AGS by default only includes the core `libastal` library. +AGS by default only includes the core `astal3/astal4` and `astal-io` libraries. If you want to include any other [library](../libraries/references) you have to add them to `extraPackages`. You can also add binaries which will be added to the gjs runtime. @@ -158,7 +168,11 @@ The AGS flake does not expose the `astal` cli to the home environment, you have :::code-group ```nix [<i class="devicon-nixos-plain"></i> home.nix] -home.packages = [ inputs.ags.packages.${pkgs.system}.astal ]; +home.packages = [ inputs.ags.packages.${pkgs.system}.io ]; +``` + +```sh [<i class="devicon-bash-plain"></i> sh] +astal --help ``` ::: diff --git a/docs/guide/getting-started/supported-languages.md b/docs/guide/getting-started/supported-languages.md index 4cb7f3a..d6d669d 100644 --- a/docs/guide/getting-started/supported-languages.md +++ b/docs/guide/getting-started/supported-languages.md @@ -1,9 +1,15 @@ # Supported Languages +There are currently two languages that have an additional +Astal package: Lua and Gjs. Their purpose is to abstract away +Gtk by implementing a state management and UI declaring solution. + ## JavaScript -The main intended usage of Astal is in TypeScript with [AGS](/guide/ags/first-widgets). -It supports JSX and has a state management solution similar to web frameworks. +The main intended usage of Astal is in TypeScript+JSX. +It is recommended to use [AGS](/guide/typescript/first-widgets) to scaffold and run projects in TypeScript. +However, if you are familiar with JavaScript's tooling +ecosystem you can also setup an environment yourself. Only a minimal knowledge of JavaScript's syntax is needed to get started. :::info @@ -17,11 +23,7 @@ Examples: ## Lua -Similar to how there is a [TypeScript](https://github.com/Aylur/astal/tree/main/core/gjs) lib for GJS, there is also an accompanying library for [Lua](https://github.com/Aylur/astal/tree/main/core/lua). -<!--TODO: open issue and link performance issue--> -Unfortunately, I have encountered very heavy [performance issues](https://github.com/aylur/astal) with [lgi](https://github.com/lgi-devs/lgi), -and so currently I don't recommend using Lua for full desktop shells, but only for static -components that don't render child nodes dynamically, bars and panels for example. +Lua is well-supported, but I would still recommend TypeScript, as Lua lacks a type system, which in turn limits editor support. Examples: @@ -30,10 +32,9 @@ Examples: ## Python -There was a WIP [library for python](https://github.com/aylur/astal/tree/feat/python), to make it behave similar to the above two -but I don't plan on finishing it, because I'm not a fan of python. -If you are interested in picking it up, feel free to open a PR. -Nonetheless you can still use python the OOP way [pygobject](https://pygobject.gnome.org/tutorials/gobject/subclassing.html) intended it. +There is a WIP [package for python](https://github.com/aylur/astal/tree/feat/python), +to bring declaritivity to Python similar to the above two languages. +However, you can still use python the OOP way [pygobject](https://pygobject.gnome.org/tutorials/gobject/subclassing.html) intended it in the meantime. Examples: @@ -44,7 +45,7 @@ Examples: Vala is a language that simply put uses C# syntax and compiles to C. It is the language most of Astal is written in. I would still recommend -using TypeScript or Lua over Vala as they don't need a build step. +using TypeScript or Lua over Vala as they are simpler to work with. Examples: diff --git a/docs/guide/libraries/apps.md b/docs/guide/libraries/apps.md index c53daf0..7f9ee6e 100644 --- a/docs/guide/libraries/apps.md +++ b/docs/guide/libraries/apps.md @@ -33,21 +33,10 @@ cd astal/lib/apps 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Apps reference](https://aylur.github.io/libastal/apps). @@ -106,8 +95,3 @@ end ``` ::: - -:::info -The fuzzy query uses [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). I am not a mathematician, but if you know how to reimplement -the logic of [fzf](https://github.com/junegunn/fzf) to make it better feel free to open PRs. -::: diff --git a/docs/guide/libraries/auth.md b/docs/guide/libraries/auth.md index 1f07a17..d5f0a49 100644 --- a/docs/guide/libraries/auth.md +++ b/docs/guide/libraries/auth.md @@ -43,21 +43,10 @@ cd astal/lib/auth 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Auth reference](https://aylur.github.io/libastal/auth). diff --git a/docs/guide/libraries/battery.md b/docs/guide/libraries/battery.md index b42d747..7f94297 100644 --- a/docs/guide/libraries/battery.md +++ b/docs/guide/libraries/battery.md @@ -37,21 +37,10 @@ cd astal/lib/battery 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Battery reference](https://aylur.github.io/libastal/battery). diff --git a/docs/guide/libraries/bluetooth.md b/docs/guide/libraries/bluetooth.md index 04d9db2..672f66d 100644 --- a/docs/guide/libraries/bluetooth.md +++ b/docs/guide/libraries/bluetooth.md @@ -37,21 +37,10 @@ cd astal/lib/bluetooth 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Bluetooth reference](https://aylur.github.io/libastal/bluetooth). diff --git a/docs/guide/libraries/hyprland.md b/docs/guide/libraries/hyprland.md index faf9e50..672faad 100644 --- a/docs/guide/libraries/hyprland.md +++ b/docs/guide/libraries/hyprland.md @@ -32,21 +32,10 @@ cd astal/lib/hyprland 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Hyprland reference](https://aylur.github.io/libastal/hyprland). diff --git a/docs/guide/libraries/mpris.md b/docs/guide/libraries/mpris.md index dfe7956..8f28924 100644 --- a/docs/guide/libraries/mpris.md +++ b/docs/guide/libraries/mpris.md @@ -6,6 +6,18 @@ exposing an mpris interface through dbus. An alternative for [playerctl](https://github.com/altdesktop/playerctl) that better integrates with astal. +:::warning +In order for network cover art urls to be cached (spotify for example) +make sure `gvfs` is enabled. + +:::code-group + +```nix [<i class="devicon-nixos-plain"></i> configuration.nix] +services.gvfs.enable = true; +``` + +::: + ## Installation 1. install dependencies @@ -13,15 +25,15 @@ with astal. :::code-group ```sh [<i class="devicon-archlinux-plain"></i> Arch] -sudo pacman -Syu meson vala json-glib gobject-introspection +sudo pacman -Syu meson vala gvfs json-glib gobject-introspection ``` ```sh [<i class="devicon-fedora-plain"></i> Fedora] -sudo dnf install meson gcc valac json-glib-devel gobject-introspection-devel +sudo dnf install meson gcc valac gvfs json-glib-devel gobject-introspection-devel ``` ```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] -sudo apt install meson valac libjson-glib-dev gobject-introspection +sudo apt install meson valac gvfs libjson-glib-dev gobject-introspection ``` ::: @@ -36,21 +48,10 @@ cd astal/lib/mpris 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Mpris reference](https://aylur.github.io/libastal/mpris). diff --git a/docs/guide/libraries/network.md b/docs/guide/libraries/network.md index afeb5d2..e076950 100644 --- a/docs/guide/libraries/network.md +++ b/docs/guide/libraries/network.md @@ -32,21 +32,10 @@ cd astal/lib/network 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Network reference](https://aylur.github.io/libastal/network). diff --git a/docs/guide/libraries/notifd.md b/docs/guide/libraries/notifd.md index 7e02149..094b770 100644 --- a/docs/guide/libraries/notifd.md +++ b/docs/guide/libraries/notifd.md @@ -36,21 +36,10 @@ cd astal/lib/notifd 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Notifd reference](https://aylur.github.io/libastal/notifd). diff --git a/docs/guide/libraries/powerprofiles.md b/docs/guide/libraries/powerprofiles.md index 8571c29..159f3ff 100644 --- a/docs/guide/libraries/powerprofiles.md +++ b/docs/guide/libraries/powerprofiles.md @@ -37,21 +37,10 @@ cd astal/lib/powerprofiles 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [PowerProfiles reference](https://aylur.github.io/libastal/powerprofiles). diff --git a/docs/guide/libraries/references.md b/docs/guide/libraries/references.md index 8f2bd02..3a85d73 100644 --- a/docs/guide/libraries/references.md +++ b/docs/guide/libraries/references.md @@ -29,7 +29,6 @@ Reading their documentation will vary depending on the language they are used in ## Astal Libraries -- [Astal](https://aylur.github.io/libastal): libastal the core library, which has the widgets and utilites - [Apps](https://aylur.github.io/libastal/apps): Library and cli tool for querying applications - [Auth](https://aylur.github.io/libastal/auth): Authentication library using PAM - [Battery](https://aylur.github.io/libastal/battery): DBus proxy library for upower daemon diff --git a/docs/guide/libraries/river.md b/docs/guide/libraries/river.md index 4818d0b..299aa8c 100644 --- a/docs/guide/libraries/river.md +++ b/docs/guide/libraries/river.md @@ -32,21 +32,10 @@ cd astal/lib/river 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [River reference](https://aylur.github.io/libastal/river). diff --git a/docs/guide/libraries/tray.md b/docs/guide/libraries/tray.md index c8d093b..b5cccc7 100644 --- a/docs/guide/libraries/tray.md +++ b/docs/guide/libraries/tray.md @@ -32,21 +32,10 @@ cd astal/lib/tray 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Tray reference](https://aylur.github.io/libastal/tray). diff --git a/docs/guide/libraries/wireplumber.md b/docs/guide/libraries/wireplumber.md index 5f1daab..0592628 100644 --- a/docs/guide/libraries/wireplumber.md +++ b/docs/guide/libraries/wireplumber.md @@ -32,21 +32,10 @@ cd astal/lib/wireplumber 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Wireplumber reference](https://aylur.github.io/libastal/wireplumber). diff --git a/docs/guide/lua/binding.md b/docs/guide/lua/binding.md new file mode 100644 index 0000000..f4d5f0b --- /dev/null +++ b/docs/guide/lua/binding.md @@ -0,0 +1,139 @@ +# Binding + +As mentioned before binding an object's state to another - +so in most cases a `Variable` or a `GObject.Object` property to a widget's property - +is done through the `bind` function which returns a `Binding` object. + +`Binding` objects simply hold information about the source and how it should be transformed +which Widget constructors can use to setup a connection between themselves and the source. + +```lua +---@class Binding<T> +---@field private transform_fn fun(value: T): any +---@field private emitter Connectable | Subscribable<T> +---@field private property? string +---@field as fun(transform: fun(value: T): any): Binding +---@field get fun(): T +---@field subscribe fun(self, callback: fun(value: T)): function +``` + +A `Binding` can be constructed from an object implementing +the `Subscribable` interface (usually a `Variable`) +or an object implementing the `Connectable` interface and one of its properties +(usually a `GObject.Object` instance). + +Lua type annotations are not expressive enough to explain this, +so I'll use TypeScript to demonstrate it. + +<!--TODO: use Teal maybe?--> + +```ts +function bind<T>(obj: Subscribable<T>): Binding<T> + +function bind< + Obj extends Connectable, + Prop extends keyof Obj, +>(obj: Obj, prop: Prop): Binding<Obj[Prop]> +``` + +## Subscribable and Connectable interface + +Any object implementing one of these interfaces can be used with `bind`. + +```ts +interface Subscribable<T> { + subscribe(callback: (value: T) => void): () => void + get(): T +} + +interface Connectable { + connect(signal: string, callback: (...args: any[]) => unknown): number + disconnect(id: number): void +} +``` + +`Connectable` is usually used for GObjects coming from [libraries](../libraries/references) +You won't be implementing it in Lua code. + +## Example Custom Subscribable + +When binding the children of a box from an array, usually not all elements +of the array changes each time, so it would make sense to not destroy +the widget which represents the element. + +::: code-group + +```lua :line-numbers [varmap.lua] +local Gtk = require("astal.gtk3").Gtk +local Variable = require("astal.variable") + +---@param initial table +return function(initial) + local map = initial + local var = Variable() + + local function notify() + local arr + for _, value in pairs(map) do + table.insert(arr, value) + end + var:set(arr) + end + + local function delete(key) + if Gtk.Widget:is_type_of(map[key]) then + map[key]:destroy() + end + + map[key] = nil + end + + notify() -- init + + return { + set = function(key, value) + delete(key) + map[key] = value + notify() + end, + delete = function(key) + delete(key) + notify() + end, + get = function() + return var:get() + end, + subscribe = function(callback) + return var:subscribe(callback) + end, + } +end +``` + +::: + +And this `VarMap<key, Widget>` can be used as an alternative to `Variable<Array<Widget>>`. + +```lua +function MappedBox() + local map = varmap({ + ["1"] = Widget.Label({ label = "1" }), + ["2"] = Widget.Label({ label = "2" }), + }) + + return Widget.Box({ + setup = function (self) + self:hook(gobject, "added", function (_, id) + map.set(id, Widget.Label({ label = id })) + end) + self:hook(gobject, "removed", function (_, id) + map.delete(id) + end) + end, + bind(map):as(function (arr) + -- can be sorted here + return arr + end), + }) +end +``` diff --git a/docs/guide/lua/cli-app.md b/docs/guide/lua/cli-app.md new file mode 100644 index 0000000..6bfaa9e --- /dev/null +++ b/docs/guide/lua/cli-app.md @@ -0,0 +1,131 @@ +# CLI and App + +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html). + +Depending on gtk version require paths will differ + +<!--TODO: remove gtk4 notice when its available--> + +```lua +local App = require("astal.gtk3.app") + +local App = require("astal.gtk4.app") -- not yet available +``` + +## Entry point + +`App:start` is a wrapper function for `App:run` +that will only run the application if there is no +instance already running with the specified name. + +:::code-group + +```lua [init.lua] +App:start({ + instance_name = "my-instance", -- defaults to "astal" + main = function() + -- setup anything + -- instantiate widgets + end, +}) +``` + +::: + +## Messaging from CLI + +If you want to interact with an instance from the CLI, +you can do so by sending a request. + +```lua +App:start({ + main = function() end, + + ---@param request string + ---@param res fun(response: any): nil + request_handler = function(request, res) + if request == "say hi" then + return res("hi cli") + end + res("unknown command") + end +}) +``` + +```sh +astal say hi +# hi cli +``` + +## Toggling Windows by their name + +In order for Astal to know about your windows, you have to register them. +You can do this by specifying a **unique** `name` and calling `App:add_window`. + +```lua +local App = require("astal.gtk3.app") + +local function Bar() + return Widget.Window({ + name = "Bar", + setup = function(self) + App:add_window(self) + end, + Widget.Box() + }) +end +``` + +You can also invoke `App:add_window` by simply passing the `App` to the `application` prop. + +```lua +local App = require("astal.gtk3.app") + +local function Bar() + return Widget.Window({ + name = "Bar", + application = App, + Widget.Box() + }) +end +``` + +```sh +astal -t Bar +``` + +:::warning +When assigning the `application` prop make sure `name` comes before. +Props are set sequentially and if name is applied after application it won't work. +::: + +## Client instances + +The first time `App:start` is invoked the `main` function gets called. +While that instance is running any subsequent execution of the script will call +the `client` function. + +:::code-group + +```lua [init.lua] +App:start({ + -- main instance + main = function(...) + local args = { ... } + print(string.format("{%s}", table.concat(args, ", "))) + end, + + -- client instance + client = function(request, ...) + local res = request("you can send a request to the main instance") + print(res) + end, + + -- this runs in the main instance + request_handler = function(request, res) + res("response from main instance") + end +}) +``` + +::: diff --git a/docs/guide/lua/first-widgets.md b/docs/guide/lua/first-widgets.md new file mode 100644 index 0000000..efc1c4f --- /dev/null +++ b/docs/guide/lua/first-widgets.md @@ -0,0 +1,265 @@ +# First Widgets + +## Getting Started + +Start by importing the singleton +[Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html) instance. + +:::code-group + +```lua [init.lua] +local App = require("astal.gtk3.app") + +App:start({ + main = function() + -- you will instantiate Widgets here + -- or setup anything else if you need + print("hi") + end +}) +``` + +::: + +Then run `lua init.lua` in the terminal, and that's it! +Now you have an instance running with Lua. + +## Root of every shell component: Window + +Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. +A widget can be as small as a button or an entire bar. +The top level widget is always a [Window](https://aylur.github.io/libastal/astal3/class.Window.html) +which will hold all widgets. + +::: code-group + +```lua [widget/Bar.lua] +local Widget = require("astal.gtk3.widget") +local Anchor = require("astal.gtk3").Astal.WindowAnchor + +return function(monitor) + return Widget.Window({ + monitor = monitor, + anchor = Anchor.TOP + Anchor.LEFT + Anchor.RIGHT, + exclusivity = "EXCLUSIVE", + Widget.Label({ + label = "Example label content", + }), + }) +end +``` + +::: + +::: code-group + +```lua [init.lua] +local App = require("astal.gtk3.app") +local Bar = require("widget.Bar") + +App:start { + main = function() + Bar(0) + Bar(1) -- instantiate for each monitor + end, +} +``` + +::: + +## Creating and nesting widgets + +Widgets are simply Lua functions that return Gtk widgets, +you can nest widgets by passing them as arguments to the table in the function. + +:::code-group + +```lua [widget/MyButton.lua] +local Widget = require("astal.gtk3.widget") + +return function(text) + return Widget.Button({ + on_click_release = function(_, event) + if event.button == "PRIMARY" then + print("Left click") + elseif event.button == "SECONDARY" then + print("Right click") + end + end, + Widget.Label({ + label = text, + }), + }) +end +``` + +::: + +Now, you should be able to nest it into another widgets. + +::: code-group + +```lua [widget/Bar.lua] {13} +local MyButton = require("widget.MyButton") +local Anchor = require("astal.gtk3").Astal.WindowAnchor + +return function(monitor) + return Widget.Window({ + monitor = monitor, + anchor = Anchor.TOP + Anchor.LEFT + Anchor.RIGHT, + exclusivity = "EXCLUSIVE", + Widget.Box({ + Widget.Label({ + label = "Click the button", + }), + MyButton("hi, im a button"), + }), + }) +end +``` + +::: + +## Widget signal handlers + +You can respond to events by declaring event handler functions inside your widget: + +```lua +local function MyButton() + return Widget.Button({ + on_click_release = function(_, event) + print(event.button) + end, + }) +end +``` + +:::info +Keys prefixed with `on_` will connect to a `signal` of the widget. +Refer to the Gtk and Astal docs to have a full list of them. +::: + +## State management + +The state of widgets are handled with Bindings. A [Binding](./binding) lets you +connect the state of an [object](./binding#subscribable-and-connectable-interface) +to a widget so it re-renders when that state changes. + +Use the `bind` function to create a `Binding` object from a `Variable` or +a regular `GObject` and one of its properties. + +Here is an example of a Counter widget that uses a `Variable` as its state: + +```lua +local astal = require("astal") +local bind = astal.bind +local Variable = astal.Variable +local Widget = require("astal.gtk3.widget") + +local function Counter() + local count = Variable(0) + return Widget.Box({ + Widget.Label({ + label = bind(count):as(tostring), + }), + Widget.Button({ + label = "Click to increment", + on_click_release = function() + count:set(count:get() + 1) + end, + }), + }) +end +``` + +:::info +Bindings have an `:as()` method which lets you transform the assigned value. +In the case of a Label, its label property expects a string, so it needs to be +converted into a string first. +::: + +:::tip +`Variables` have a shorthand for `bind(variable):as(transform)` + +```lua +local v = Variable(0) + +return Widget.Box { + -- these three are equivalent + Widget.Label({ label = bind(v):as(tostring) }), + Widget.Label({ label = v():as(tostring) }), + Widget.Label({ label = v(tostring) }), +} +``` + +::: + +Here is an example of a battery percent label that binds the `percentage` +property of the Battery object from the [Battery Library](/guide/libraries/battery): + +```lua +local astal = require("astal") +local bind = astal.bind +local Battery = astal.require("AstalBattery") +local Widget = require("astal.gtk3.widget") + +local function BatteryPercentage() + local bat = Battery.get_default() + + return Widget.Label({ + label = bind(bat, "percentage"):as(function(p) + return string.format("%.0f%%", p * 100) + end), + }) +end +``` + +## Dynamic children + +You can also use a `Binding` for `child` and `children` properties. + +```lua +local astal = require("astal") +local Variable = astal.Variable +local Widget = require("astal.gtk3.widget") + +local child = Variable(Widget.Box()) + +return Widget.Box({ + child(), +}) +``` + +```lua +local num = Variable(3) + +return Widget.Box { + num():as(function(n) + local tbl = {} + for i = 1, n do + table.insert(tbl, Widget.Button({ + label = tostring(i) + })) + end + return tbl + end) +} +``` + +:::tip +Binding children of widgets will implicitly call `:destroy()` on widgets +that would be left without a parent. You can opt out of this behavior +by setting `no_implicity_destroy` property on the container widget. +::: + +:::info +You can pass the followings as children: + +- widgets +- deeply nested arrays of widgets +- bindings of widgets, +- bindings of deeply nested arrays of widgets + +`nil` is the only value that is not rendered and anything not from this list +will be coerced into a string and rendered as a label. +::: diff --git a/docs/guide/lua/installation.md b/docs/guide/lua/installation.md new file mode 100644 index 0000000..b99d8df --- /dev/null +++ b/docs/guide/lua/installation.md @@ -0,0 +1,25 @@ +# Installation + +## Nix + +maintainer: [@Aylur](https://github.com/Aylur) + +Read more about it on the [nix page](../getting-started/nix) + +## Arch + +```sh +yay -S lua-libastal-git +``` + +## From Source + +1. [Install Astal](../getting-started/installation.md) if you have not already + +2. Install the Astal Lua package + +```sh +git clone https://github.com/aylur/astal.git +cd lang/lua +sudo luarocks make +``` diff --git a/docs/guide/lua/theming.md b/docs/guide/lua/theming.md new file mode 100644 index 0000000..502e8e9 --- /dev/null +++ b/docs/guide/lua/theming.md @@ -0,0 +1,130 @@ +# Theming + +Since the widget toolkit is **GTK3** theming is done with **CSS**. + +- [CSS tutorial](https://www.w3schools.com/css/) +- [GTK CSS Overview wiki](https://docs.gtk.org/gtk3/css-overview.html) +- [GTK CSS Properties Overview wiki](https://docs.gtk.org/gtk3/css-properties.html) + +:::warning GTK is not the web +While most features are implemented in GTK, +you can't assume anything that works on the web will work with GTK. +Refer to the [GTK docs](https://docs.gtk.org/gtk3/css-overview.html) +to see what is available. +::: + +So far every widget you made used your default GTK3 theme. +To make them more custom, you can apply stylesheets to them. + +## From file at startup + +You can pass a path to a file or css as a string in `App:start` + +:::code-group + +```lua [init.lua] +local inline_css = [[ + window { + background-color: transparent; + } +]] + +App:start({ + css = inline_css, + css = "/path/to/style.css", + css = "./style.css", +}) +``` + +::: + +:::warning +When using relative paths, so for example `./style.css` keep in mind that they +will be relative to the current working directory. +::: + +## Css Property on Widgets + +```lua +Widget.Label({ + css = "color: blue; padding: 1em;", + label = "hello" +}) +``` + +:::info +The `css` property of a widget will not cascade to its children. +::: + +## Apply Stylesheets at Runtime + +You can apply additional styles at runtime. + +```lua +App:apply_css("/path/to/file.css") +``` + +```lua +App:apply_css([[ + window { + background-color: transparent; + } +]]) +``` + +```lua +App:reset_css() -- reset if need +``` + +:::warning +`App:apply_css` will apply on top of other stylesheets applied before. +You can reset stylesheets with `App:reset_css` +or by passing `true` as a second parameter to `App:apply_css`. +::: + +## Inspector + +If you are not sure about the widget hierarchy or any CSS selector, +you can use the [GTK inspector](https://wiki.gnome.org/Projects/GTK/Inspector) + +```sh +# to bring up the inspector run +astal --inspector +``` + +## Using SCSS + +Gtk's CSS only supports a subset of what the web offers. +Most notably nested selectors are unsupported by Gtk, but this can be +workaround by using preprocessors like [SCSS](https://sass-lang.com/). + +:::code-group + +```sh [<i class="devicon-archlinux-plain"></i> Arch] +sudo pacman -Syu dart-sass +``` + +```sh [<i class="devicon-fedora-plain"></i> Fedora] +npm install -g sass # not packaged on Fedora +``` + +```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] +npm install -g sass # not packaged on Ubuntu +``` + +::: + +:::code-group + +```lua [init.lua] +local scss = "./style.scss" +local css = "/tmp/style.css" + +astal.exec(string.format("sass %s %s", scss, css)) + +App:start({ + css = css, +}) +``` + +::: diff --git a/docs/guide/lua/utilities.md b/docs/guide/lua/utilities.md new file mode 100644 index 0000000..1ef70c7 --- /dev/null +++ b/docs/guide/lua/utilities.md @@ -0,0 +1,191 @@ +# Utilities + +## File functions + +```lua +local read_file = astal.read_file +local read_file_async = astal.read_file_async +local write_file = astal.write_file +local write_file_async = astal.write_file_async +local monitor_file = astal.monitor_file +``` + +### Reading files + +```lua +---@param path string +---@return string +local function read_file(path) end + +---@param path string +---@param callback fun(content: string, err: string): nil +local function read_file_async(path, callback) end +``` + +### Writing files + +```lua +---@param path string +---@param content string +local function write_file(path, content) end + +---@param path string +---@param content string +---@param callback? fun(err: string): nil +local function write_file_async(path, content, callback) end +``` + +### Monitoring files + +```lua +---@param path string +---@param callback fun(file: string, event: Gio.FileMonitorEvent): nil +local function monitor_file(path, callback) end +``` + +## Timeouts and Intervals + +```lua +local interval = astal.interval +local timeout = astal.timeout +local idle = astal.idle +``` + +### Interval + +Will immediately execute the function and every `interval` millisecond. + +```lua +---@param interval number +---@param callback? function +---@return Astal.Time +local function interval(interval, callback) end +``` + +### Timeout + +Will execute the `callback` after `timeout` millisecond. + +```lua +---@param timeout number +---@param callback? function +---@return Astal.Time +local function timeout(timeout, callback) end +``` + +### Idle + +Executes `callback` whenever there are no higher priority events pending. + +```lua +---@param callback? function +---@return Astal.Time +local function idle(callback) end +``` + +Example: + +```lua +local timer = interval(1000, function() + print("optional callback") +end) + +timer.on_now = function() + print("now") +end + +timer.on_cancelled = function() + print("cancelled") +end + +timer:cancel() +``` + +## Process functions + +```lua +local subprocess = astal.subprocess +local exec = astal.exec +local exec_async = astal.exec_async +``` + +### Subprocess + +You can start a subprocess and run callback functions whenever it outputs to +stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/io/class.Process.html) has a `stdout` and `stderr` signal. + +```lua +---@param commandline string | string[] +---@param on_stdout? fun(out: string): nil +---@param on_stderr? fun(err: string): nil +---@return Astal.Process | nil +local function subprocess(commandline, on_stdout, on_stderr) end +``` + +Example: + +```lua +local proc = subprocess( + "some-command", + function(out) print(out) end, + function(err) print(err) end, +) + +-- with signals +local proc = subprocess("some-command") + +proc.on_stdout = function(_, stdout) + print(stdout) +end + +proc.on_stderr = function(_, stderr) + print(stderr) +end +``` + +### Executing external commands and scripts + +```lua +---@param commandline string | string[] +---@return string, string +local function exec(commandline) end + +---@param commandline string | string[] +---@param callback? fun(out: string, err: string): nil +local function exec_async(commandline, callback) end +``` + +Example: + +```lua +local out, err = exec("/path/to/script") + +if err ~= nil then + print(err) +else + print(out) +end + +exec_async({ "bash", "-c", "/path/to/script.sh" }, function(out, err) + if err ~= nil then + print(err) + else + print(out) + end +end) +``` + +:::warning +`subprocess`, `exec`, and `exec_async` executes the passed executable as is. +They are **not** executed in a shell environment, +they do **not** expand ENV variables like `$HOME`, +and they do **not** handle logical operators like `&&` and `||`. + +If you want bash, run them with bash. + +```lua +exec({ "bash", "-c", "command $VAR && command" }) +exec("bash -c 'command $VAR' && command") +``` + +::: diff --git a/docs/guide/lua/variable.md b/docs/guide/lua/variable.md new file mode 100644 index 0000000..915632c --- /dev/null +++ b/docs/guide/lua/variable.md @@ -0,0 +1,162 @@ +# Variable + +```lua +local Variable = require("astal").Variable +local Variable = require("astal.variable") +``` + +Variable is just a simple object which holds a single value. +It also has some shortcuts for hooking up subprocesses, intervals and other gobjects. + +## Example Usage + +```lua +local my_var = Variable("initial-value") + +-- whenever its value changes, callback will be executed +my_var:subscribe(function(value) + print(value) +end) + +-- settings its value +my_var:set("new value") + +-- getting its value +local value = my_var:get() + +-- binding them to widgets +Widget.Label({ + label = bind(my_var):as(function(value) + return string.format("transformed %s", value) + end), + -- shorthand for the above + label = my_var(function(value) + return string.format("transformed %s", value) + end) +}) +``` + +:::warning +Make sure to the transform functions you pass to `:as()` are pure. +The `:get()` function can be called anytime by `astal` especially when `deriving`, +so make sure there are no sideeffects. +::: + +## Variable Composition + +Using `Variable.derive` any `Subscribable` object can be composed. + +```lua +local v1 = Variable(1) -- Variable +local v2 = bind(obj, "prop") -- Binding +local v3 = { -- Subscribable + get = function() + return 3 + end, + subscribe = function() + return function() end + end, +} + +-- first argument is a list of dependencies +-- second argument is a transform function, +-- where the parameters are the values of the dependencies in the order they were passed +local v4 = Variable.derive({ v1, v2, v3 }, function(v1, v2, v3) + return v1 * v2 * v3 +end) +``` + +## Subprocess shorthands + +Using `:poll` and `:watch` you can start subprocesses and capture their +output. They can poll and watch at the same time, but they +can only poll/watch once. + +:::warning +The command parameter is passed to [exec_async](/guide/lua/utilities#executing-external-commands-and-scripts) +which means they are **not** executed in a shell environment, +they do **not** expand ENV variables like `$HOME`, +and they do **not** handle logical operators like `&&` and `||`. + +If you want bash, run them with bash. + +```lua +Variable(""):poll(1000, { "bash", "-c", "command $VAR && command" }) +``` + +::: + +```lua +local my_var = Variable(0) + :poll(1000, "command", function(out, prev) + return tonumber(out) + end) + :poll(1000, { "bash", "-c", "command" }, function(out, prev) + return tonumber(out) + end) + :poll(1000, function(prev) + return prev + 1 + end) +``` + +```lua +local my_var = Variable(0) + :watch("command", function(out, prev) + return tonumber(out) + end) + :watch({ "bash", "-c", "command" }, function(out, prev) + return tonumber(out) + end) +``` + +You can temporarily stop them and restart them whenever. + +```lua +my_var:stop_watch() -- this kills the subprocess +my_var:stop_poll() + +my_var:start_listen() -- launches the subprocess again +my_var:start_poll() + +print(my_var:is_listening()) +print(my_var:is_polling()) +``` + +## Gobject connection shorthands + +Using `:observe` you can connect gobject signals and capture their value. + +```lua +local my_var = Variable("") + :observe(obj1, "signal", function() + return "" + end):observe(obj2, "signal", function() + return "" + end) +``` + +## Dispose if no longer needed + +This will stop the interval, force exit the subprocess and disconnect gobjects. + +```lua +my_var:drop() +``` + +:::warning +Don't forget to drop derived variables or variables with +either `:poll`, `:watch` or `:observe` when they are defined inside closures. + +```lua +local function MyWidget() + local my_var = Variable():poll() + + return Widget.Box({ + on_destroy = function() + my_var:drop() + end + }) +end +``` + +::: diff --git a/docs/guide/lua/widget.md b/docs/guide/lua/widget.md new file mode 100644 index 0000000..d9f99fa --- /dev/null +++ b/docs/guide/lua/widget.md @@ -0,0 +1,158 @@ +# Widget + +## Gtk3 + +### Additional widget properties + +These are properties that Astal additionally adds to Gtk.Widgets + +- class_name: `string` - List of class CSS selectors separated by white space. +- css: `string` - Inline CSS. e.g `label { color: white; }`. If no selector is specified `*` will be assumed. e.g `color: white;` will be inferred as `* { color: white; }`. +- cursor: `string` - Cursor style when hovering over widgets that have hover states, e.g it won't work on labels. [list of valid values](https://docs.gtk.org/gdk3/ctor.Cursor.new_from_name.html). +- click_through: `boolean` - Lets click events through. + +To have a full list of available properties, reference the documentation of the widget. + +- [Astal3 widgets](https://aylur.github.io/libastal/astal3/index.html#classes) +- [Gtk widgets](https://docs.gtk.org/gtk3/#classes) + +### Additional widget methods + +#### setup + +`setup` is a convenience prop to remove the need to predefine widgets +before returning them in cases where a reference is needed. + +without `setup` + +```lua +local function MyWidget() + local button = Widget.Button() + -- setup button + return button +end +``` + +using `setup` + +```lua +local function MyWidget() + return Widget.Button({ + setup = function(self) + -- setup button + end, + }) +end +``` + +#### hook + +Shorthand for connecting and disconnecting to [Subscribable and Connectable](./binding#subscribable-and-connectable-interface) objects. + +without `hook` + +```lua +local function MyWidget() + local id = gobject.on_signal:connect(callback) + local unsub = variable:subscribe(callback) + + return Widget.Box({ + on_destroy = function() + GObject.signal_handler_disconnect(gobject, id) + unsub() + end, + }) +end +``` + +with `hook` + +```lua +local function MyWidget() + return Widget.Box({ + setup = function(self) + self:hook(gobject, "signal", callback) + self:hook(variable, callback) + end, + }) +end +``` + +#### toggle_class_name + +Toggle class names based on a condition. + +```lua +local function MyWidget() + return Widget.Box({ + setup = function(self) + self:toggle_class_name("classname", some_condition) + end, + }) +end +``` + +### How to use non builtin Gtk widgets + +Using the `astalify` function you can wrap widgets +to behave like builtin widgets. +It will apply the following: + +- set `visible` to true by default (Gtk3 widgets are invisible by default) +- make gobject properties accept and consume `Binding` objects +- add properties and methods listed above + +```lua +local astal = require("astal.gtk3") +local astalify = astal.astalify +local Gtk = astal.Gtk +local Gdk = astal.Gdk + +local ColorButton = astalify(Gtk.ColorButton) + +local function MyWidget() + return ColorButton({ + setup = function(self) + -- setup ColorButton instance + end, + use_alpha = true, + rgba = Gdk.RGBA({ + red = 1, + green = 0, + blue = 0, + alpha = 0.5, + }), + on_color_set = function(self) + print(self.rgba:to_string()) + end + }) +end +``` + +### Builtin Widgets + +You can check the [source code](https://github.com/Aylur/astal/blob/main/lang/lua/astal/gtk3/widget.lua) to have a full list of builtin widgets. + +These widgets are available by default in Lua. + +- Box: [Astal.Box](https://aylur.github.io/libastal/astal3/class.Box.html) +- Button: [Astal.Button](https://aylur.github.io/libastal/astal3/class.Button.html) +- CenterBox: [Astal.CenterBox](https://aylur.github.io/libastal/astal3/class.CenterBox.html) +- CircularProgress: [Astal.CircularProgress](https://aylur.github.io/libastal/astal3/class.CircularProgress.html) +- DrawingArea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/astal3/class.DrawingArea.html) +- Entry: [Gtk.Entry](https://docs.gtk.org/gtk3/astal3/class.Entry.html) +- Eventbox: [Astal.EventBox](https://aylur.github.io/libastal/astal3/class.EventBox.html) +- Icon: [Astal.Icon](https://aylur.github.io/libastal/astal3/class.Icon.html) +- Label: [Astal.Label](https://aylur.github.io/libastal/astal3/class.Label.html) +- Levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/astal3/class.LevelBar.html) +- Overlay: [Astal.Overlay](https://aylur.github.io/libastal/astal3/class.Overlay.html) +- Revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/astal3/class.Revealer.html) +- Scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/astal3/class.Scrollable.html) +- Slider: [Astal.Slider](https://aylur.github.io/libastal/astal3/class.Slider.html) +- Stack: [Astal.Stack](https://aylur.github.io/libastal/astal3/class.Stack.html) +- Switch: [Gtk.Switch](https://docs.gtk.org/gtk3/astal3/class.Switch.html) +- Window: [Astal.Window](https://aylur.github.io/libastal/astal3/class.Window.html) + +## Gtk4 + +🚧 Work in Progress 🚧 diff --git a/docs/guide/typescript/binding.md b/docs/guide/typescript/binding.md new file mode 100644 index 0000000..15fe3cc --- /dev/null +++ b/docs/guide/typescript/binding.md @@ -0,0 +1,235 @@ +# Binding + +As mentioned before binding an object's state to another - +so in most cases a `Variable` or a `GObject.Object` property to a widget's property - +is done through the `bind` function which returns a `Binding` object. + +`Binding` objects simply hold information about the source and how it should be transformed +which Widget constructors can use to setup a connection between themselves and the source. + +```ts +class Binding<Value> { + private transformFn: (v: any) => unknown + private emitter: Subscribable<Value> | Connectable + private prop?: string + + as<T>(fn: (v: Value) => T): Binding<T> + get(): Value + subscribe(callback: (value: Value) => void): () => void +} +``` + +A `Binding` can be constructed from an object implementing +the `Subscribable` interface (usually a `Variable`) +or an object implementing the `Connectable` interface and one of its properties +(usually a `GObject.Object` instance). + +```ts +function bind<T>(obj: Subscribable<T>): Binding<T> + +function bind< + Obj extends Connectable, + Prop extends keyof Obj, +>(obj: Obj, prop: Prop): Binding<Obj[Prop]> +``` + +## Subscribable and Connectable interface + +Any object implementing one of these interfaces can be used with `bind`. + +```ts +interface Subscribable<T> { + subscribe(callback: (value: T) => void): () => void + get(): T +} + +interface Connectable { + connect(signal: string, callback: (...args: any[]) => unknown): number + disconnect(id: number): void +} +``` + +## Example Custom Subscribable + +When binding the children of a box from an array, usually not all elements +of the array changes each time, so it would make sense to not destroy +the widget which represents the element. + +::: code-group + +```ts :line-numbers [varmap.ts] +import { type Subscribable } from "astal/binding" +import { Gtk } from "astal" + +export class VarMap<K, T = Gtk.Widget> implements Subscribable { + #subs = new Set<(v: Array<[K, T]>) => void>() + #map: Map<K, T> + + #notifiy() { + const value = this.get() + for (const sub of this.#subs) { + sub(value) + } + } + + #delete(key: K) { + const v = this.#map.get(key) + + if (v instanceof Gtk.Widget) { + v.destroy() + } + + this.#map.delete(key) + } + + constructor(initial?: Iterable<[K, T]>) { + this.#map = new Map(initial) + } + + set(key: K, value: T) { + this.#delete(key) + this.#map.set(key, value) + this.#notifiy() + } + + delete(key: K) { + this.#delete(key) + this.#notifiy() + } + + get() { + return [...this.#map.entries()] + } + + subscribe(callback: (v: Array<[K, T]>) => void) { + this.#subs.add(callback) + return () => this.#subs.delete(callback) + } +} +``` + +::: + +And this `VarMap<key, Widget>` can be used as an alternative to `Variable<Array<Widget>>`. + +```tsx +function MappedBox() { + const map = new VarMap([ + [1, <MyWidget id={id} />] + [2, <MyWidget id={id} />] + ]) + + const conns = [ + gobject.connect("added", (_, id) => map.set(id, MyWidget({ id }))), + gobject.connect("removed", (_, id) => map.delete(id, MyWidget({ id }))), + ] + + return <box onDestroy={() => conns.map(id => gobject.disconnect(id))}> + {bind(map).as(arr => arr.sort(([a], [b]) => a - b).map(([,w]) => w))} + </box> +} +``` + +## Example Custom Connectable + +Astal provides [decorator functions](./gobject#example-usage) +that make it easy to subclass gobjects, however +you can read more about GObjects and subclassing +on [gjs.guide](https://gjs.guide/guides/gobject/subclassing.html#gobject-subclassing). + +Objects coming from [libraries](../libraries/references#astal-libraries) +usually have a singleton gobject you can access with `.get_default()`. + +Here is an example of a Brightness library by wrapping the `brightnessctl` cli utility +and by monitoring `/sys/class/backlight` + +::: code-group + +```ts :line-numbers [brightness.ts] +import GObject, { register, property } from "astal/gobject" +import { monitorFile, readFileAsync } from "astal/file" +import { exec, execAsync } from "astal/process" + +const get = (args: string) => Number(exec(`brightnessctl ${args}`)) +const screen = exec(`bash -c "ls -w1 /sys/class/backlight | head -1"`) +const kbd = exec(`bash -c "ls -w1 /sys/class/leds | head -1"`) + +@register({ GTypeName: "Brightness" }) +export default class Brightness extends GObject.Object { + static instance: Brightness + static get_default() { + if (!this.instance) + this.instance = new Brightness() + + return this.instance + } + + #kbdMax = get(`--device ${kbd} max`) + #kbd = get(`--device ${kbd} get`) + #screenMax = get("max") + #screen = get("get") / (get("max") || 1) + + @property(Number) + get kbd() { return this.#kbd } + + set kbd(value) { + if (value < 0 || value > this.#kbdMax) + return + + execAsync(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { + this.#kbd = value + this.notify("kbd") + }) + } + + @property(Number) + get screen() { return this.#screen } + + set screen(percent) { + if (percent < 0) + percent = 0 + + if (percent > 1) + percent = 1 + + execAsync(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { + this.#screen = percent + this.notify("screen") + }) + } + + constructor() { + super() + + const screenPath = `/sys/class/backlight/${screen}/brightness` + const kbdPath = `/sys/class/leds/${kbd}/brightness` + + monitorFile(screenPath, async f => { + const v = await readFileAsync(f) + this.#screen = Number(v) / this.#screenMax + this.notify("screen") + }) + + monitorFile(kbdPath, async f => { + const v = await readFileAsync(f) + this.#kbd = Number(v) / this.#kbdMax + this.notify("kbd") + }) + } +} +``` + +::: + +And it can be used like any other library object. + +```tsx +function BrightnessSlider() { + const brightness = Brightness.get_default() + + return <slider + value={bind(brightness, "screen")} + onDragged={({ value }) => brightness.screen = value} + /> +} +``` diff --git a/docs/guide/ags/cli-app.md b/docs/guide/typescript/cli-app.md index ec6d174..f409176 100644 --- a/docs/guide/ags/cli-app.md +++ b/docs/guide/typescript/cli-app.md @@ -1,9 +1,13 @@ # CLI and App -`App` is a singleton **instance** of [Astal.Application](https://aylur.github.io/libastal/class.Application.html). +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html). + +Depending on gtk version import paths will differ ```ts -import { App } from "astal" +import { App } from "astal/gtk3" + +import { App } from "astal/gtk4" ``` ## Entry point @@ -21,10 +25,6 @@ App.start({ ::: -:::warning -You can not instantiate widgets outside of the main function. -::: - ## Instance identifier You can run multiple instance by defining a unique instance name. @@ -32,47 +32,48 @@ You can run multiple instance by defining a unique instance name. ```ts App.start({ instanceName: "my-instance", // defaults to "astal" - main() {}, + main() { }, }) ``` ## Messaging from CLI -If you want to interact with an instance from the cli, you can do so by sending a message. +If you want to interact with an instance from the CLI, +you can do so by sending a message. ```ts App.start({ - main() {}, requestHandler(request: string, res: (response: any) => void) { if (request == "say hi") { res("hi cli") } res("unknown command") }, + main() { }, }) ``` :::code-group -```sh [ags] -ags -m "say hi" +```sh [astal] +astal say hi # hi cli ``` -```sh [astal] -astal say hi +```sh [ags] +ags -m "say hi" # hi cli ``` ::: -If you want to run arbitrary JavaScript from cli, you can use `App.eval`. -It will evaluate the passed string as the body of an `async` function. +If you want to run arbitrary JavaScript from CLI, you can use `App.eval` +which will evaluate the passed string as the body of an `async` function. ```ts App.start({ main() {}, - requestHandler(js: string, res) { + requestHandler(js, res) { App.eval(js).then(res).catch(res) }, }) @@ -81,23 +82,23 @@ App.start({ If the string does not contain a semicolon, a single expression is assumed and returned implicity. ```sh -ags -m "'hello'" +astal "'hello'" # hello ``` If the string contains a semicolon, you have to return explicitly ```sh -ags -m "'hello';" +astal "'hello';" # undefined -ags -m "return 'hello';" +astal "return 'hello';" # hello ``` ## Toggling Windows by their name -In order for AGS to know about your windows, you have to register them. +In order for Astal to know about your windows, you have to register them. You can do this by specifying a **unique** `name` and calling `App.add_window` ```tsx {4} @@ -127,18 +128,24 @@ When assigning the `application` prop make sure `name` comes before. Props are set sequentially and if name is applied after application it won't work. ::: -```sh +:::code-group + +```sh [astal] +astal -t Bar +``` + +```sh [ags] ags -t Bar ``` -## App without AGS +::: + +## Bundled scripts -As mentioned before AGS is only a scaffolding tool. You can setup -a dev environment and a bundler yourself. In which case you won't be using -the ags cli to run the bundled scripts. The produced script can run as the main instance +The produced scripts when bundling can run as the main instance and a "client" instance. -The first time you run your bundled script the `main` function gets executed. +The first time you execute your bundled script the `main` function gets called. While that instance is running any subsequent execution of the script will call the `client` function. diff --git a/docs/guide/ags/faq.md b/docs/guide/typescript/faq.md index cb5d609..48c802c 100644 --- a/docs/guide/ags/faq.md +++ b/docs/guide/typescript/faq.md @@ -2,22 +2,22 @@ ## Monitor id does not match compositor -The monitor property that windows expect is mapped by Gdk, which is not always +The monitor id property that windows expect is mapped by Gdk, which is not always the same as the compositor. Instead use the `gdkmonitor` property which expects -a `Gdk.Monitor` object which you can get from compositor libraries. - -Example with Hyprland +a `Gdk.Monitor` object. ```tsx -import Hyprland from "gi://AstalHyprland" +import { App } from "astal" function Bar(gdkmonitor) { return <window gdkmonitor={gdkmonitor} /> } function main() { - for (const m of Hyprland.get_default().get_monitors()) { - Bar(m.gdk_monitor) + for (const monitor of App.get_monitors()) { + if (monitor.model == "your-desired-model") { + Bar(monitor) + } } } @@ -53,7 +53,7 @@ import GLib from "gi://GLib" const HOME = GLib.getenv("HOME") ``` -## Custom svg symbolic icons +## Custom SVG symbolic icons Put the svgs in a directory, named `<icon-name>-symbolic.svg` and use `App.add_icons` or `icons` parameter in `App.start` @@ -90,74 +90,6 @@ print("print this line to stdout") printerr("print this line to stderr") ``` -## Binding custom structures - -The `bind` function can take two types of objects. - -```ts -interface Subscribable<T = unknown> { - subscribe(callback: (value: T) => void): () => void - get(): T -} - -interface Connectable { - connect(signal: string, callback: (...args: any[]) => unknown): number - disconnect(id: number): void -} -``` - -`Connectable` is for mostly gobjects, while `Subscribable` is for `Variables` -and custom objects. - -For example you can compose `Variables` in using a class. - -```ts -type MyVariableValue = { - number: number - string: string -} - -class MyVariable { - number = Variable(0) - string = Variable("") - - get(): MyVariableValue { - return { - number: this.number.get(), - string: this.string.get(), - } - } - - subscribe(callback: (v: MyVariableValue) => void) { - const unsub1 = this.number.subscribe((value) => { - callback({ string: value, number: this.number.get() }) - }) - - const unsub2 = this.string.subscribe((value) => { - callback({ number: value, string: this.string.get() }) - }) - - return () => { - unsub1() - unsub2() - } - } -} -``` - -Then it can be used with `bind`. - -```tsx -function MyWidget() { - const myvar = new MyVariable() - const label = bind(myvar).as(({ string, number }) => { - return `${string} ${number}` - }) - - return <label label={label} /> -} -``` - ## Populate the global scope with frequently accessed variables It might be annoying to always import Gtk only for `Gtk.Align` enums. @@ -272,7 +204,7 @@ notifd.get_notifications() // ✅ ## How to create regular floating windows -Use `Gtk.Window` with [Widget.astalify](/guide/ags/widget#how-to-use-non-builtin-gtk-widgets). +Use `Gtk.Window` with [Widget.astalify](/guide/typescript/widget#how-to-use-non-builtin-gtk-widgets). By default `Gtk.Window` is destroyed on close. To prevent this add a handler for `delete-event`. @@ -289,91 +221,46 @@ return <RegularWindow </RegularWindow> ``` -## Avoiding unnecessary re-rendering - -As mentioned before, any object can be bound that implements the `Subscribable` interface. - -```ts -interface Subscribable<T = unknown> { - subscribe(callback: (value: T) => void): () => void - get(): T -} -``` - -This can be used to our advantage to create a reactive `Map` object. - -```ts -import { type Subscribable } from "astal/binding" -import { Gtk } from "astal" - -export class VarMap<K, T = Gtk.Widget> implements Subscribable { - #subs = new Set<(v: Array<[K, T]>) => void>() - #map: Map<K, T> - - #notifiy() { - const value = this.get() - for (const sub of this.#subs) { - sub(value) - } - } - - #delete(key: K) { - const v = this.#map.get(key) - - if (v instanceof Gtk.Widget) { - v.destroy() - } - - this.#map.delete(key) - } +## Is there a way to limit the width/height of a widget? - constructor(initial?: Iterable<[K, T]>) { - this.#map = new Map(initial) - } +Unfortunately not. You can set a minimum size with `min-width` and `min-heigth` css attributes, +but you can not set max size. - add(key: K, value: T) { - this.#delete(key) - this.#map.set(key, value) - this.#notifiy() - } +## Custom widgets with bindable properties - delete(key: K) { - this.#delete(key) - this.#notifiy() - } +In function components you can wrap any primitive to handle both +binding and value cases as one. - get() { - return [...this.#map.entries()] +```tsx +function MyWidget(props: { prop: string | Binding<string> }) { + const prop = props.prop instanceof Binding + ? props.prop + : bind({ get: () => props.prop, subscribe: () => () => {} }) + + function setup(self: Widget.Box) { + self.hook(prop, () => { + const value = prop.get() + // handler + }) } - subscribe(callback: (v: Array<[K, T]>) => void) { - this.#subs.add(callback) - return () => this.#subs.delete(callback) - } + return <box setup={setup}> + </box> } ``` -And this `VarMap<key, Widget>` can be used as an alternative to `Variable<Array<Widget>>`. +You can pass the prop the super constructor in subclasses ```tsx -function MappedBox() { - const map = new VarMap([ - [1, <MyWidget id={id} />] - [2, <MyWidget id={id} />] - ]) - - const conns = [ - gobject.connect("added", (_, id) => map.set(id, MyWidget({ id }))), - gobject.connect("removed", (_, id) => map.delete(id, MyWidget({ id }))), - ] - - return <box onDestroy={() => conns.map(id => gobject.disconnect(id))}> - {bind(map).as(arr => arr.sort(([a], [b]) => a - b).map(([,w]) => w))} - </box> +@register() +class MyWidget extends Widget.Box { + @property(String) + set prop(v: string) { + // handler + } + + constructor(props: { prop: string | Binding<string> }) { + super(props) + } } ``` - -## Is there a way to limit the width/height of a widget? - -Unfortunately not. You can set a minimum size with `min-width` and `min-heigth` css attributes, -but you can not set max size. diff --git a/docs/guide/ags/first-widgets.md b/docs/guide/typescript/first-widgets.md index c4c4436..a7372a8 100644 --- a/docs/guide/ags/first-widgets.md +++ b/docs/guide/typescript/first-widgets.md @@ -1,15 +1,5 @@ # First Widgets -AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported -JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal projects in TypeScript. -While what made AGS what it is, is now part of the Astal project, for simplicity we will -refer to the Astal TypeScript lib as AGS. - -:::tip -If you are not familiar with the JavaScript syntax [MDN](https://developer.mozilla.org/en-US/) -and [javascript.info](https://javascript.info/) have great references. -::: - ## Getting Started Start by initializing a project @@ -24,19 +14,35 @@ then run `ags` in the terminal ags ``` -Done! You have now a custom written bar using Gtk. +:::details Usage without AGS +🚧 Not yet documented. 🚧 +::: + +That's it! You have now a custom written bar using Gtk. :::tip -AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular javascript then -it will bundle everything into a single javascript file which then GJS can execute. -The bundler used is [esbuild](https://esbuild.github.io/). +AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular JavaScript, then +it will bundle everything into a single JavaScript file which then GJS can execute. ::: +The AGS init command will generate the following files + +```txt +. +├── @girs/ # generated types +├── widget/ +│ └── Bar.tsx +├── app.ts # entry proint +├── env.d.ts # additional types +├── style.css +└── tsconfig.json # needed by LSPs +``` + ## Root of every shell component: Window Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. A widget can be as small as a button or an entire bar. -The top level widget is always a [Window](https://aylur.github.io/libastal/class.Window.html) which will hold all widgets. +The top level widget is always a [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which will hold all widgets. ::: code-group @@ -75,19 +81,19 @@ either by using JSX or using a widget constructor. ```tsx [MyButton.tsx] function MyButton(): JSX.Element { return <button onClicked="echo hello"> - Clicke Me! + <label label="Click me!" /> </button> } ``` ```ts [MyButton.ts] -import { Widget } from "astal" +import { Widget } from "astal/gtk3" function MyButton(): Widget.Button { - return Widget.Button({ - onClicked: "echo hello", - label: "Click Me!", - }) + return new Widget.Button( + { onClicked: "echo hello" }, + new Widget.Label({ label: "Click me!" }), + ) } ``` @@ -96,7 +102,7 @@ function MyButton(): Widget.Button { :::info The only difference between the two is the return type. Using markup the return type is always `Gtk.Widget` (globally available as `JSX.Element`), -while using constructors the return type is the type of the widget. +while using constructors the return type is the actual type of the widget. It is rare to need the actual return type, so most if not all of the time, you can use markup. ::: @@ -261,13 +267,12 @@ return <MyWidget myprop="hello"> ## State management -The state of widgets are handled with Bindings. A `Binding` lets you -connect the state of one [GObject](https://docs.gtk.org/gobject/class.Object.html) to another, in our case it is used to -rerender part of a widget based on the state of a `GObject`. -A `GObject` can be a [Variable](./variable) or it can be from a [Library](../libraries/references). +The state of widgets are handled with Bindings. A [Binding](./binding) lets you +connect the state of an [object](./binding#subscribable-and-connectable-interface) +to a widget so it re-renders when that state changes. -We use the `bind` function to create a `Binding` object from a `Variable` or -a regular GObject and one of its properties. +Use the `bind` function to create a `Binding` object from a `Variable` or +a regular `GObject` and one of its properties. Here is an example of a Counter widget that uses a `Variable` as its state: @@ -349,26 +354,32 @@ return <box> <box> ``` -:::warning -Only bind children of the `box` or the `stack` widget. Gtk does not cleanup widgets by default, -they have to be explicitly destroyed. The box widget is a special container that -will implicitly call `.destroy()` on its removed child widgets. -You can disable this behavior by setting the `noImplicityDestroy` property. +:::tip +Binding children of widgets will implicitly call `.destroy()` on widgets +that would be left without a parent. You can opt out of this behavior +by setting `noImplicityDestroy` property on the container widget. ::: :::info -The above example destroys and recreates every widget in the list everytime +The above example destroys and recreates every widget in the list **every time** the value of the `Variable` changes. There might be cases where you would -want to [handle child creation and deletion](/guide/ags/faq#avoiding-unnecessary-re-rendering) +want to [handle child creation and deletion](/guide/typescript/faq#avoiding-unnecessary-re-rendering) yourself, because you don't want to lose the -inner state of widgets that does not need to be recreated. +inner state of widgets that does not need to be recreated. In this case +you can create a [custom reactive structure](./binding#example-custom-subscribable) ::: When there is at least one `Binding` passed as a child, the `children` -parameter will always be a flattened `Binding<Array<JSX.Element>>` +parameter will always be a flattened `Binding<Array<JSX.Element>>`. +When there is a single `Binding` passed as a child, the `child` parameter will +be a `Binding<JSX.Element>` or a flattened `Binding<Array<JSX.Element>>`. ```tsx -function MyContainer({ children }) { +import { type Binding } from "astal" + +function MyContainer({ children }: { + children?: Binding<Array<JSX.Element>> +}) { // children is a Binding over an Array of widgets } diff --git a/docs/guide/typescript/gobject.md b/docs/guide/typescript/gobject.md new file mode 100644 index 0000000..f7f001d --- /dev/null +++ b/docs/guide/typescript/gobject.md @@ -0,0 +1,165 @@ +# Subclassing GObject.Object + +Astal provides decorator functions that make it easy to subclass gobjects. + +## Example Usage + +```ts +import GObject, { register, property } from "astal/gobject" + +@register() +class MyObj extends GObject.Object { + @property(String) + declare myProp: string + + @signal(String, Number) + declare mySignal: (a: string, b: number) => void +} +``` + +## Property decorator + +```ts +type PropertyDeclaration = + | GObject.ParamSpec + | { $gtype: GObject.GType } + +function property(declaration: PropertyDeclaration) +``` + +The `property` decorator can take any class that has a registered GType. +This includes the globally available `String`, `Number`, `Boolean` and `Object` +javascript constructors. They are mapped to their relative `GObject.ParamSpec`. + +The property decorator can be applied in the following ways: + +1. On a property declaration + +```ts {3,4} +@register() +class MyObj extends GObject.Object { + @property(String) + declare myProp: string +} +``` + +This will create a getter and setter for the property and will also +emit the notify signal when the value is set to a new value. + +:::info +The `declare` keyword is required so that the property declaration +is not transpiled into JavaScript, otherwise the initial value of the +property would be `undefined`. +::: + +:::warning +The value is checked by reference, this is important if your +property is an object type. + +```ts +const dict = obj.prop +dict["key"] = 0 +obj.prop = dict // This will not emit notify::prop // [!code error] +obj.prop = { ...dict } // This will emit notify::prop +``` + +::: + +If you want to set a custom default value, do so in the constructor of your class. + +```ts {7} +@register() +class MyObj extends GObject.Object { + @property(String) + declare myProp: string + + constructor() { + super({ myProp: "default-value" }) + } +} +``` + +2. On a getter + +```ts {3,4} +@register() +class MyObj extends GObject.Object { + @property(String) + get myProp () { + return "value" + } +} +``` + +This will create a read-only property. + +3. On a getter and setter + +```ts {5,6,10} +@register() +class MyObj extends GObject.Object { + declare private _prop: string + + @property(String) + get myProp () { + return "value" + } + + set myProp (v: string) { + if (v !== this._prop) { + this._prop = v + this.notify("my-prop") + } + } +} +``` + +This will create a read-write property. + +:::info +When defining getter/setters for the property, notify signal emission has to be done explicitly. +::: + +## Signal decorator + +```ts +function signal(...params: Array<{ $gtype: GObject.GType }) + +function signal(declaration?: SignalDeclaration) // Object you would pass to GObject.registerClass +``` + +You can apply the signal decorator to either a property declaration or a method. + +```ts {3,4,6,7} +@register() +class MyObj extends GObject.Object { + @signal(String, String) + declare mySig: (a: String, b: String) => void + + @signal(String, String) + mySig(a: string, b: string) { + // default signal handler + } +} +``` + +You can emit the signal by calling the signal method or using `emit`. + +```ts +const obj = new MyObj() +obj.connect("my-sig", (obj, a: string, b: string) => {}) + +obj.mySig("a", "b") +obj.emit("my-sig", "a", "b") +``` + +## Register decorator + +Every GObject subclass has to be registered. You can pass the same options +to this decorator as you would to `GObject.registerClass` + +```ts +@register({ GTypeName: "MyObj" }) +class MyObj extends GObject.Object { +} +``` diff --git a/docs/guide/typescript/installation.md b/docs/guide/typescript/installation.md new file mode 100644 index 0000000..f1d20c5 --- /dev/null +++ b/docs/guide/typescript/installation.md @@ -0,0 +1,90 @@ +# Installation + +It is recommended to use [AGS](https://github.com/aylur/ags) +to scaffold and run projects in TypeScript. + +It lets you + +- generate TypeScript types using [ts-for-gir](https://github.com/gjsify/ts-for-gir) +- generate a tsconfig which is used by LSPs +- bundle your TypeScript and JavaScript code using [esbuild](https://esbuild.github.io/). + +:::details Trivia +AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported +JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal+TypeScript+JSX projects. +::: + +## Nix + +maintainer: [@Aylur](https://github.com/Aylur) + +Read more about it on the [nix page](../getting-started/nix#ags) + +You can try without installing. + +<!--TODO: remove v2 after merge--> +```sh +nix run github:aylur/ags/v2#agsFull -- --help +``` + +## From source + +1. [Install Astal](../getting-started/installation.md) if you have not already + +2. Install the Astal GJS package + +```sh +git clone https://github.com/aylur/astal /tmp/astal +cd /tmp/astal/lang/gjs +meson setup --prefix /usr build +meson install -C build +``` + +:::tip +You might be wondering why it is recommended to install a JavaScript +package on the system instead of installing it as a node module. +It is solely to keep it in **sync** with the core `astal-io` and `astal3`/`astal4` package. +::: + +3. Install the following dependencies + +:::code-group + +```sh [<i class="devicon-archlinux-plain"></i> Arch] +sudo pacman -Syu go npm gjs +``` + +```sh [<i class="devicon-fedora-plain"></i> Fedora] +sudo dnf install golang npm gjs +``` + +```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] +sudo apt install golang-go npm gjs +``` + +::: + +3. Clone the repo and Install + +<!--TODO: remove v2 after merge--> +```sh +git clone https://github.com/aylur/ags.git /tmp/ags +cd /tmp/ags +git checkout v2 # https://github.com/Aylur/ags/pull/504 +cd src +go install +``` + +:::tip +`go install` installs the `ags` binary to `$GOPATH/bin` so make sure its in your `$PATH`. +You can move it to another directory if you like. For example + +```sh +sudo mv $GOPATH/bin/ags /usr/bin/ags +``` + +::: + +## Without AGS + +🚧 Setting up a dev environment without AGS is not yet documented. 🚧 diff --git a/docs/guide/ags/theming.md b/docs/guide/typescript/theming.md index cb0ebff..10a3981 100644 --- a/docs/guide/ags/theming.md +++ b/docs/guide/typescript/theming.md @@ -23,7 +23,9 @@ You can pass a path to a file or css as a string in `App.start` :::code-group ```ts [app.ts] -const inlineCss = ` +import style from "inline:./style.css" + +const inlineCssInCode = ` window { background-color: transparent; } @@ -31,6 +33,7 @@ window { App.start({ css: "./style.css", + css: style, css: `${SRC}/style.css'`, css: inlineCss, }) @@ -39,8 +42,9 @@ App.start({ ::: :::info -The global `SRC` will point to the directory `app.ts` is in. +When using AGS the global `SRC` will point to the directory `app.ts` is in. AGS will set the current working directory to `--config`, so `./style.css` also works. +If you are not using AGS you should inline import CSS instead. ::: ## Css Property on Widgets @@ -86,11 +90,20 @@ You can reset stylesheets with `App.resetCss` If you are not sure about the widget hierarchy or any CSS selector, you can use the [GTK inspector](https://wiki.gnome.org/Projects/GTK/Inspector) -```sh +::: code-group + +```sh [astal] +# to bring up the inspector run +astal --inspector +``` + +```sh [ags] # to bring up the inspector run ags --inspector ``` +::: + ## Using SCSS Gtk's CSS only supports a subset of what the web offers. @@ -128,6 +141,11 @@ App.start({ ::: +:::details Without AGS +AGS uses a plugin to transpile scss files before importing them. +If you are not using AGS, you can use a plugin for your chosen bundler. +::: + :::tip If you for example want to set scss varibles from JS, You can inline import, compose, and transpile yourself. diff --git a/docs/guide/ags/utilities.md b/docs/guide/typescript/utilities.md index 42589d3..361c33b 100644 --- a/docs/guide/ags/utilities.md +++ b/docs/guide/typescript/utilities.md @@ -2,16 +2,10 @@ ## File functions -Import them from `astal` or `astal/file` +Import from `astal` or `astal/file` ```ts -import { - readFile, - readFileAsync, - writeFile, - writeFileAsync, - monitorFile, -} from "astal" +import { readFile, readFileAsync, writeFile, writeFileAsync, monitorFile, } from "astal/file" ``` ### Reading files @@ -30,6 +24,8 @@ function writeFileAsync(path: string, content: string): Promise<void> ### Monitoring files +If `path` is a directory it will be recursively monitored. + ```ts function monitorFile( path: string, @@ -39,25 +35,25 @@ function monitorFile( ## Timeouts and Intervals -Import them from `astal` or `astal/time` +Import from `astal` or `astal/time` ```ts -import { interval, timeout, idle } from "astal" +import { interval, timeout, idle } from "astal/time" ``` You can use javascript native `setTimeout` or `setInterval` they return a [GLib.Source](https://docs.gtk.org/glib/struct.Source.html) instance. Alternatively you can use these functions provided by Astal, -which return an [Astal.Time](https://aylur.github.io/libastal/class.Time.html) instance. +which return an [AstalIO.Time](https://aylur.github.io/libastal/io/class.Time.html) instance. -`Astal.Time` has a `now` signal and a `cancelled` signal. +`AstalIO.Time` has a `now` signal and a `cancelled` signal. ### Interval Will immediately execute the function and every `interval` millisecond. ```ts -function interval(interval: number, callback?: () => void): Astal.Time +function interval(interval: number, callback?: () => void): AstalIO.Time ``` ### Timeout @@ -65,7 +61,7 @@ function interval(interval: number, callback?: () => void): Astal.Time Will execute the `callback` after `timeout` millisecond. ```ts -function timeout(timeout: number, callback?: () => void): Astal.Time +function timeout(timeout: number, callback?: () => void): AstalIO.Time ``` ### Idle @@ -73,7 +69,7 @@ function timeout(timeout: number, callback?: () => void): Astal.Time Executes `callback` whenever there are no higher priority events pending. ```ts -function idle(callback?: () => void): Astal.Time +function idle(callback?: () => void): AstalIO.Time ``` Example: @@ -96,29 +92,29 @@ timer.cancel() ## Process functions -Import them from `astal` or `astal/proc` +Import from `astal` or `astal/process` ```ts -import { subprocess, exec, execAsync } from "astal" +import { subprocess, exec, execAsync } from "astal/process" ``` ### Subprocess You can start a subprocess and run callback functions whenever it outputs to -stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/class.Process.html) has a `stdout` and `stderr` signal. +stdout or stderr. [AstalIO.Process](https://aylur.github.io/libastal/io/class.Process.html) has a `stdout` and `stderr` signal. ```ts function subprocess(args: { cmd: string | string[] out?: (stdout: string) => void err?: (stderr: string) => void -}): Astal.Process +}): AstalIO.Process function subprocess( cmd: string | string[], onOut?: (stdout: string) => void, onErr?: (stderr: string) => void, -): Astal.Process +): AstalIO.Process ``` Example: @@ -132,8 +128,8 @@ const proc = subprocess( // or with signals const proc = subprocess("some-command") -proc.connect("stdout", (out) => console.log(out)) -proc.connect("stderr", (err) => console.error(err)) +proc.connect("stdout", (_, out) => console.log(out)) +proc.connect("stderr", (_, err) => console.error(err)) ``` ### Executing external commands and scripts @@ -161,7 +157,7 @@ execAsync(["bash", "-c", "/path/to/script.sh"]) :::warning `subprocess`, `exec`, and `execAsync` executes the passed executable as is. They are **not** executed in a shell environment, -they do **not** expand env variables like `$HOME`, +they do **not** expand ENV variables like `$HOME`, and they do **not** handle logical operators like `&&` and `||`. If you want bash, run them with bash. diff --git a/docs/guide/ags/variable.md b/docs/guide/typescript/variable.md index 96e8d38..e6f3434 100644 --- a/docs/guide/ags/variable.md +++ b/docs/guide/typescript/variable.md @@ -4,17 +4,17 @@ import { Variable } from "astal" ``` -Variable is just a simple `GObject` that holds a value. -And has shortcuts for hooking up subprocesses. +Variable is just a simple object which holds a single value. +It also has some shortcuts for hooking up subprocesses, intervals and other gobjects. :::info -The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/class.Variable.html). +The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/io/class.Variable.html). ::: -## Variable as state +## Example Usage ```typescript -const myvar = Variable<string>("initial-value") +const myvar = Variable("initial-value") // whenever its value changes, callback will be executed myvar.subscribe((value: string) => { @@ -35,43 +35,49 @@ Widget.Label({ ``` :::warning -Make sure to make the transform functions pure. The `.get()` function can be called -anytime by `astal` especially when `deriving`, so make sure there are no sideeffects. +Make sure to the transform functions you pass to `:as()` are pure. +The `.get()` function can be called anytime by `astal` especially when `deriving`, +so make sure there are no sideeffects. ::: -## Composing variables +## Variable Composition -Using `Variable.derive` we can compose both Variables and Bindings. +Using `Variable.derive` any `Subscribable` object can be composed. ```typescript -const v1: Variable<number> = Variable(2) -const v2: Variable<number> = Variable(3) +const v1: Variable<number> = Variable(1) +const v2: Binding<number> = bind(obj, "prop") +const v3: Subscribable<number> = { + get: () => 3, + subscribe: () => () => {}, +} // first argument is a list of dependencies // second argument is a transform function, // where the parameters are the values of the dependencies in the order they were passed -const v3: Variable<number> = Variable.derive([v1, v2], (v1, v2) => { - return v1 * v2 -}) - -const b1: Binding<string> = bind(obj, "prop") -const b2: Binding<string> = bind(obj, "prop") - -const b3: Variable<string> = Variable.derive([b1, b2], (b1, b2) => { - return `${b1}-${b2}` -}) +const v4: Variable<number> = Variable.derive( + [v1, v2, v3], + (v1: number, v2: number, v3: number) => { + return v1 * v2 * v3 + } +) ``` +:::info +The types are only for demonstration purposes, you do not have to declare +the type of a Variable, they will be inferred from their initial value. +::: + ## Subprocess shorthands -Using `.poll` and `.watch` we can start subprocess and capture their -output in `Variables`. They can poll and watch at the same time, but they -can only poll/watch one subprocess. +Using `.poll` and `.watch` we can start subprocesses and capture their +output. They can poll and watch at the same time, but they +can only poll/watch once. :::warning -The command parameter is passed to [execAsync](/guide/ags/utilities#executing-external-commands-and-scripts) +The command parameter is passed to [execAsync](/guide/typescript/utilities#executing-external-commands-and-scripts) which means they are **not** executed in a shell environment, -they do **not** expand env variables like `$HOME`, +they do **not** expand ENV variables like `$HOME`, and they do **not** handle logical operators like `&&` and `||`. If you want bash, run them with bash. @@ -83,14 +89,14 @@ Variable("").poll(1000, ["bash", "-c", "command $VAR && command"]) ::: ```typescript -const myVar = Variable<number>(0) +const myVar = Variable(0) .poll(1000, "command", (out: string, prev: number) => parseInt(out)) .poll(1000, ["bash", "-c", "command"], (out, prev) => parseInt(out)) .poll(1000, (prev) => prev + 1) ``` ```typescript -const myVar = Variable<number>(0) +const myVar = Variable(0) .watch("command", (out: string, prev: number) => parseInt(out)) .watch(["bash", "-c", "command"], (out, prev) => parseInt(out)) ``` @@ -120,21 +126,27 @@ const myvar = Variable("") ## Dispose if no longer needed -This will stop the interval and force exit the subprocess and disconnect gobjects. +This will stop the interval, force exit the subprocess and disconnect gobjects. ```js myVar.drop() ``` :::warning -Don't forget to drop them when they are defined inside widgets -with either `.poll`, `.watch` or `.observe` +Don't forget to drop derived variables or variables with +either `.poll`, `.watch` or `.observe` when they are defined inside closures. ```tsx function MyWidget() { const myvar = Variable().poll() - - return <box onDestroy={() => myvar.drop()} /> + const derived = Variable.derive() + + return <box + onDestroy={() => { + myvar.drop() + derived.drop() + }} + /> } ``` diff --git a/docs/guide/ags/widget.md b/docs/guide/typescript/widget.md index 1fe755f..7ed69e3 100644 --- a/docs/guide/ags/widget.md +++ b/docs/guide/typescript/widget.md @@ -1,8 +1,10 @@ # Widget -## AGS widget properties +## Gtk3 -These are properties that Astal.js additionally adds to Gtk.Widgets +### Additional widget properties + +These are properties that Astal additionally adds to Gtk.Widgets - className: `string` - List of class CSS selectors separated by white space. - css: `string` - Inline CSS. e.g `label { color: white; }`. If no selector is specified `*` will be assumed. e.g `color: white;` will be inferred as `* { color: white; }`. @@ -11,16 +13,15 @@ These are properties that Astal.js additionally adds to Gtk.Widgets To have a full list of available properties, reference the documentation of the widget. -- [Astal widgets](https://aylur.github.io/libastal/index.html#classes) +- [Astal3 widgets](https://aylur.github.io/libastal/astal3/index.html#classes) - [Gtk widgets](https://docs.gtk.org/gtk3/#classes) -## AGS widget methods - -Additional methods that Astal.js adds to Gtk.Widget instances +### Additional widget methods -### setup +#### setup -`setup` is a convenience prop to not have predefine widgets before returning them +`setup` is a convenience prop to remove the need to predefine widgets +before returning them in cases where a reference is needed. without `setup` @@ -44,19 +45,21 @@ function MyWidget() { } ``` -### hook +#### hook -Shorthand for connection and disconnecting to gobjects. +Shorthand for connection and disconnecting to [Subscribable and Connectable](./binding#subscribable-and-connectable-interface) objects. without `hook` ```tsx function MyWidget() { const id = gobject.connect("signal", callback) + const unsub = variable.subscribe(callback) return <box onDestroy={() => { gobject.disconnect(id) + unsub() }} /> } @@ -69,12 +72,13 @@ function MyWidget() { return <box setup={(self) => { self.hook(gobject, "signal", callback) + self.hook(variable, callback) }} /> } ``` -### toggleClassName +#### toggleClassName Toggle classNames based on a condition @@ -88,35 +92,38 @@ function MyWidget() { } ``` -## How to use non builtin Gtk widgets +### How to use non builtin Gtk widgets -Using `Widget.astalify` you can setup widget constructors to behave like builtin widgets. -The `astalify` function will apply the following: +Using the `Widget.astalify` mixin you can subclass widgets +to behave like builtin widgets. +The `astalify` mixin will apply the following: - set `visible` to true by default (Gtk3 widgets are invisible by default) - make gobject properties accept and consume `Binding` objects - add properties and methods listed above -- proxify the constructor so the `new` keyword is not needed - sets up signal handlers that are passed as props prefixed with `on` ```tsx -import { Widget, Gtk } from "astal" - -// define its props, constructor and type -export type ColorButtonProps = Widget.ConstructProps< - Gtk.ColorButton, - Gtk.ColorButton.ConstructorProps, - { onColorSet: [] } -> -export const ColorButton = Widget.astalify< - typeof Gtk.ColorButton, - ColorButtonProps, - "ColorButton" ->(Gtk.ColorButton) -export type ColorButton = ReturnType<typeof ColorButton> +import GObject from "gi://GObject" +import { Gtk, Gdk, Widget, astalify, type ConstructProps } from "astal/gtk3" + +// subclass, register, define constructor props +class ColorButton extends astalify(Gtk.ColorButton) { + static { GObject.registerClass(this) } + + constructor(props: ConstructProps< + ColorButton, + Gtk.ColorButton.ConstructorProps, + { onColorSet: [] } // signals of Gtk.ColorButton have to be manually typed + >) { + super(props as any) + } +} function MyWidget() { - function setup(button: ColorButton) {} + function setup(button: ColorButton) { + + } return <ColorButton setup={setup} @@ -140,36 +147,14 @@ You can reference [Gtk3](https://gjs-docs.gnome.org/gtk30~3.0/) and [Astal](https://aylur.github.io/libastal/index.html#classes) for available signals. ::: -:::tip - -As stated before children are passed as either `child` or `children` property, -when passing a container widget with `Widget.astalify` these rules still apply. -While subclasses of `Gtk.Bin` *can* take a `child` property in gjs, you might notice -a warning that it is deprecated. You can workaround this with a simple wrapper function. - -```tsx -const GtkFrame = Widget.astalify< - typeof Gtk.Frame, - FrameProps, - "Frame" ->(Gtk.Frame) - -export function Frame({ child, ...props }: FrameProps) { - const frame = GtkFrame(props) - frame.add(child) // use the widget's child adding function - return frame -} -``` - -::: - -## TypeScript +### TypeScript Type of widgets are available through `Widget`. Here is an example Widget that takes in and handles a possibly `Binding` prop. ```tsx -import { Binding, Variable, Widget } from "astal" +import { Binding, Variable } from "astal" +import { Widget } from "astal/gtk3" export interface ToggleButtonProps extends Widget.ButtonProps { onToggled?: (self: Widget.Button, on: boolean) => void @@ -202,26 +187,30 @@ export default function ToggleButton(btnprops: ToggleButtonProps) { } ``` -## Builtin Widgets +### Builtin Widgets -You can check the [source code](https://github.com/aylur/astal/blob/main/core/gjs/src/widgets.ts) to have a full list of builtin widgets. +You can check the [source code](https://github.com/aylur/astal/blob/main/lang/gjs/src/gtk3/index.ts) to have a full list of builtin widgets. These widgets are available by default in JSX. -- box: [Astal.Box](https://aylur.github.io/libastal/class.Box.html) -- button: [Astal.Button](https://aylur.github.io/libastal/class.Button.html) -- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/class.CenterBox.html) -- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/class.CircularProgress.html) +- box: [Astal.Box](https://aylur.github.io/libastal/astal3/class.Box.html) +- button: [Astal.Button](https://aylur.github.io/libastal/astal3/class.Button.html) +- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/astal3/class.CenterBox.html) +- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/astal3/class.CircularProgress.html) - drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html) - entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html) -- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/class.EventBox.html) -- icon: [Astal.Icon](https://aylur.github.io/libastal/class.Icon.html) -- label: [Astal.Label](https://aylur.github.io/libastal/class.Label.html) -- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/class.LevelBar.html) -- overlay: [Astal.Overlay](https://aylur.github.io/libastal/class.Overlay.html) +- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/astal3/class.EventBox.html) +- icon: [Astal.Icon](https://aylur.github.io/libastal/astal3/class.Icon.html) +- label: [Astal.Label](https://aylur.github.io/libastal/astal3/class.Label.html) +- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/astal3/class.LevelBar.html) +- overlay: [Astal.Overlay](https://aylur.github.io/libastal/astal3/class.Overlay.html) - revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html) -- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/class.Scrollable.html) -- slider: [Astal.Slider](https://aylur.github.io/libastal/class.Slider.html) -- stack: [Astal.Stack](https://aylur.github.io/libastal/class.Stack.html) +- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/astal3/class.Scrollable.html) +- slider: [Astal.Slider](https://aylur.github.io/libastal/astal3/class.Slider.html) +- stack: [Astal.Stack](https://aylur.github.io/libastal/astal3/class.Stack.html) - switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html) -- window: [Astal.Window](https://aylur.github.io/libastal/class.Window.html) +- window: [Astal.Window](https://aylur.github.io/libastal/astal3/class.Window.html) + +## Gtk4 + +🚧 Work in Progress 🚧 diff --git a/docs/index.md b/docs/index.md index f22ae19..8f5287b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,7 @@ pageClass: home-page hero: name: "Astal" text: "Create Beautiful Widgets With Ease" - tagline: "The Framework to Craft Desktop Shells and <i>beautiful</i> <i>functional</i> Wayland Widgets with GTK!" + tagline: "The Linux Suite and Framework to Craft Desktop Shells and <i>beautiful</i> <i>functional</i> Wayland Widgets with GTK!" image: /icon.svg actions: - theme: brand @@ -21,10 +21,10 @@ hero: features: - title: Use Your Preferred Language icon: <i style="color:var(--vp-c-brand-3)" class="devicon-typescript-plain"></i> - details: The main focus of Astal is TypeScript using JSX. But you can use the libraries in any language that supports <a href="https://en.wikipedia.org/wiki/List_of_language_bindings_for_GTK">Gobject Introspection</a>. + details: The main focus of Astal is TypeScript+JSX. But you can use the libraries in any language that supports <a href="https://en.wikipedia.org/wiki/List_of_language_bindings_for_GTK">Gobject Introspection</a>. - title: No bash scripts needed icon: <i style="color:var(--vp-c-brand-3)" class="devicon-bash-plain"></i> - details: Includes modules to work with Network, Bluetooth, Battery, Audio and more. + details: Includes modules to work with Network, Bluetooth, Battery, Audio and <a href="/astal/guide/libraries/references#astal-libraries">more</a>. - title: Use any Gtk widget icon: <i style="color:var(--vp-c-brand-3)" class="fl-gtk"></i> details: With Astal you work with Gtk directly. You are not limited to only a set of them. @@ -56,6 +56,7 @@ features: .VPFeature a { font-weight: bold; + color: var(--vp-c-brand-2); } .VPFooter { diff --git a/docs/package-lock.json b/docs/package-lock.json index 30daaa4..1f821b0 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -10,6 +10,11 @@ "font-logos": "^1.2.0" }, "devDependencies": { + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "eslint-plugin-vue": "^9.28.0", + "typescript": "^5.6.3", + "typescript-eslint": "^8.8.1", "vitepress": "^1.3.4", "vitepress-plugin-auto-sidebar": "^1.2.0", "vue": "^3.4.38" @@ -456,61 +461,10 @@ } } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { + "node_modules/@esbuild/linux-x64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -518,333 +472,266 @@ "license": "MIT", "optional": true, "os": [ - "android" + "linux" ], "engines": { "node": ">=12" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], "engines": { - "node": ">=12" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } + "license": "Python-2.0", + "peer": true }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/js": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "levn": "^0.4.1" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" + }, "engines": { - "node": ">=12" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], + "node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -854,159 +741,43 @@ "dev": true, "license": "MIT" }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz", - "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz", - "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz", - "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz", - "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz", - "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz", - "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz", - "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz", - "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==", - "cpu": [ - "arm64" - ], + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz", - "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==", - "cpu": [ - "ppc64" - ], + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 8" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz", - "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==", - "cpu": [ - "riscv64" - ], + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz", - "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.22.5", @@ -1036,48 +807,6 @@ "linux" ] }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz", - "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz", - "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz", - "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@shikijs/core": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.21.0.tgz", @@ -1144,6 +873,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.9.0.tgz", + "integrity": "sha512-OrDyFAYjBT61122MIY1a3SfEgy3YCMgt2vL4eoPmvTwDBwyQhAXurxNQznlRD/jESNfYWfID8Ej+31LljvF7Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.8.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -1161,6 +910,14 @@ "@types/unist": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", @@ -1210,6 +967,209 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", + "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/type-utils": "8.8.1", + "@typescript-eslint/utils": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.1.tgz", + "integrity": "sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", + "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz", + "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.8.1", + "@typescript-eslint/utils": "8.8.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", + "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", + "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", + "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", + "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -1563,6 +1523,47 @@ } } }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/algoliasearch": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", @@ -1630,6 +1631,23 @@ "@algolia/requester-common": "4.24.0" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1640,6 +1658,13 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/birpc": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.17.tgz", @@ -1650,6 +1675,47 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -1661,6 +1727,24 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/character-entities-html4": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", @@ -1683,6 +1767,28 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -1694,6 +1800,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/copy-anything": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", @@ -1710,6 +1824,35 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1717,6 +1860,32 @@ "dev": true, "license": "MIT" }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1799,6 +1968,196 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", + "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.12.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.29.0.tgz", + "integrity": "sha512-hamyjrBhNH6Li6R1h1VF9KHfshJlKgKEg3ARbGTn72CMNDSMhWbgC7NdkRDEh25AFW+4SDATzyNM+3gWuZii8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1813,6 +2172,42 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -1820,6 +2215,149 @@ "dev": true, "license": "MIT" }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/focus-trap": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.0.tgz", @@ -1846,19 +2384,50 @@ "js-yaml": "^3.13.1" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "peer": true, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" } }, "node_modules/hast-util-to-html": { @@ -1917,6 +2486,78 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-what": { "version": "4.1.16", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", @@ -1930,6 +2571,14 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -1944,6 +2593,88 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -1983,6 +2714,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromark-util-character": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", @@ -2077,6 +2818,49 @@ ], "license": "MIT" }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/minisearch": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.0.tgz", @@ -2091,6 +2875,13 @@ "dev": true, "license": "MIT" }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -2110,6 +2901,26 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/oniguruma-to-js": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz", @@ -2123,6 +2934,95 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", @@ -2137,6 +3037,19 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", @@ -2166,6 +3079,20 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/preact": { "version": "10.24.1", "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.1.tgz", @@ -2177,6 +3104,17 @@ "url": "https://opencollective.com/preact" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/property-information": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", @@ -2188,6 +3126,38 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/regex": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.2.tgz", @@ -2195,6 +3165,28 @@ "dev": true, "license": "MIT" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -2238,6 +3230,30 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/search-insights": { "version": "2.17.2", "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.2.tgz", @@ -2246,6 +3262,44 @@ "license": "MIT", "peer": true }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/shiki": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.21.0.tgz", @@ -2314,6 +3368,20 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/superjson": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.1.tgz", @@ -2327,6 +3395,20 @@ "node": ">=16" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", @@ -2334,6 +3416,14 @@ "dev": true, "license": "MIT" }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -2344,6 +3434,19 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -2355,6 +3458,84 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.1.tgz", + "integrity": "sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.8.1", + "@typescript-eslint/parser": "8.8.1", + "@typescript-eslint/utils": "8.8.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -2428,6 +3609,24 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -2593,6 +3792,131 @@ } } }, + "node_modules/vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/docs/package.json b/docs/package.json index 0bc5ce1..fea7e8f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -2,6 +2,11 @@ "name": "docs", "type": "module", "devDependencies": { + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "eslint-plugin-vue": "^9.28.0", + "typescript": "^5.6.3", + "typescript-eslint": "^8.8.1", "vitepress": "^1.3.4", "vitepress-plugin-auto-sidebar": "^1.2.0", "vue": "^3.4.38" @@ -10,7 +15,8 @@ "dev": "vitepress dev", "build": "vitepress build", "preview": "vitepress preview", - "vitepress": "vitepress" + "vitepress": "vitepress", + "lint": "eslint . --fix" }, "dependencies": { "devicon": "^2.16.0", diff --git a/docs/public/showcase/aylur1.png b/docs/public/showcase/aylur.png Binary files differindex 5dc5dd7..5dc5dd7 100644 --- a/docs/public/showcase/aylur1.png +++ b/docs/public/showcase/aylur.png diff --git a/docs/public/showcase/kotontrion-kompass.webp b/docs/public/showcase/kotontrion-kompass.webp Binary files differnew file mode 100644 index 0000000..f622cfd --- /dev/null +++ b/docs/public/showcase/kotontrion-kompass.webp diff --git a/docs/public/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp b/docs/public/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp Binary files differnew file mode 100644 index 0000000..94f6080 --- /dev/null +++ b/docs/public/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp diff --git a/docs/showcases/Showcase.vue b/docs/showcases/Showcase.vue index a5a1e01..d58986b 100644 --- a/docs/showcases/Showcase.vue +++ b/docs/showcases/Showcase.vue @@ -1,38 +1,149 @@ <script setup> -const props = defineProps({ - src: { type: String, required: true }, - label: { type: String, required: true }, - url: { type: String, required: true } -}); +import { VPButton } from "vitepress/theme" +defineProps({ + image: { type: String, required: true }, + url: { type: String, required: true }, + icon: { type: String, required: false, default: "" }, + title: { type: String, required: false, default: "" }, + description: { type: String, required: false, default: "" }, + author: { type: String, required: true }, +}) </script> <template> <figure> - <a :href="url"> - <img :src="src" :alt="label" /> - </a> - <figcaption> - <span>{{ label }}</span> - </figcaption> + <div class="image-wrapper"> + <img :src="image" :alt="title"> + <div class="overlay"> + <div class="text-content"> + <h3 v-if="title.length"> + {{ title }} + </h3> + <h3 v-else> + {{ author }}'s dotfiles + </h3> + <p v-if="description"> + {{ description }} + </p> + <span class="author">— {{ author }}</span> + <VPButton + tag + :href="url" + target="_blank" + size="medium" + text="View Setup" + /> + </div> + </div> + <i + v-if="icon" + :class="icon" + class="language-icon" + /> + </div> </figure> </template> <style scoped> -img { - border-radius: 4px; -} - -/* same as VPFeature */ figure { - padding: 0.8rem; - padding-bottom: 0; - border-radius: 12px; + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 1rem; + border-radius: 1rem; background-color: var(--vp-c-bg-soft); + transition: + box-shadow 0.3s ease, + transform 0.3s ease; +} + +figure:hover { + box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.2); + transform: translateY(-1rem); +} + +.image-wrapper { + position: relative; + width: 100%; + border-radius: 0.5rem; + overflow: hidden; +} + +figure img { + width: 100%; + transition: filter 0.3s ease; +} + +figure .overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: flex-start; + padding: 1rem; + opacity: 0; + transition: + opacity 0.3s ease, + backdrop-filter 0.01s ease; +} + +figure:hover .overlay { + opacity: 1; + backdrop-filter: blur(1rem); +} + +.text-content { + color: white; + text-align: left; + opacity: 0; + transform: translateX(-5rem); + transition: + transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), + opacity 0.6s ease; +} + +figure:hover .text-content { + transform: translateX(2.5rem); + opacity: 1; +} + +.text-content h3 { + margin: 0; + font-size: 2rem; +} + +.text-content p { + margin: 0.5rem 0; + font-size: 1.1rem; +} + +.text-content .author { + margin-top: 0.5rem; + text-align: left; + display: block; + position: relative; + font-style: italic; + font-size: 1rem; + color: #f0f0f0; +} + +figure .language-icon { + position: absolute; + bottom: 0.5rem; + right: 0.5rem; + padding: 0.5rem; + background: var(--vp-c-bg-soft); + border-radius: 100%; + font-size: 1rem; + z-index: 1; } -figcaption { - text-align: center; - padding-top: .4em; - padding-bottom: .6em; +.VPButton { + margin-top: 2rem; + text-decoration: none; } </style> diff --git a/docs/showcases/Showcases.vue b/docs/showcases/Showcases.vue index 86a17bf..57cf5fa 100644 --- a/docs/showcases/Showcases.vue +++ b/docs/showcases/Showcases.vue @@ -1,18 +1,36 @@ <script setup lang="ts"> -import showcases from './showcases' -import Showcase from './Showcase.vue' +import showcases from "./showcases" +import Showcase from "./Showcase.vue" </script> - <template> <div class="Showcases"> <template v-for="(showcase, index) in showcases" :key="index"> <div v-if="Array.isArray(showcase)" class="row"> - <div v-for="(elem, elemIndex) in showcase" :key="elemIndex" class="item" - :class="`grid-${showcase.length}`"> - <Showcase v-bind="elem" /> + <div + v-for="(elem, elemIndex) in showcase" + :key="elemIndex" + class="item" + :class="`grid-${showcase.length}`" + > + <Showcase + :image="elem.image" + :url="elem.url" + :icon="elem.icon" + :title="elem.title" + :description="elem.description" + :author="elem.author" + /> </div> </div> - <Showcase v-else v-bind="showcase" /> + <Showcase + v-else + :image="showcase.image" + :url="showcase.url" + :icon="showcase.icon" + :title="showcase.title" + :description="showcase.description" + :author="showcase.author" + /> </template> </div> </template> diff --git a/docs/showcases/showcases.ts b/docs/showcases/showcases.ts index 138ae7f..2aea04a 100644 --- a/docs/showcases/showcases.ts +++ b/docs/showcases/showcases.ts @@ -1,15 +1,38 @@ type Showcase = { - label: string - src: string + image: string url: string + icon?: string // https://devicon.dev/ + title?: string + description?: string + author: string } -type Grid<T> = T - | [T, T] - | [T, T, T] - | [T, T, T, T] +// TODO: support more layouts +type Grid<T> = T | [T, T] export default [ - { label: "Placeholder (this is an ags v1 screenshot)", src: "/astal/showcase/aylur1.png", url: "https://github.com/Aylur/dotfiles" }, - // add more showcases here + { + image: "/astal/showcase/aylur.png", + url: "https://github.com/Aylur/dotfiles", + icon: "devicon-typescript-plain", + description: "Placeholder (this is an ags v1 screenshot)", + author: "Aylur", + }, + { + image: "/astal/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp", + url: "https://github.com/tokyob0t/dotfiles", + icon: "devicon-lua-plain", + title: "Tokyob0t's Desktop", + description: "Abandonad toda esperanza, vosotros que entráis aquÃ.", + author: "tokyob0t", + }, + { + image: "/astal/showcase/kotontrion-kompass.webp", + url: "https://github.com/kotontrion/kompass", + icon: "devicon-vala-plain", + title: "kompass", + author: "kotontrion", + }, + + // add more showcases here~ ] satisfies Array<Grid<Showcase>> diff --git a/docs/vitepress.config.ts b/docs/vitepress.config.ts index a76388b..f542a68 100644 --- a/docs/vitepress.config.ts +++ b/docs/vitepress.config.ts @@ -20,10 +20,11 @@ export default defineConfig({ themeConfig: { logo: "/icon.svg", + outline: "deep", footer: { - message: 'Released under the LGPL v2.1 License', - copyright: 'Logo is created by VDawg' + message: "Released under the LGPL v2.1 License", + copyright: "Logo is created by VDawg", }, nav: [ @@ -43,7 +44,7 @@ export default defineConfig({ { text: "Contributing", link: github("/blob/main/CONTRIBUTING.md") }, { text: "Changelog", link: github("/blob/main/CHANGELOG.md") }, ], - } + }, ], sidebar: [ @@ -58,26 +59,47 @@ export default defineConfig({ ], }, { - text: "AGS", - base: "/guide/ags", - collapsed: false, + text: "TypeScript", + base: "/guide/typescript", + collapsed: true, items: [ { text: "Installation", link: "/installation" }, { text: "First Widgets", link: "/first-widgets" }, { text: "Theming", link: "/theming" }, { text: "CLI and App", link: "/cli-app" }, { text: "Widget", link: "/widget" }, - { text: "Utilities", link: "/utilities" }, { text: "Variable", link: "/variable" }, + { text: "Binding", link: "/binding" }, + { text: "GObject", link: "/gobject" }, + { text: "Utilities", link: "/utilities" }, { text: "FAQ", link: "/faq" }, ], }, { + text: "Lua", + base: "/guide/lua", + collapsed: true, + items: [ + { text: "Installation", link: "/installation" }, + { text: "First Widgets", link: "/first-widgets" }, + { text: "Theming", link: "/theming" }, + { text: "CLI and App", link: "/cli-app" }, + { text: "Widget", link: "/widget" }, + { text: "Variable", link: "/variable" }, + { text: "Binding", link: "/binding" }, + // { text: "GObject", link: "/gobject" }, + { text: "Utilities", link: "/utilities" }, + // { text: "FAQ", link: "/faq" }, + ], + }, + { text: "Libraries", collapsed: true, items: [ { text: "References", link: "/guide/libraries/references" }, - { text: "Astal", link: "https://aylur.github.io/libastal" }, + { text: "IO", link: "https://aylur.github.io/libastal/io" }, + { text: "Astal3", link: "https://aylur.github.io/libastal/astal3" }, + // { text: "Astal4", link: "https://aylur.github.io/libastal/astal4" }, { text: "Apps", link: "/guide/libraries/apps" }, { text: "Auth", link: "/guide/libraries/auth" }, { text: "Battery", link: "/guide/libraries/battery" }, @@ -111,6 +133,6 @@ export default defineConfig({ search: { provider: "local", - } + }, }, }) diff --git a/examples/js/.gitignore b/examples/js/.gitignore index b0d983b..261d669 100644 --- a/examples/js/.gitignore +++ b/examples/js/.gitignore @@ -1,3 +1,6 @@ @girs/ tsconfig.json env.d.ts +dist/ +package.json +package-lock.json diff --git a/examples/js/simple-bar/app.ts b/examples/js/simple-bar/app.ts index 05f043a..4b7ea48 100644 --- a/examples/js/simple-bar/app.ts +++ b/examples/js/simple-bar/app.ts @@ -1,8 +1,13 @@ -import { App } from "astal" +import { App } from "astal/gtk3" import style from "./style.scss" import Bar from "./widget/Bar" App.start({ css: style, + instanceName: "js", + requestHandler(request, res) { + print(request) + res("ok") + }, main: () => App.get_monitors().map(Bar), }) diff --git a/examples/js/simple-bar/widget/Bar.tsx b/examples/js/simple-bar/widget/Bar.tsx index 644e835..efc065a 100644 --- a/examples/js/simple-bar/widget/Bar.tsx +++ b/examples/js/simple-bar/widget/Bar.tsx @@ -1,4 +1,6 @@ -import { App, Variable, Astal, Gtk, Gdk, GLib, bind } from "astal" +import { App } from "astal/gtk3" +import { Variable, GLib, bind } from "astal" +import { Astal, Gtk, Gdk } from "astal/gtk3" import Hyprland from "gi://AstalHyprland" import Mpris from "gi://AstalMpris" import Battery from "gi://AstalBattery" diff --git a/examples/lua/simple-bar/init.lua b/examples/lua/simple-bar/init.lua index aecf7a6..8c412fb 100644 --- a/examples/lua/simple-bar/init.lua +++ b/examples/lua/simple-bar/init.lua @@ -1,5 +1,5 @@ local astal = require("astal") -local App = astal.App +local App = require("astal.gtk3.app") local Bar = require("widget.Bar") local src = require("lib").src @@ -10,7 +10,12 @@ local css = "/tmp/style.css" astal.exec("sass " .. scss .. " " .. css) App:start({ + instance_name = "lua", css = css, + request_handler = function(msg, res) + print(msg) + res("ok") + end, main = function() for _, mon in pairs(App.monitors) do Bar(mon) diff --git a/examples/lua/simple-bar/widget/Bar.lua b/examples/lua/simple-bar/widget/Bar.lua index d44db2d..bf230bb 100644 --- a/examples/lua/simple-bar/widget/Bar.lua +++ b/examples/lua/simple-bar/widget/Bar.lua @@ -1,9 +1,9 @@ local astal = require("astal") -local App = astal.App -local Widget = astal.Widget +local App = require("astal.gtk3.app") +local Widget = require("astal.gtk3.widget") local Variable = astal.Variable -local Gdk = astal.Gdk -local GLib = astal.GLib +local Gdk = astal.require("Gdk", "3.0") +local GLib = astal.require("GLib") local bind = astal.bind local Mpris = astal.require("AstalMpris") local Battery = astal.require("AstalBattery") @@ -134,6 +134,10 @@ local function Workspaces() return Widget.Box({ class_name = "Workspaces", bind(hypr, "workspaces"):as(function(wss) + table.sort(wss, function(a, b) + return a.id < b.id + end) + return map(wss, function(ws) return Widget.Button({ class_name = bind(hypr, "focused-workspace"):as(function(fw) @@ -142,7 +146,9 @@ local function Workspaces() on_clicked = function() ws:focus() end, - label = bind(ws, "id"):as(tostring), + label = bind(ws, "id"):as(function(v) + return type(v) == "number" and string.format("%.0f", v) or v + end), }) end) end), @@ -164,10 +170,12 @@ local function Time(format) end return function(gdkmonitor) + local WindowAnchor = astal.require("Astal", "3.0").WindowAnchor + return Widget.Window({ class_name = "Bar", gdkmonitor = gdkmonitor, - anchor = astal.Astal.WindowAnchor.TOP + astal.Astal.WindowAnchor.LEFT + astal.Astal.WindowAnchor.RIGHT, + anchor = WindowAnchor.TOP + WindowAnchor.LEFT + WindowAnchor.RIGHT, exclusivity = "EXCLUSIVE", Widget.CenterBox({ diff --git a/examples/py/.gitignore b/examples/py/.gitignore index b0bff8b..c18dd8d 100644 --- a/examples/py/.gitignore +++ b/examples/py/.gitignore @@ -1,3 +1 @@ -pygobject-stubs/ -*.pyi __pycache__/ diff --git a/examples/py/simple-bar/app.py b/examples/py/simple-bar/app.py index f5a8a80..17b6782 100755 --- a/examples/py/simple-bar/app.py +++ b/examples/py/simple-bar/app.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import sys import versions -from gi.repository import Astal, Gio +from gi.repository import AstalIO, Astal, Gio from widget.Bar import Bar from pathlib import Path @@ -10,23 +10,27 @@ css = "/tmp/style.css" class App(Astal.Application): - def do_request(self, msg: str, conn: Gio.SocketConnection) -> None: + def do_astal_application_request( + self, msg: str, conn: Gio.SocketConnection + ) -> None: print(msg) - Astal.write_sock(conn, "hello") + AstalIO.write_sock(conn, "hello") def do_activate(self) -> None: self.hold() - Astal.Process.execv(["sass", scss, css]) + AstalIO.Process.execv(["sass", scss, css]) self.apply_css(css, True) + print("hello") for mon in self.get_monitors(): self.add_window(Bar(mon)) -instance_name = "simple-bar" +instance_name = "python" app = App(instance_name=instance_name) if __name__ == "__main__": - if app.acquire_socket(): + try: + print(app.acquire_socket()) app.run(None) - else: - print(Astal.Application.send_message(instance_name, "".join(sys.argv[1:]))) + except Exception as e: + print(AstalIO.send_message(instance_name, "".join(sys.argv[1:]))) diff --git a/examples/py/simple-bar/versions.py b/examples/py/simple-bar/versions.py index a8a1ab8..0e57708 100644 --- a/examples/py/simple-bar/versions.py +++ b/examples/py/simple-bar/versions.py @@ -1,6 +1,7 @@ import gi -gi.require_version("Astal", "0.1") +gi.require_version("AstalIO", "0.1") +gi.require_version("Astal", "3.0") gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") gi.require_version("Gio", "2.0") diff --git a/examples/py/simple-bar/widget/Bar.py b/examples/py/simple-bar/widget/Bar.py index 89581f1..3b09dce 100644 --- a/examples/py/simple-bar/widget/Bar.py +++ b/examples/py/simple-bar/widget/Bar.py @@ -1,5 +1,6 @@ import math from gi.repository import ( + AstalIO, Astal, Gtk, Gdk, @@ -125,8 +126,8 @@ class SysTray(Gtk.Box): app.add_icons(theme) menu = item.create_menu() - btn = Astal.Button() - icon = Astal.Icon() + btn = Astal.Button(visible=True) + icon = Astal.Icon(visible=True) def on_clicked(btn): if menu: @@ -143,6 +144,7 @@ class SysTray(Gtk.Box): item.bind_property("gicon", icon, "gicon", SYNC) self.add(btn) self.items[id] = btn + self.show_all() def remove_item(self, _: Tray.Tray, id: str): if id in self.items: @@ -203,7 +205,7 @@ class Time(Astal.Label): def __init__(self, format="%H:%M - %A %e."): super().__init__() self.format = format - self.interval = Astal.Time.interval(1000, self.sync) + self.interval = AstalIO.Time.interval(1000, self.sync) self.connect("destroy", self.interval.cancel) Astal.widget_set_class_names(self, ["Time"]) diff --git a/examples/vala/simple-bar/app.in.vala b/examples/vala/simple-bar/app.in.vala index aece979..b04a1fa 100644 --- a/examples/vala/simple-bar/app.in.vala +++ b/examples/vala/simple-bar/app.in.vala @@ -3,7 +3,7 @@ class App : Astal.Application { public override void request (string msg, SocketConnection conn) { print(@"$msg\n"); - Astal.write_sock.begin(conn, "hello"); + AstalIO.write_sock.begin(conn, "ok"); } public override void activate () { @@ -14,16 +14,17 @@ class App : Astal.Application { } public static void main(string[] args) { - var instance_name = "simple-bar"; + var instance_name = "vala"; App.instance = new App() { instance_name = instance_name }; - if (App.instance.acquire_socket()) { + try { + App.instance.acquire_socket(); App.instance.run(null); - } else { - print(Astal.Application.send_message(instance_name, string.joinv(" ", args))); + } catch (Error err) { + print(AstalIO.send_message(instance_name, string.joinv(" ", args))); } } } diff --git a/examples/vala/simple-bar/flake.lock b/examples/vala/simple-bar/flake.lock deleted file mode 100644 index 06f572f..0000000 --- a/examples/vala/simple-bar/flake.lock +++ /dev/null @@ -1,62 +0,0 @@ -{ - "nodes": { - "astal": { - "inputs": { - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1727022015, - "narHash": "sha256-ka7aRbReUE6ImjQV8KabMHoojUgb3gtn1/9drMFTtBk=", - "owner": "aylur", - "repo": "astal", - "rev": "8cab7d039e2cf783033a5f1f26cf8be42b0d158e", - "type": "github" - }, - "original": { - "owner": "aylur", - "repo": "astal", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1716293225, - "narHash": "sha256-pU9ViBVE3XYb70xZx+jK6SEVphvt7xMTbm6yDIF4xPs=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "3eaeaeb6b1e08a016380c279f8846e0bd8808916", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1726937504, - "narHash": "sha256-bvGoiQBvponpZh8ClUcmJ6QnsNKw0EMrCQJARK3bI1c=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "9357f4f23713673f310988025d9dc261c20e70c6", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "astal": "astal", - "nixpkgs": "nixpkgs_2" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/examples/vala/simple-bar/flake.nix b/examples/vala/simple-bar/flake.nix index 78bfb62..d13c649 100644 --- a/examples/vala/simple-bar/flake.nix +++ b/examples/vala/simple-bar/flake.nix @@ -27,7 +27,8 @@ ]; buildInputs = [ - astal.packages.${system}.astal + astal.packages.${system}.io + astal.packages.${system}.astal3 astal.packages.${system}.battery astal.packages.${system}.wireplumber astal.packages.${system}.network diff --git a/examples/vala/simple-bar/meson.build b/examples/vala/simple-bar/meson.build index d0ef209..10f5dd2 100644 --- a/examples/vala/simple-bar/meson.build +++ b/examples/vala/simple-bar/meson.build @@ -8,7 +8,8 @@ pkgconfig_deps = [ dependency('gobject-2.0'), dependency('gtk+-3.0'), dependency('libnm'), - dependency('astal-0.1'), + dependency('astal-io-0.1'), + dependency('astal-3.0'), dependency('astal-battery-0.1'), dependency('astal-wireplumber-0.1'), dependency('astal-network-0.1'), diff --git a/examples/vala/simple-bar/widget/Bar.vala b/examples/vala/simple-bar/widget/Bar.vala index 6e99327..17db831 100644 --- a/examples/vala/simple-bar/widget/Bar.vala +++ b/examples/vala/simple-bar/widget/Bar.vala @@ -191,7 +191,7 @@ class Battery : Gtk.Box { class Time : Astal.Label { string format; - Astal.Time interval; + AstalIO.Time interval; void sync() { label = new DateTime.now_local().format(format); @@ -199,7 +199,7 @@ class Time : Astal.Label { public Time(string format = "%H:%M - %A %e.") { this.format = format; - interval = Astal.Time.interval(1000, null); + interval = AstalIO.Time.interval(1000, null); interval.now.connect(sync); destroy.connect(interval.cancel); Astal.widget_set_class_names(this, {"Time"}); @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1716293225, - "narHash": "sha256-pU9ViBVE3XYb70xZx+jK6SEVphvt7xMTbm6yDIF4xPs=", + "lastModified": 1729256560, + "narHash": "sha256-/uilDXvCIEs3C9l73JTACm4quuHUsIHcns1c+cHUJwA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "3eaeaeb6b1e08a016380c279f8846e0bd8808916", + "rev": "4c2fcb090b1f3e5b47eaa7bd33913b574a11e0a0", "type": "github" }, "original": { @@ -1,6 +1,4 @@ { - inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - outputs = { self, nixpkgs, @@ -22,11 +20,15 @@ vala wayland wayland-scanner + python3 ]; propagatedBuildInputs = [pkgs.glib] ++ inputs; pname = name; version = readVer "${src}/version"; src = src; + postUnpack = '' + cp --remove-destination ${./lib/gir.py} $sourceRoot/gir.py + ''; outputs = ["out" "dev"]; }; in { @@ -43,9 +45,10 @@ packages.${system} = with pkgs; { docs = import ./docs {inherit self pkgs;}; - default = self.packages.${system}.astal; + default = self.packages.${system}.io; - astal = mkPkg "astal" ./core [gtk3 gtk-layer-shell]; + io = mkPkg "astal" ./lib/astal/io []; + astal3 = mkPkg "astal" ./lib/astal/gtk3 [self.packages.${system}.io gtk3 gtk-layer-shell]; apps = mkPkg "astal-apps" ./lib/apps [json-glib]; auth = mkPkg "astal-auth" ./lib/auth [pam]; battery = mkPkg "astal-battery" ./lib/battery [json-glib]; @@ -59,6 +62,23 @@ river = mkPkg "astal-river" ./lib/river [json-glib]; tray = mkPkg "astal-tray" ./lib/tray [gtk3 gdk-pixbuf libdbusmenu-gtk3 json-glib]; wireplumber = mkPkg "astal-wireplumber" ./lib/wireplumber [wireplumber]; + # polkit = mkPkg "astal-polkit" ./lib/polkit [polkit]; + + gjs = pkgs.stdenvNoCC.mkDerivation { + src = ./lang/gjs; + name = "astal-gjs"; + buildInputs = [ + meson + ninja + pkg-config + self.packages.${system}.io + self.packages.${system}.astal3 + ]; + }; }; }; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + }; } diff --git a/core/gjs/.gitignore b/lang/gjs/.gitignore index 53f4bc3..53f4bc3 100644 --- a/core/gjs/.gitignore +++ b/lang/gjs/.gitignore diff --git a/core/gjs/eslint.config.mjs b/lang/gjs/eslint.config.mjs index 99dad7d..05e49ee 100644 --- a/core/gjs/eslint.config.mjs +++ b/lang/gjs/eslint.config.mjs @@ -14,5 +14,6 @@ export default tseslint.config({ ], rules: { "@typescript-eslint/no-explicit-any": "off", + "@stylistic/new-parens": "off", }, }) diff --git a/lang/gjs/index.ts b/lang/gjs/index.ts new file mode 100644 index 0000000..46e72b1 --- /dev/null +++ b/lang/gjs/index.ts @@ -0,0 +1 @@ +export * from "./src" diff --git a/lang/gjs/meson.build b/lang/gjs/meson.build new file mode 100644 index 0000000..388b301 --- /dev/null +++ b/lang/gjs/meson.build @@ -0,0 +1,22 @@ +project('astal-gjs') + +dest = get_option('prefix') / get_option('datadir') / 'astal' / 'gjs' + +dependency('astal-io-0.1') +dependency('astal-3.0') + +install_data( + [ + 'src/binding.ts', + 'src/file.ts', + 'src/gobject.ts', + 'src/index.ts', + 'src/process.ts', + 'src/time.ts', + 'src/variable.ts', + ], + install_dir: dest, +) + +install_subdir('src/gtk3', install_dir: dest) +# install_subdir('src/gtk4', install_dir: dest) diff --git a/core/gjs/package-lock.json b/lang/gjs/package-lock.json index aa679c8..4d45c8f 100644 --- a/core/gjs/package-lock.json +++ b/lang/gjs/package-lock.json @@ -12,13 +12,13 @@ "linux" ], "devDependencies": { - "@eslint/js": "^9.7.0", - "@stylistic/eslint-plugin": "latest", - "@ts-for-gir/cli": "latest", + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "@ts-for-gir/cli": "^4.0.0-beta.16", "@types/eslint__js": "^8.42.3", - "eslint": "^8.57.0", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.1" + "eslint": "^8.57.1", + "typescript": "^5.6.3", + "typescript-eslint": "^7.18.0" }, "engines": { "gjs": ">=1.79.0" @@ -29,12 +29,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" }, "engines": { @@ -42,21 +43,23 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -70,6 +73,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -82,6 +86,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -96,6 +101,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -104,13 +110,25 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -120,6 +138,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -132,6 +151,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -147,6 +167,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -155,10 +176,11 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -168,6 +190,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -191,6 +214,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -201,6 +225,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -213,6 +238,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -230,6 +256,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -238,10 +265,11 @@ } }, "node_modules/@eslint/js": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", - "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -251,6 +279,7 @@ "resolved": "https://registry.npmjs.org/@gi.ts/parser/-/parser-2.0.0.tgz", "integrity": "sha512-Tz5T+3Ep+qY7rfBnYMGdVraCCUf1CKkDfxNd2fggfHLzjI7u5Th8a/piPgj0001jDs5czI+Ec3peh+6gkKPmHw==", "dev": true, + "license": "MIT", "dependencies": { "fast-xml-parser": "^4.3.5" }, @@ -259,13 +288,14 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -278,6 +308,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -288,6 +319,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -300,6 +332,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -313,13 +346,15 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@inquirer/figures": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.4.tgz", - "integrity": "sha512-R7Gsg6elpuqdn55fBH2y9oYzrU/yKrSmIsDX4ROT51vohrECFzTf2zw9BfUbOW8xjfmM2QbVoVYdTwhrtEKWSQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.7.tgz", + "integrity": "sha512-m+Trk77mp54Zma6xLkLuY+mvanPxlE4A7yNKs2HBiyZ4UkVs28Mv5c/pgWrHeInx+USHeX/WEPzjrWrcJiQgjw==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" } @@ -329,6 +364,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -342,10 +378,11 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -358,6 +395,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -369,13 +407,15 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -393,6 +433,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -408,6 +449,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -425,6 +467,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -438,6 +481,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -447,6 +491,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -455,61 +500,16 @@ "node": ">= 8" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.3.0.tgz", - "integrity": "sha512-rtiz6u5gRyyEZp36FcF1/gHJbsbT3qAgXZ1qkad6Nr/xJ9wrSJkiSFFQhpYVTIZ7FJNRJurEcumZDCwN9dEI4g==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "2.3.0", - "@stylistic/eslint-plugin-jsx": "2.3.0", - "@stylistic/eslint-plugin-plus": "2.3.0", - "@stylistic/eslint-plugin-ts": "2.3.0", - "@types/eslint": "^8.56.10" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.3.0.tgz", - "integrity": "sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.9.0.tgz", + "integrity": "sha512-OrDyFAYjBT61122MIY1a3SfEgy3YCMgt2vL4eoPmvTwDBwyQhAXurxNQznlRD/jESNfYWfID8Ej+31LljvF7Xg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint": "^8.56.10", - "acorn": "^8.11.3", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.3.0.tgz", - "integrity": "sha512-tsQ0IEKB195H6X9A4iUSgLLLKBc8gUBWkBIU8tp1/3g2l8stu+PtMQVV/VmK1+3bem5FJCyvfcZIQ/WF1fsizA==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "^2.3.0", - "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^8.8.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", "estraverse": "^5.3.0", "picomatch": "^4.0.2" }, @@ -520,51 +520,22 @@ "eslint": ">=8.40.0" } }, - "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.3.0.tgz", - "integrity": "sha512-xboPWGUU5yaPlR+WR57GwXEuY4PSlPqA0C3IdNA/+1o2MuBi95XgDJcZiJ9N+aXsqBXAPIpFFb+WQ7QEHo4f7g==", - "dev": true, - "dependencies": { - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" - }, - "peerDependencies": { - "eslint": "*" - } - }, - "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.3.0.tgz", - "integrity": "sha512-wqOR38/uz/0XPnHX68ftp8sNMSAqnYGjovOTN7w00xnjS6Lxr3Sk7q6AaxWWqbMvOj7V2fQiMC5HWAbTruJsCg==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "2.3.0", - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, "node_modules/@ts-for-gir/cli": { - "version": "4.0.0-beta.7", - "resolved": "https://registry.npmjs.org/@ts-for-gir/cli/-/cli-4.0.0-beta.7.tgz", - "integrity": "sha512-s345hGCB2su0NIFA7A10GIY9mLiNtrbSXp9ZscKsasx6Fm77QZybO09dLcIPMuePq8gbRlOpNp8MedAqO7zWRw==", + "version": "4.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@ts-for-gir/cli/-/cli-4.0.0-beta.16.tgz", + "integrity": "sha512-E5T6NOdmrkRw3b7SyaZco5g7udMcg8kbCNnxgASLQj7VC0cxiwxLi/z7ALYjmbB1W5xhuensauq1yh5rLUWAXA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@gi.ts/parser": "^2.0.0", - "@ts-for-gir/generator-base": "^4.0.0-beta.7", - "@ts-for-gir/generator-html-doc": "^4.0.0-beta.7", - "@ts-for-gir/generator-typescript": "^4.0.0-beta.7", - "@ts-for-gir/lib": "^4.0.0-beta.7", + "@ts-for-gir/generator-base": "^4.0.0-beta.16", + "@ts-for-gir/generator-html-doc": "^4.0.0-beta.16", + "@ts-for-gir/generator-typescript": "^4.0.0-beta.16", + "@ts-for-gir/lib": "^4.0.0-beta.16", "colorette": "^2.0.20", "cosmiconfig": "^9.0.0", "glob": "^11.0.0", - "inquirer": "^9.3.5", + "inquirer": "^9.3.6", "prettier": "^3.3.3", "yargs": "^17.7.2" }, @@ -576,38 +547,41 @@ } }, "node_modules/@ts-for-gir/generator-base": { - "version": "4.0.0-beta.7", - "resolved": "https://registry.npmjs.org/@ts-for-gir/generator-base/-/generator-base-4.0.0-beta.7.tgz", - "integrity": "sha512-Z3dlwea0LvbGwcb51xjSqp33n5wvqmsX7r1EwbA4vEPuN7AgPm2LDbL68G5HO6QOmFDt05Fe0gjumfzjGE8Xlw==", + "version": "4.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@ts-for-gir/generator-base/-/generator-base-4.0.0-beta.16.tgz", + "integrity": "sha512-qNahOOm2aRC5w6gqk5xjb0MvyxtYwhTFDvHwuWXEUJ+EoFeWSi95ZYkvivvowsoAiQ5W805FMXzJtt4P72O0Hw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@ts-for-gir/lib": "^4.0.0-beta.7" + "@ts-for-gir/lib": "^4.0.0-beta.16" }, "engines": { "node": ">=18" } }, "node_modules/@ts-for-gir/generator-html-doc": { - "version": "4.0.0-beta.7", - "resolved": "https://registry.npmjs.org/@ts-for-gir/generator-html-doc/-/generator-html-doc-4.0.0-beta.7.tgz", - "integrity": "sha512-srz4nSSfcqCQUQcV4Ia5booXEy7gC54iv7Q1E80cdnM/cg0XWq4XaTfCbH27CqcY2zS+KsVUJm7PWI7LHeUeiw==", + "version": "4.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@ts-for-gir/generator-html-doc/-/generator-html-doc-4.0.0-beta.16.tgz", + "integrity": "sha512-2gCEUuSsvbUEdcAcU1LKFWawC56TYg4CmHCswzDjwPeEpOrzq1tweoaW2muYTg3COcF58Jax5/TWnJ88TmFdyA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@ts-for-gir/generator-base": "^4.0.0-beta.7", - "@ts-for-gir/lib": "^4.0.0-beta.7" + "@ts-for-gir/generator-base": "^4.0.0-beta.16", + "@ts-for-gir/lib": "^4.0.0-beta.16" }, "engines": { "node": ">=18" } }, "node_modules/@ts-for-gir/generator-typescript": { - "version": "4.0.0-beta.7", - "resolved": "https://registry.npmjs.org/@ts-for-gir/generator-typescript/-/generator-typescript-4.0.0-beta.7.tgz", - "integrity": "sha512-6WVPHVod6YINT5ZX1TSaPy8b1+A1t3TAi+1Byx/nH5aF4o1jPmn1KKorvxOIDcvlqnjux053r+rjweIR+1w9Zw==", + "version": "4.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@ts-for-gir/generator-typescript/-/generator-typescript-4.0.0-beta.16.tgz", + "integrity": "sha512-BHXqfaqH5yOXD9ckL6h8ZGn17U7SkajksS4/KuQCtAhURjpXT3xw7mKw5W3FObhvFSkiaonPkZwapRUgD8kZ6w==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@ts-for-gir/generator-base": "^4.0.0-beta.7", - "@ts-for-gir/lib": "^4.0.0-beta.7", + "@ts-for-gir/generator-base": "^4.0.0-beta.16", + "@ts-for-gir/lib": "^4.0.0-beta.16", "ejs": "^3.1.10", "xml2js": "^0.6.2" }, @@ -616,10 +590,11 @@ } }, "node_modules/@ts-for-gir/lib": { - "version": "4.0.0-beta.7", - "resolved": "https://registry.npmjs.org/@ts-for-gir/lib/-/lib-4.0.0-beta.7.tgz", - "integrity": "sha512-9hhCk3OBA0diIG5KuqSCJAy6D91hVUK2JiuLbxNfdmvAaMS+4BvYSGKg+DdXvmgoTip4LqCo4EsFTHfuo7QQHg==", + "version": "4.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@ts-for-gir/lib/-/lib-4.0.0-beta.16.tgz", + "integrity": "sha512-6sFr4mHKoX+/4WT+dMpJ1EXnXSbx7lG6inQ2j6riVY0DkQu5y3ebaL3oUtpHi5twA54YWaOrP8NfFr3eg3Z3fA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@gi.ts/parser": "^2.0.0", "colorette": "^2.0.20", @@ -632,10 +607,11 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -646,33 +622,37 @@ "resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz", "integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*" } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.1.tgz", - "integrity": "sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/type-utils": "7.16.1", - "@typescript-eslint/utils": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -695,16 +675,132 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.1.tgz", - "integrity": "sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/typescript-estree": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "engines": { @@ -723,15 +819,30 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz", - "integrity": "sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -740,14 +851,93 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", + "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.1.tgz", - "integrity": "sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.16.1", - "@typescript-eslint/utils": "7.16.1", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -767,11 +957,16 @@ } } }, - "node_modules/@typescript-eslint/types": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", - "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -780,14 +975,29 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.1.tgz", - "integrity": "sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -808,54 +1018,138 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", + "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", + "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/utils": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.1.tgz", - "integrity": "sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", + "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/typescript-estree": "7.16.1" + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz", - "integrity": "sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", + "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/types": "8.8.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -867,6 +1161,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -878,13 +1173,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -897,6 +1194,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -906,6 +1204,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -922,6 +1221,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -932,11 +1232,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -946,6 +1260,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -960,28 +1275,32 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -1001,13 +1320,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -1019,6 +1340,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -1028,6 +1350,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -1054,6 +1377,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -1064,6 +1388,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1073,6 +1398,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1088,13 +1414,15 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -1107,6 +1435,7 @@ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -1119,6 +1448,7 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, + "license": "ISC", "engines": { "node": ">= 12" } @@ -1128,6 +1458,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1142,6 +1473,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1159,6 +1491,7 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -1168,6 +1501,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -1179,25 +1513,29 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, + "license": "MIT", "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -1224,6 +1562,7 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1234,12 +1573,13 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1254,13 +1594,15 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -1273,6 +1615,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -1285,6 +1628,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -1296,13 +1640,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -1317,13 +1663,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1333,39 +1681,47 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -1415,6 +1771,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -1427,10 +1784,11 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1439,10 +1797,11 @@ } }, "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -1452,28 +1811,18 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -1486,6 +1835,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -1503,6 +1853,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1511,14 +1862,15 @@ } }, "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" + "eslint-visitor-keys": "^4.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1532,6 +1884,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -1544,6 +1897,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -1556,6 +1910,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1565,6 +1920,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -1574,6 +1930,7 @@ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -1587,13 +1944,15 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1610,6 +1969,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -1621,18 +1981,20 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-xml-parser": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", - "integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", + "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", "dev": true, "funding": [ { @@ -1644,6 +2006,7 @@ "url": "https://paypal.me/naturalintelligence" } ], + "license": "MIT", "dependencies": { "strnum": "^1.0.5" }, @@ -1656,6 +2019,7 @@ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -1665,6 +2029,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -1677,6 +2042,7 @@ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } @@ -1686,6 +2052,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1698,6 +2065,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1710,6 +2078,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -1726,6 +2095,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -1739,13 +2109,15 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -1761,13 +2133,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -1777,6 +2151,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^4.0.1", @@ -1800,6 +2175,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -1807,28 +2183,33 @@ "node": ">=10.13.0" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, + "license": "ISC", "dependencies": { - "type-fest": "^0.20.2" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1839,6 +2220,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -1858,13 +2240,15 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1874,6 +2258,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -1899,13 +2284,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -1915,6 +2302,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1931,6 +2319,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -1941,6 +2330,7 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1950,13 +2340,15 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/inquirer": { - "version": "9.3.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.6.tgz", - "integrity": "sha512-riK/iQB2ctwkpWYgjjWIRv3MBLt2gzb2Sj0JNQNbyTXgyXsLWcDPJ5WS5ZDTCx7BRFnJsARtYh+58fjP5M2Y0Q==", + "version": "9.3.7", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.7.tgz", + "integrity": "sha512-LJKFHCSeIRq9hanN14IlOtPSTe3lNES7TYDTE2xxdAy1LS5rYphajK1qtwvj3YmQXvvk0U2Vbmcni8P9EIQW9w==", "dev": true, + "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.3", "ansi-escapes": "^4.3.2", @@ -1979,13 +2371,15 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1995,6 +2389,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2004,6 +2399,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -2016,6 +2412,7 @@ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2025,6 +2422,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2034,6 +2432,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2043,6 +2442,7 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2054,13 +2454,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/jackspeak": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", - "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -2069,9 +2471,6 @@ }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" } }, "node_modules/jake": { @@ -2079,6 +2478,7 @@ "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -2097,6 +2497,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2107,6 +2508,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2118,13 +2520,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -2136,31 +2540,36 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -2170,6 +2579,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -2182,13 +2592,15 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -2203,19 +2615,22 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -2228,10 +2643,11 @@ } }, "node_modules/lru-cache": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", - "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", + "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", "dev": true, + "license": "ISC", "engines": { "node": "20 || >=22" } @@ -2241,15 +2657,17 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -2263,6 +2681,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -2275,20 +2694,22 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": "20 || >=22" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2299,21 +2720,24 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/mute-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -2322,13 +2746,15 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -2338,6 +2764,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -2353,6 +2780,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -2370,6 +2798,7 @@ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -2393,6 +2822,7 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2402,6 +2832,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -2417,6 +2848,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -2428,16 +2860,18 @@ } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -2450,6 +2884,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -2468,6 +2903,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2477,6 +2913,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2486,6 +2923,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2495,6 +2933,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" @@ -2511,21 +2950,24 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -2538,6 +2980,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -2547,6 +2990,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -2562,6 +3006,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2584,13 +3029,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2605,6 +3052,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2614,6 +3062,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -2623,6 +3072,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -2635,13 +3085,15 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -2653,6 +3105,7 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -2668,6 +3121,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2679,6 +3133,7 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2699,6 +3154,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2711,6 +3167,7 @@ "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2734,6 +3191,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -2743,6 +3201,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2765,25 +3224,29 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2796,6 +3259,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -2808,6 +3272,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2817,6 +3282,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -2829,6 +3295,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2838,6 +3305,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -2847,6 +3315,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2862,6 +3331,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2876,6 +3346,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2889,6 +3360,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2901,6 +3373,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -2912,13 +3385,15 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2930,13 +3405,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -2949,6 +3426,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -2961,6 +3439,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -2969,16 +3448,18 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -2987,10 +3468,11 @@ } }, "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -2999,10 +3481,11 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3012,14 +3495,15 @@ } }, "node_modules/typescript-eslint": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.1.tgz", - "integrity": "sha512-889oE5qELj65q/tGeOSvlreNKhimitFwZqQ0o7PcWC7/lgRkAMknznsCsV8J8mZGTP/Z+cIbX8accf2DE33hrA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz", + "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "7.16.1", - "@typescript-eslint/parser": "7.16.1", - "@typescript-eslint/utils": "7.16.1" + "@typescript-eslint/eslint-plugin": "7.18.0", + "@typescript-eslint/parser": "7.18.0", + "@typescript-eslint/utils": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3037,11 +3521,127 @@ } } }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -3050,13 +3650,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } @@ -3066,6 +3668,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -3081,6 +3684,7 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3090,6 +3694,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3105,6 +3710,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3121,13 +3727,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", "dev": true, + "license": "MIT", "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -3141,6 +3749,7 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0" } @@ -3150,6 +3759,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -3159,6 +3769,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -3177,6 +3788,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -3186,6 +3798,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3198,6 +3811,7 @@ "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, diff --git a/core/gjs/package.json b/lang/gjs/package.json index e829409..9f44388 100644 --- a/core/gjs/package.json +++ b/lang/gjs/package.json @@ -1,14 +1,14 @@ { "name": "astal", "version": "0.1.0", - "description": "Building blocks for buildin linux desktop shell", + "description": "Building blocks for building linux desktop shell", "type": "module", "author": "Aylur", "license": "GPL", "repository": { "type": "git", - "url": "https://github.com/astal-sh/libastal.git", - "directory": "gjs" + "url": "https://github.com/aylur/astal.git", + "directory": "lang/gjs" }, "funding": { "type": "kofi", @@ -16,14 +16,14 @@ }, "exports": { ".": "./index.ts", - "./application": "./src/application.ts", + "./gtk3": "./src/gtk3/index.ts", + "./gtk4": "./src/gtk3/index.ts", "./binding": "./src/binding.ts", "./file": "./src/file.ts", "./gobject": "./src/gobject.ts", "./process": "./src/process.ts", "./time": "./src/time.ts", - "./variable": "./src/variable.ts", - "./widgets": "./src/widgets.ts" + "./variable": "./src/variable.ts" }, "engines": { "gjs": ">=1.79.0" @@ -31,15 +31,14 @@ "os": [ "linux" ], - "publishConfig": {}, "devDependencies": { - "@eslint/js": "^9.7.0", - "@stylistic/eslint-plugin": "latest", - "@ts-for-gir/cli": "latest", + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "@ts-for-gir/cli": "^4.0.0-beta.16", "@types/eslint__js": "^8.42.3", - "eslint": "^8.57.0", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.1" + "eslint": "^8.57.1", + "typescript": "^5.6.3", + "typescript-eslint": "^7.18.0" }, "scripts": { "lint": "eslint . --fix", diff --git a/core/gjs/src/binding.ts b/lang/gjs/src/binding.ts index 95d905f..95d905f 100644 --- a/core/gjs/src/binding.ts +++ b/lang/gjs/src/binding.ts diff --git a/core/gjs/src/file.ts b/lang/gjs/src/file.ts index 90b33a1..6ad8be3 100644 --- a/core/gjs/src/file.ts +++ b/lang/gjs/src/file.ts @@ -1,4 +1,7 @@ -import { Astal, Gio } from "./imports.js" +import Astal from "gi://AstalIO" +import Gio from "gi://Gio?version=2.0" + +export { Gio } export function readFile(path: string): string { return Astal.read_file(path) || "" diff --git a/core/gjs/src/gobject.ts b/lang/gjs/src/gobject.ts index 2658555..aeb3d9e 100644 --- a/core/gjs/src/gobject.ts +++ b/lang/gjs/src/gobject.ts @@ -1,7 +1,10 @@ import GObject from "gi://GObject" -export default GObject + +export { default as GLib } from "gi://GLib?version=2.0" +export { GObject, GObject as default } const meta = Symbol("meta") +const priv = Symbol("priv") const { ParamSpec, ParamFlags } = GObject @@ -53,30 +56,29 @@ export function property(declaration: PropertyDeclaration = Object) { const name = kebabify(prop) if (!desc) { - let value = defaultValue(declaration) - Object.defineProperty(target, prop, { get() { - return value + return this[priv]?.[prop] ?? defaultValue(declaration) }, - set(v) { - if (v !== value) { - value = v + set(v: any) { + if (v !== this[prop]) { + this[priv] ??= {} + this[priv][prop] = v this.notify(name) } }, }) Object.defineProperty(target, `set_${name.replace("-", "_")}`, { - value: function (v: any) { + value(v: any) { this[prop] = v - } + }, }) Object.defineProperty(target, `get_${name.replace("-", "_")}`, { - value: function () { + value() { return this[prop] - } + }, }) target.constructor[meta].Properties[kebabify(prop)] = pspec(name, ParamFlags.READWRITE, declaration) diff --git a/core/gjs/src/application.ts b/lang/gjs/src/gtk3/app.ts index bf82cbe..1191dc4 100644 --- a/core/gjs/src/application.ts +++ b/lang/gjs/src/gtk3/app.ts @@ -1,4 +1,10 @@ -import { Astal, GObject, Gio, GLib } from "./imports.js" +import IO from "gi://AstalIO" +import GObject from "gi://GObject" +import Astal from "gi://Astal?version=3.0" +import Gio from "gi://Gio?version=2.0" +import Gtk from "gi://Gtk?version=3.0" + +Gtk.init(null) type RequestHandler = { (request: string, res: (response: any) => void): void @@ -17,13 +23,11 @@ type Config = Partial<{ hold: boolean }> -// @ts-expect-error missing types -// https://github.com/gjsify/ts-for-gir/issues/164 import { setConsoleLogDomain } from "console" import { exit, programArgs } from "system" export default new (class AstalJS extends Astal.Application { - static { GObject.registerClass(this) } + static { GObject.registerClass({ GTypeName: "AstalJS" }, this) } eval(body: string): Promise<any> { return new Promise((res, rej) => { @@ -46,8 +50,8 @@ export default new (class AstalJS extends Astal.Application { vfunc_request(msg: string, conn: Gio.SocketConnection): void { if (typeof this.requestHandler === "function") { this.requestHandler(msg, (response) => { - Astal.write_sock(conn, String(response), (_, res) => - Astal.write_sock_finish(res), + IO.write_sock(conn, String(response), (_, res) => + IO.write_sock_finish(res), ) }) } @@ -76,17 +80,15 @@ export default new (class AstalJS extends Astal.Application { this.requestHandler = requestHandler this.connect("activate", () => { - const path: string[] = import.meta.url.split("/").slice(3) - const file = path.at(-1)!.replace(".js", ".css") - const css = `/${path.slice(0, -1).join("/")}/${file}` - if (file.endsWith(".css") && GLib.file_test(css, GLib.FileTest.EXISTS)) - this.apply_css(css, false) - main?.(...programArgs) }) - if (!this.acquire_socket()) - return client(msg => Astal.Application.send_message(this.instanceName, msg)!, ...programArgs) + try { + this.acquire_socket() + } + catch (error) { + return client(msg => IO.send_message(this.instanceName, msg)!, ...programArgs) + } if (css) this.apply_css(css, false) diff --git a/core/gjs/src/astalify.ts b/lang/gjs/src/gtk3/astalify.ts index c4cbc5c..2cd6984 100644 --- a/core/gjs/src/astalify.ts +++ b/lang/gjs/src/gtk3/astalify.ts @@ -1,9 +1,12 @@ -import Binding, { kebabify, snakeify, type Connectable, type Subscribable } from "./binding.js" -import { Astal, Gtk, Gdk, GObject } from "./imports.js" -import { execAsync } from "./process.js" -import Variable from "./variable.js" - -function mergeBindings(array: any[]) { +import Astal from "gi://Astal?version=3.0" +import Gtk from "gi://Gtk?version=3.0" +import Gdk from "gi://Gdk?version=3.0" +import GObject from "gi://GObject" +import { execAsync } from "../process.js" +import Variable from "../variable.js" +import Binding, { kebabify, snakeify, type Connectable, type Subscribable } from "../binding.js" + +export function mergeBindings(array: any[]) { function getValues(...args: any[]) { let i = 0 return array.map(value => value instanceof Binding diff --git a/lang/gjs/src/gtk3/index.ts b/lang/gjs/src/gtk3/index.ts new file mode 100644 index 0000000..cfafbda --- /dev/null +++ b/lang/gjs/src/gtk3/index.ts @@ -0,0 +1,9 @@ +import Astal from "gi://Astal?version=3.0" +import Gtk from "gi://Gtk?version=3.0" +import Gdk from "gi://Gdk?version=3.0" +import astalify, { type ConstructProps } from "./astalify.js" + +export { Astal, Gtk, Gdk } +export { default as App } from "./app.js" +export { astalify, ConstructProps } +export * as Widget from "./widget.js" diff --git a/core/gjs/src/jsx/jsx-runtime.ts b/lang/gjs/src/gtk3/jsx-runtime.ts index f40dc05..22dc424 100644 --- a/core/gjs/src/jsx/jsx-runtime.ts +++ b/lang/gjs/src/gtk3/jsx-runtime.ts @@ -1,10 +1,18 @@ -import { Gtk } from "../imports.js" -import * as Widget from "../widgets.js" +import Gtk from "gi://Gtk?version=3.0" +import { mergeBindings, type BindableChild } from "./astalify.js" +import * as Widget from "./widget.js" function isArrowFunction(func: any): func is (args: any) => any { return !Object.hasOwn(func, "prototype") } +export function Fragment({ children = [], child }: { + child?: BindableChild + children?: Array<BindableChild> +}) { + return mergeBindings([...children, child]) +} + export function jsx( ctor: keyof typeof ctors | typeof Gtk.Widget, { children, ...props }: any, diff --git a/core/gjs/src/widgets.ts b/lang/gjs/src/gtk3/widget.ts index e14ca0b..b4e8497 100644 --- a/core/gjs/src/widgets.ts +++ b/lang/gjs/src/gtk3/widget.ts @@ -1,9 +1,9 @@ /* eslint-disable max-len */ -import { Astal, GObject, Gtk } from "./imports.js" +import Astal from "gi://Astal?version=3.0" +import Gtk from "gi://Gtk?version=3.0" +import GObject from "gi://GObject" import astalify, { type ConstructProps, type BindableChild } from "./astalify.js" -export { astalify, ConstructProps } - // Box Object.defineProperty(Astal.Box.prototype, "children", { get() { return this.get_children() }, @@ -103,6 +103,11 @@ export class LevelBar extends astalify(Astal.LevelBar) { // TODO: ListBox // Overlay +Object.defineProperty(Astal.Overlay.prototype, "overlays", { + get() { return this.get_overlays() }, + set(v) { this.set_overlays(v) }, +}) + export type OverlayProps = ConstructProps<Overlay, Astal.Overlay.ConstructorProps> export class Overlay extends astalify(Astal.Overlay) { static { GObject.registerClass({ GTypeName: "Overlay" }, this) } diff --git a/lang/gjs/src/gtk4/app.ts b/lang/gjs/src/gtk4/app.ts new file mode 100644 index 0000000..d931f73 --- /dev/null +++ b/lang/gjs/src/gtk4/app.ts @@ -0,0 +1 @@ +// TODO: gtk4 diff --git a/lang/gjs/src/gtk4/astalify.ts b/lang/gjs/src/gtk4/astalify.ts new file mode 100644 index 0000000..d931f73 --- /dev/null +++ b/lang/gjs/src/gtk4/astalify.ts @@ -0,0 +1 @@ +// TODO: gtk4 diff --git a/lang/gjs/src/gtk4/index.ts b/lang/gjs/src/gtk4/index.ts new file mode 100644 index 0000000..d931f73 --- /dev/null +++ b/lang/gjs/src/gtk4/index.ts @@ -0,0 +1 @@ +// TODO: gtk4 diff --git a/lang/gjs/src/gtk4/jsx-runtime.ts b/lang/gjs/src/gtk4/jsx-runtime.ts new file mode 100644 index 0000000..d931f73 --- /dev/null +++ b/lang/gjs/src/gtk4/jsx-runtime.ts @@ -0,0 +1 @@ +// TODO: gtk4 diff --git a/lang/gjs/src/index.ts b/lang/gjs/src/index.ts new file mode 100644 index 0000000..cabc961 --- /dev/null +++ b/lang/gjs/src/index.ts @@ -0,0 +1,7 @@ +export { default as AstalIO } from "gi://AstalIO?version=0.1" +export * from "./process.js" +export * from "./time.js" +export * from "./file.js" +export * from "./gobject.js" +export { bind, default as Binding } from "./binding.js" +export { Variable } from "./variable.js" diff --git a/core/gjs/src/process.ts b/lang/gjs/src/process.ts index bf8ea28..c41adc1 100644 --- a/core/gjs/src/process.ts +++ b/lang/gjs/src/process.ts @@ -1,4 +1,4 @@ -import { Astal } from "./imports.js" +import Astal from "gi://AstalIO" type Args = { cmd: string | string[] @@ -6,6 +6,8 @@ type Args = { err?: (stderr: string) => void } +export const { Process } = Astal + export function subprocess(args: Args): Astal.Process export function subprocess( diff --git a/core/gjs/src/time.ts b/lang/gjs/src/time.ts index 4e28ad0..1939d98 100644 --- a/core/gjs/src/time.ts +++ b/lang/gjs/src/time.ts @@ -1,4 +1,6 @@ -import { Astal } from "./imports.js" +import Astal from "gi://AstalIO" + +export const { Time } = Astal export function interval(interval: number, callback?: () => void) { return Astal.Time.interval(interval, () => void callback?.()) diff --git a/core/gjs/src/variable.ts b/lang/gjs/src/variable.ts index 8739ef6..9b3d3d2 100644 --- a/core/gjs/src/variable.ts +++ b/lang/gjs/src/variable.ts @@ -1,6 +1,6 @@ -import Binding, { type Connectable } from "./binding.js" -import { Astal } from "./imports.js" -import { interval, idle } from "./time.js" +import Astal from "gi://AstalIO" +import Binding, { type Connectable, type Subscribable } from "./binding.js" +import { interval } from "./time.js" import { execAsync, subprocess } from "./process.js" class VariableWrapper<T> extends Function { @@ -200,10 +200,9 @@ class VariableWrapper<T> extends Function { } static derive< - const Deps extends Array<Variable<any> | Binding<any>>, + const Deps extends Array<Subscribable<any>>, Args extends { - [K in keyof Deps]: Deps[K] extends Variable<infer T> - ? T : Deps[K] extends Binding<infer T> ? T : never + [K in keyof Deps]: Deps[K] extends Subscribable<infer T> ? T : never }, V = Args, >(deps: Deps, fn: (...args: Args) => V = (...args) => args as unknown as V) { @@ -225,7 +224,7 @@ export const Variable = new Proxy(VariableWrapper as any, { }) as { derive: typeof VariableWrapper["derive"] <T>(init: T): Variable<T> - new <T>(init: T): Variable<T> + new<T>(init: T): Variable<T> } export default Variable diff --git a/lang/gjs/tsconfig.json b/lang/gjs/tsconfig.json new file mode 100644 index 0000000..171e75b --- /dev/null +++ b/lang/gjs/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "target": "ES2023", + "outDir": "dist", + "strict": true, + "moduleResolution": "Bundler", + "skipLibCheck": true, + "baseUrl": ".", + }, + "include": [ + "@girs", + "src/*.ts", + "index.ts", + ] +} diff --git a/core/lua/astal-dev-1.rockspec b/lang/lua/astal-dev-1.rockspec index 9a41fd1..3970672 100644 --- a/core/lua/astal-dev-1.rockspec +++ b/lang/lua/astal-dev-1.rockspec @@ -19,13 +19,19 @@ dependencies = { build = { type = "builtin", modules = { - ["astal.application"] = "astal/application.lua", ["astal.binding"] = "astal/binding.lua", + ["astal.file"] = "astal/file.lua", ["astal.init"] = "astal/init.lua", ["astal.process"] = "astal/process.lua", ["astal.time"] = "astal/time.lua", ["astal.variable"] = "astal/variable.lua", - ["astal.widget"] = "astal/widget.lua", - ["astal.file"] = "astal/file.lua", + ["astal.gtk3.app"] = "astal/gtk3/app.lua", + ["astal.gtk3.init"] = "astal/gtk3/init.lua", + ["astal.gtk3.astalify"] = "astal/gtk3/astalify.lua", + ["astal.gtk3.widget"] = "astal/gtk3/widget.lua", + -- ["astal.gtk4.app"] = "astal/gtk4/app.lua", + -- ["astal.gtk4.init"] = "astal/gtk4/init.lua", + -- ["astal.gtk4.astalify"] = "astal/gtk4/astalify.lua", + -- ["astal.gtk4.widget"] = "astal/gtk4/widget.lua", }, } diff --git a/core/lua/astal/binding.lua b/lang/lua/astal/binding.lua index ba1e6e4..2944ec4 100644 --- a/core/lua/astal/binding.lua +++ b/lang/lua/astal/binding.lua @@ -4,7 +4,7 @@ local GObject = lgi.require("GObject", "2.0") ---@class Binding ---@field emitter table|Variable ---@field property? string ----@field transformFn function +---@field transform_fn function local Binding = {} ---@param emitter table @@ -14,7 +14,7 @@ function Binding.new(emitter, property) return setmetatable({ emitter = emitter, property = property, - transformFn = function(v) + transform_fn = function(v) return v end, }, Binding) @@ -30,10 +30,10 @@ end function Binding:get() if self.property ~= nil and GObject.Object:is_type_of(self.emitter) then - return self.transformFn(self.emitter[self.property]) + return self.transform_fn(self.emitter[self.property]) end if type(self.emitter.get) == "function" then - return self.transformFn(self.emitter:get()) + return self.transform_fn(self.emitter:get()) end error("can not get: Not a GObject or a Variable " + self) end @@ -42,8 +42,8 @@ end ---@return Binding function Binding:as(transform) local b = Binding.new(self.emitter, self.property) - b.transformFn = function(v) - return transform(self.transformFn(v)) + b.transform_fn = function(v) + return transform(self.transform_fn(v)) end return b end diff --git a/core/lua/astal/file.lua b/lang/lua/astal/file.lua index ca5a592..e3be783 100644 --- a/core/lua/astal/file.lua +++ b/lang/lua/astal/file.lua @@ -1,5 +1,5 @@ local lgi = require("lgi") -local Astal = lgi.require("Astal", "0.1") +local Astal = lgi.require("AstalIO", "0.1") local GObject = lgi.require("GObject", "2.0") local M = {} diff --git a/core/lua/astal/application.lua b/lang/lua/astal/gtk3/app.lua index 663a457..7895f69 100644 --- a/core/lua/astal/application.lua +++ b/lang/lua/astal/gtk3/app.lua @@ -1,5 +1,6 @@ local lgi = require("lgi") -local Astal = lgi.require("Astal", "0.1") +local Astal = lgi.require("Astal", "3.0") +local AstalIO = lgi.require("AstalIO", "0.1") local AstalLua = Astal.Application:derive("AstalLua") local request_handler @@ -7,8 +8,8 @@ local request_handler function AstalLua:do_request(msg, conn) if type(request_handler) == "function" then request_handler(msg, function(response) - Astal.write_sock(conn, tostring(response), function(_, res) - Astal.write_sock_finish(res) + AstalIO.write_sock(conn, tostring(response), function(_, res) + AstalIO.write_sock_finish(res) end) end) else @@ -82,9 +83,10 @@ function Astal.Application:start(config) end end - if not app:acquire_socket() then + local _, err = app:acquire_socket() + if err ~= nil then return config.client(function(msg) - return Astal.Application.send_message(self.instance_name, msg) + return AstalIO.send_message(self.instance_name, msg) end, table.unpack(arg)) end diff --git a/core/lua/astal/widget.lua b/lang/lua/astal/gtk3/astalify.lua index 8f49409..211a1d4 100644 --- a/core/lua/astal/widget.lua +++ b/lang/lua/astal/gtk3/astalify.lua @@ -1,5 +1,5 @@ local lgi = require("lgi") -local Astal = lgi.require("Astal", "0.1") +local Astal = lgi.require("Astal", "3.0") local Gtk = lgi.require("Gtk", "3.0") local GObject = lgi.require("GObject", "2.0") local Binding = require("astal.binding") @@ -28,8 +28,7 @@ local function map(tbl, fn) return copy end -local flatten -flatten = function(tbl) +local function flatten(tbl) local copy = {} for _, value in pairs(tbl) do if type(value) == "table" and getmetatable(value) == nil then @@ -132,7 +131,7 @@ local function merge_bindings(array) return Variable.derive(bindings, get_values)() end -local function astalify(ctor) +return function(ctor) function ctor:hook(object, signalOrCallback, callback) if GObject.Object:is_type_of(object) and type(signalOrCallback) == "string" then local id @@ -234,89 +233,3 @@ local function astalify(ctor) return widget end end - -local Widget = { - astalify = astalify, - Box = astalify(Astal.Box), - Button = astalify(Astal.Button), - CenterBox = astalify(Astal.CenterBox), - CircularProgress = astalify(Astal.CircularProgress), - DrawingArea = astalify(Gtk.DrawingArea), - Entry = astalify(Gtk.Entry), - EventBox = astalify(Astal.EventBox), - -- TODO: Fixed - -- TODO: FlowBox - Icon = astalify(Astal.Icon), - Label = astalify(Gtk.Label), - LevelBar = astalify(Astal.LevelBar), - -- TODO: ListBox - Overlay = astalify(Astal.Overlay), - Revealer = astalify(Gtk.Revealer), - Scrollable = astalify(Astal.Scrollable), - Slider = astalify(Astal.Slider), - Stack = astalify(Astal.Stack), - Switch = astalify(Gtk.Switch), - Window = astalify(Astal.Window), -} - -Gtk.Widget._attribute.css = { - get = Astal.widget_get_css, - set = Astal.widget_set_css, -} - -Gtk.Widget._attribute.class_name = { - get = function(self) - local result = "" - local strings = Astal.widget_set_class_names(self) - for i, str in ipairs(strings) do - result = result .. str - if i < #strings then - result = result .. " " - end - end - return result - end, - set = function(self, class_name) - local names = {} - for word in class_name:gmatch("%S+") do - table.insert(names, word) - end - Astal.widget_set_class_names(self, names) - end, -} - -Gtk.Widget._attribute.cursor = { - get = Astal.widget_get_cursor, - set = Astal.widget_set_cursor, -} - -Gtk.Widget._attribute.click_through = { - get = Astal.widget_get_click_through, - set = Astal.widget_set_click_through, -} - -local no_implicit_destroy = {} -Gtk.Widget._attribute.no_implicit_destroy = { - get = function(self) - return no_implicit_destroy[self] or false - end, - set = function(self, v) - if no_implicit_destroy[self] == nil then - self.on_destroy = function() - no_implicit_destroy[self] = nil - end - end - no_implicit_destroy[self] = v - end, -} - -Astal.Box._attribute.children = { - get = Astal.Box.get_children, - set = Astal.Box.set_children, -} - -return setmetatable(Widget, { - __call = function(_, ctor) - return astalify(ctor) - end, -}) diff --git a/lang/lua/astal/gtk3/init.lua b/lang/lua/astal/gtk3/init.lua new file mode 100644 index 0000000..e5cc0e6 --- /dev/null +++ b/lang/lua/astal/gtk3/init.lua @@ -0,0 +1,11 @@ +local lgi = require("lgi") + +return { + App = require("astal.gtk3.app"), + astalify = require("astal.gtk3.astalify"), + Widget = require("astal.gtk3.widget"), + + Gtk = lgi.require("Gtk", "3.0"), + Gdk = lgi.require("Gdk", "3.0"), + Astal = lgi.require("Astal", "3.0"), +} diff --git a/lang/lua/astal/gtk3/widget.lua b/lang/lua/astal/gtk3/widget.lua new file mode 100644 index 0000000..beaad6c --- /dev/null +++ b/lang/lua/astal/gtk3/widget.lua @@ -0,0 +1,90 @@ +local lgi = require("lgi") +local Astal = lgi.require("Astal", "3.0") +local Gtk = lgi.require("Gtk", "3.0") +local astalify = require("astal.gtk3.astalify") + +local Widget = { + astalify = astalify, + Box = astalify(Astal.Box), + Button = astalify(Astal.Button), + CenterBox = astalify(Astal.CenterBox), + CircularProgress = astalify(Astal.CircularProgress), + DrawingArea = astalify(Gtk.DrawingArea), + Entry = astalify(Gtk.Entry), + EventBox = astalify(Astal.EventBox), + -- TODO: Fixed + -- TODO: FlowBox + Icon = astalify(Astal.Icon), + Label = astalify(Gtk.Label), + LevelBar = astalify(Astal.LevelBar), + -- TODO: ListBox + Overlay = astalify(Astal.Overlay), + Revealer = astalify(Gtk.Revealer), + Scrollable = astalify(Astal.Scrollable), + Slider = astalify(Astal.Slider), + Stack = astalify(Astal.Stack), + Switch = astalify(Gtk.Switch), + Window = astalify(Astal.Window), +} + +Gtk.Widget._attribute.css = { + get = Astal.widget_get_css, + set = Astal.widget_set_css, +} + +Gtk.Widget._attribute.class_name = { + get = function(self) + local result = "" + local strings = Astal.widget_get_class_names(self) + for i, str in ipairs(strings) do + result = result .. str + if i < #strings then + result = result .. " " + end + end + return result + end, + set = function(self, class_name) + local names = {} + for word in class_name:gmatch("%S+") do + table.insert(names, word) + end + Astal.widget_set_class_names(self, names) + end, +} + +Gtk.Widget._attribute.cursor = { + get = Astal.widget_get_cursor, + set = Astal.widget_set_cursor, +} + +Gtk.Widget._attribute.click_through = { + get = Astal.widget_get_click_through, + set = Astal.widget_set_click_through, +} + +local no_implicit_destroy = {} +Gtk.Widget._attribute.no_implicit_destroy = { + get = function(self) + return no_implicit_destroy[self] or false + end, + set = function(self, v) + if no_implicit_destroy[self] == nil then + self.on_destroy = function() + no_implicit_destroy[self] = nil + end + end + no_implicit_destroy[self] = v + end, +} + +Astal.Box._attribute.children = { + get = Astal.Box.get_children, + set = Astal.Box.set_children, +} + +return setmetatable(Widget, { + __call = function(_, ctor) + return astalify(ctor) + end, +}) diff --git a/core/lua/astal/init.lua b/lang/lua/astal/init.lua index f56c3f5..5630ba4 100644 --- a/core/lua/astal/init.lua +++ b/lang/lua/astal/init.lua @@ -1,20 +1,16 @@ +if not table.unpack then + table.unpack = unpack +end + local lgi = require("lgi") -local Astal = lgi.require("Astal", "0.1") -local Gtk = lgi.require("Gtk", "3.0") -local Gdk = lgi.require("Gdk", "3.0") -local GObject = lgi.require("GObject", "2.0") -local Widget = require("astal.widget") -local Variable = require("astal.variable") local Binding = require("astal.binding") -local App = require("astal.application") +local File = require("astal.file") local Process = require("astal.process") local Time = require("astal.time") -local File = require("astal.file") +local Variable = require("astal.variable") return { - App = App, Variable = Variable, - Widget = Widget, bind = Binding.new, interval = Time.interval, @@ -31,11 +27,5 @@ return { write_file_async = File.write_file_async, monitor_file = File.monitor_file, - Astal = Astal, - Gtk = Gtk, - Gdk = Gdk, - GObject = GObject, - GLib = lgi.require("GLib", "2.0"), - Gio = lgi.require("Gio", "2.0"), require = lgi.require, } diff --git a/core/lua/astal/process.lua b/lang/lua/astal/process.lua index 62360b3..0031f4c 100644 --- a/core/lua/astal/process.lua +++ b/lang/lua/astal/process.lua @@ -1,37 +1,38 @@ local lgi = require("lgi") -local Astal = lgi.require("Astal", "0.1") +local Astal = lgi.require("AstalIO", "0.1") local M = {} +M.Process = Astal.Process + ---@param commandline string | string[] ---@param on_stdout? fun(out: string): nil ---@param on_stderr? fun(err: string): nil ---@return { kill: function } | nil proc function M.subprocess(commandline, on_stdout, on_stderr) - if on_stdout == nil then - on_stdout = function(out) - io.stdout:write(tostring(out) .. "\n") - end + on_stdout = on_stdout or function(out) + io.stdout:write(tostring(out) .. "\n") end - if on_stderr == nil then - on_stderr = function(err) - io.stderr:write(tostring(err) .. "\n") - end + on_stderr = on_stderr or function(err) + io.stderr:write(tostring(err) .. "\n") end + local proc, err + if type(commandline) == "table" then proc, err = Astal.Process.subprocessv(commandline) else proc, err = Astal.Process.subprocess(commandline) end + if err ~= nil then err(err) return nil end - proc.on_stdout = function(_, stdoud) - on_stdout(stdoud) + proc.on_stdout = function(_, stdout) + on_stdout(stdout) end proc.on_stderr = function(_, stderr) on_stderr(stderr) @@ -52,13 +53,11 @@ end ---@param commandline string | string[] ---@param callback? fun(out: string, err: string): nil function M.exec_async(commandline, callback) - if callback == nil then - callback = function(out, err) - if err ~= nil then - io.stdout:write(tostring(out) .. "\n") - else - io.stderr:write(tostring(err) .. "\n") - end + callback = callback or function(out, err) + if err ~= nil then + io.stdout:write(tostring(out) .. "\n") + else + io.stderr:write(tostring(err) .. "\n") end end diff --git a/core/lua/astal/time.lua b/lang/lua/astal/time.lua index f4e2b81..2b81dbd 100644 --- a/core/lua/astal/time.lua +++ b/lang/lua/astal/time.lua @@ -1,9 +1,11 @@ local lgi = require("lgi") -local Astal = lgi.require("Astal", "0.1") +local Astal = lgi.require("AstalIO", "0.1") local GObject = lgi.require("GObject", "2.0") local M = {} +M.Time = Astal.Time + ---@param interval number ---@param fn function ---@return { cancel: function, on_now: function } diff --git a/core/lua/astal/variable.lua b/lang/lua/astal/variable.lua index 662eee7..2305a71 100644 --- a/core/lua/astal/variable.lua +++ b/lang/lua/astal/variable.lua @@ -1,5 +1,5 @@ local lgi = require("lgi") -local Astal = lgi.require("Astal", "0.1") +local Astal = lgi.require("AstalIO", "0.1") local GObject = lgi.require("GObject", "2.0") local Binding = require("astal.binding") local Time = require("astal.time") @@ -20,7 +20,7 @@ local Process = require("astal.process") local Variable = {} Variable.__index = Variable ----@param value any +---@param value? any ---@return Variable function Variable.new(value) local v = Astal.VariableBase() @@ -30,7 +30,7 @@ function Variable.new(value) }, Variable) v.on_dropped = function() variable:stop_watch() - variable:stop_watch() + variable:stop_poll() end v.on_error = function(_, err) if variable.err_handler then @@ -40,16 +40,14 @@ function Variable.new(value) return variable end ----@param transform function +---@param transform? fun(v: any): any ---@return Binding function Variable:__call(transform) - if transform == nil then - transform = function(v) - return v - end + if type(transform) == "nil" then return Binding.new(self) + else + return Binding.new(self):as(transform) end - return Binding.new(self):as(transform) end function Variable:__tostring() @@ -57,7 +55,7 @@ function Variable:__tostring() end function Variable:get() - return self._value or nil + return self._value end function Variable:set(value) @@ -67,8 +65,16 @@ function Variable:set(value) end end +function Variable:is_polling() + return self._poll ~= nil +end + +function Variable:is_watching() + return self._watch ~= nil +end + function Variable:start_poll() - if self._poll ~= nil then + if self:is_polling() then return end @@ -81,15 +87,16 @@ function Variable:start_poll() Process.exec_async(self.poll_exec, function(out, err) if err ~= nil then return self.variable.emit_error(err) + else + self:set(self.poll_transform(out, self:get())) end - self:set(self.poll_transform(out, self:get())) end) end) end end function Variable:start_watch() - if self._watch then + if self:is_watching() then return end @@ -100,27 +107,21 @@ function Variable:start_watch() end) end + function Variable:stop_poll() - if self._poll then + if self:is_polling() then self._poll.cancel() end self._poll = nil end function Variable:stop_watch() - if self._watch then + if self:is_watching() then self._watch.kill() end self._watch = nil end -function Variable:is_polling() - return self._poll ~= nil -end - -function Variable:is_watching() - return self._watch ~= nil -end function Variable:drop() self.variable.emit_dropped() @@ -137,7 +138,7 @@ end ---@return Variable function Variable:on_error(callback) self.err_handler = nil - self.variable.on_eror = function(_, err) + self.variable.on_error = function(_, err) callback(err) end return self @@ -158,11 +159,10 @@ end ---@param exec string | string[] | function ---@param transform? fun(next: any, prev: any): any function Variable:poll(interval, exec, transform) - if transform == nil then - transform = function(next) - return next - end + transform = transform or function(next) + return next end + self:stop_poll() self.poll_interval = interval self.poll_transform = transform @@ -181,12 +181,11 @@ end ---@param exec string | string[] ---@param transform? fun(next: any, prev: any): any function Variable:watch(exec, transform) - if transform == nil then - transform = function(next) - return next - end + transform = transform or function (next) + return next end - self:stop_poll() + + self:stop_watch() self.watch_exec = exec self.watch_transform = transform self:start_watch() @@ -208,6 +207,7 @@ function Variable:observe(object, sigOrFn, callback) return self:get() end end + local set = function(...) self:set(f(...)) end @@ -226,10 +226,8 @@ end ---@param transform? fun(...): any ---@return Variable function Variable.derive(deps, transform) - if type(transform) == "nil" then - transform = function(...) - return { ... } - end + transform = transform or function(...) + return { ... } end if getmetatable(deps) == Variable then @@ -246,7 +244,7 @@ function Variable.derive(deps, transform) end end - local update = function() + local function update() local params = {} for i, binding in ipairs(deps) do params[i] = binding:get() @@ -257,6 +255,7 @@ function Variable.derive(deps, transform) local var = Variable.new(update()) local unsubs = {} + for i, b in ipairs(deps) do unsubs[i] = b:subscribe(update) end @@ -273,4 +272,4 @@ return setmetatable(Variable, { __call = function(_, v) return Variable.new(v) end, -}) +})
\ No newline at end of file diff --git a/core/lua/stylua.toml b/lang/lua/stylua.toml index d4a4951..d4a4951 100644 --- a/core/lua/stylua.toml +++ b/lang/lua/stylua.toml diff --git a/lib/apps/application.vala b/lib/apps/application.vala index 5748fc6..0a2f73c 100644 --- a/lib/apps/application.vala +++ b/lib/apps/application.vala @@ -1,23 +1,68 @@ -namespace AstalApps { -public class Application : Object { +public class AstalApps.Application : Object { + /** + * The underlying DesktopAppInfo. + */ public DesktopAppInfo app { get; construct set; } + + /** + * The number of times [[email protected]] was called on this Application. + */ public int frequency { get; set; default = 0; } + + /** + * The name of this Application. + */ public string name { get { return app.get_name(); } } + + /** + * Name of the .desktop of this Application. + */ public string entry { get { return app.get_id(); } } + + /** + * Description of this Application. + */ public string description { get { return app.get_description(); } } + + /** + * `StartupWMClass` field from the desktop file. + * This represents the `WM_CLASS` property of the main window of the application. + */ public string wm_class { get { return app.get_startup_wm_class(); } } + + /** + * `Exec` field from the desktop file. + * Note that if you want to launch this Application you should use the [[email protected]] method. + */ public string executable { owned get { return app.get_string("Exec"); } } + + /** + * `Icon` field from the desktop file. + * This is usually a named icon or a path to a file. + */ public string icon_name { owned get { return app.get_string("Icon"); } } + /** + * `Keywords` field from the desktop file. + */ + public string[] keywords { owned get { return app.get_keywords(); } } + internal Application(string id, int? frequency = 0) { Object(app: new DesktopAppInfo(id)); this.frequency = frequency; } + /** + * Get a value from the .desktop file by its key. + */ public string get_key(string key) { return app.get_string(key); } + /** + * Launches this application. + * The launched application inherits the environment of the launching process + */ public bool launch() { try { var s = app.launch(null, null); @@ -29,22 +74,36 @@ public class Application : Object { } } + /** + * Calculate a score for an application using fuzzy matching algorithm. + */ public Score fuzzy_match(string term) { var score = Score(); + if (name != null) - score.name = levenshtein(term, name); + score.name = fuzzy_match_string(term, name); if (entry != null) - score.entry = levenshtein(term, entry); + score.entry = fuzzy_match_string(term, entry); if (executable != null) - score.executable = levenshtein(term, executable); + score.executable = fuzzy_match_string(term, executable); if (description != null) - score.description = levenshtein(term, description); + score.description = fuzzy_match_string(term, description); + foreach (var keyword in keywords) { + var s = fuzzy_match_string(term, keyword); + if (s > score.keywords) { + score.keywords = s; + } + } return score; } + /** + * Calculate a score using exact string algorithm. + */ public Score exact_match(string term) { var score = Score(); + if (name != null) score.name = name.down().contains(term.down()) ? 1 : 0; if (entry != null) @@ -53,12 +112,17 @@ public class Application : Object { score.executable = executable.down().contains(term.down()) ? 1 : 0; if (description != null) score.description = description.down().contains(term.down()) ? 1 : 0; + foreach (var keyword in keywords) { + if (score.keywords == 0) { + score.keywords = keyword.down().contains(term.down()) ? 1 : 0; + } + } return score; } internal Json.Node to_json() { - return new Json.Builder() + var builder = new Json.Builder() .begin_object() .set_member_name("name").add_string_value(name) .set_member_name("entry").add_string_value(entry) @@ -66,53 +130,24 @@ public class Application : Object { .set_member_name("description").add_string_value(description) .set_member_name("icon_name").add_string_value(icon_name) .set_member_name("frequency").add_int_value(frequency) - .end_object() - .get_root(); - } -} - -int min3(int a, int b, int c) { - return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); -} - -double levenshtein(string s1, string s2) { - int len1 = s1.length; - int len2 = s2.length; - - int[, ] d = new int[len1 + 1, len2 + 1]; - - for (int i = 0; i <= len1; i++) { - d[i, 0] = i; - } - for (int j = 0; j <= len2; j++) { - d[0, j] = j; - } + .set_member_name("keywords") + .begin_array(); - for (int i = 1; i <= len1; i++) { - for (int j = 1; j <= len2; j++) { - int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1; - d[i, j] = min3( - d[i - 1, j] + 1, // deletion - d[i, j - 1] + 1, // insertion - d[i - 1, j - 1] + cost // substitution - ); + foreach (string keyword in keywords) { + builder.add_string_value(keyword); } - } - var distance = d[len1, len2]; - int max_len = len1 > len2 ? len1 : len2; - - if (max_len == 0) { - return 1.0; + return builder + .end_array() + .end_object() + .get_root(); } - - return 1.0 - ((double)distance / max_len); } -public struct Score { - double name; - double entry; - double executable; - double description; -} +public struct AstalApps.Score { + int name; + int entry; + int executable; + int description; + int keywords; } diff --git a/lib/apps/apps.vala b/lib/apps/apps.vala index 2a0d507..dde7d44 100644 --- a/lib/apps/apps.vala +++ b/lib/apps/apps.vala @@ -1,25 +1,84 @@ -namespace AstalApps { -public class Apps : Object { +public class AstalApps.Apps : Object { private string cache_directory; private string cache_file; private List<Application> _list; private HashTable<string, int> frequents { get; private set; } + /** + * Indicates wether hidden applications should included in queries. + */ public bool show_hidden { get; set; } + + /** + * Full list of available applications. + */ public List<weak Application> list { owned get { return _list.copy(); } } - public double min_score { get; set; default = 0.5; } + /** + * The minimum score the application has to meet in order to be included in queries. + */ + public double min_score { get; set; default = 0; } + /** + * Extra multiplier to apply when matching the `name` of an application. + * Defaults to `2` + */ public double name_multiplier { get; set; default = 2; } + + /** + * Extra multiplier to apply when matching the entry of an application. + * Defaults to `1` + */ public double entry_multiplier { get; set; default = 1; } + + /** + * Extra multiplier to apply when matching the executable of an application. + * Defaults to `1` + */ public double executable_multiplier { get; set; default = 1; } + + /** + * Extra multiplier to apply when matching the description of an application. + * Defaults to `0.5` + */ public double description_multiplier { get; set; default = 0.5; } + /** + * Extra multiplier to apply when matching the keywords of an application. + * Defaults to `0.5` + */ + public double keywords_multiplier { get; set; default = 0.5; } + + /** + * Consider the name of an application during queries. + * Defaults to `true` + */ public bool include_name { get; set; default = true; } + + /** + * Consider the entry of an application during queries. + * Defaults to `false` + */ public bool include_entry { get; set; default = false; } + + /** + * Consider the executable of an application during queries. + * Defaults to `false` + */ public bool include_executable { get; set; default = false; } + + /** + * Consider the description of an application during queries. + * Defaults to `false` + */ public bool include_description { get; set; default = false; } + /** + * Consider the keywords of an application during queries. + * Defaults to `false` + */ + public bool include_keywords { get; set; default = false; } + construct { cache_directory = Environment.get_user_cache_dir() + "/astal"; cache_file = cache_directory + "/apps-frequents.json"; @@ -49,23 +108,39 @@ public class Apps : Object { reload(); } - private double score (string search, Application a, bool exact) { - var am = exact ? a.exact_match(search) : a.fuzzy_match(search); + private double score(string search, Application a, SearchAlgorithm alg) { + var s = Score(); double r = 0; - if (include_name) - r += am.name * name_multiplier; - if (include_entry) - r += am.entry * entry_multiplier; - if (include_executable) - r += am.executable * executable_multiplier; - if (include_description) - r += am.description * description_multiplier; + if (alg == FUZZY) s = a.fuzzy_match(search); + if (alg == EXACT) s = a.exact_match(search); + + if (include_name) r += s.name * name_multiplier; + if (include_entry) r += s.entry * entry_multiplier; + if (include_executable) r += s.executable * executable_multiplier; + if (include_description) r += s.description * description_multiplier; + if (include_keywords) r += s.keywords * keywords_multiplier; return r; } - public List<weak Application> query(string? search = "", bool exact = false) { + /** + * Calculate a score for an application using fuzzy matching algorithm. + * Taking this Apps' include settings into consideration . + */ + public double fuzzy_score(string search, Application a) { + return score(search, a, FUZZY); + } + + /** + * Calculate a score for an application using exact string algorithm. + * Taking this Apps' include settings into consideration . + */ + public double exact_score(string search, Application a) { + return score(search, a, EXACT); + } + + internal List<weak Application> query(string? search = "", SearchAlgorithm alg = FUZZY) { if (search == null) search = ""; @@ -83,7 +158,7 @@ public class Apps : Object { // single character, sort by frequency and exact match if (search.length == 1) { foreach (var app in list) { - if (score(search, app, true) == 0) + if (score(search, app, alg) == 0) arr.remove(app); } @@ -96,14 +171,14 @@ public class Apps : Object { // filter foreach (var app in list) { - if (score(search, app, exact) < min_score) + if (score(search, app, alg) < min_score) arr.remove(app); } // sort by score, frequency arr.sort_with_data((a, b) => { - var s1 = score(search, a, exact); - var s2 = score(search, b, exact); + var s1 = score(search, a, alg); + var s2 = score(search, b, alg); if (s1 == s2) return (int)b.frequency - (int)a.frequency; @@ -114,14 +189,23 @@ public class Apps : Object { return arr; } + /** + * Query the `list` of applications with a fuzzy matching algorithm. + */ public List<weak Application> fuzzy_query(string? search = "") { - return query(search, false); + return query(search, FUZZY); } + /** + * Query the `list` of applications with a simple string matching algorithm. + */ public List<weak Application> exact_query(string? search = "") { - return query(search, true); + return query(search, EXACT); } + /** + * Reload the `list` of Applications. + */ public void reload() { var arr = AppInfo.get_all(); @@ -169,4 +253,8 @@ public class Apps : Object { } } } + +private enum AstalApps.SearchAlgorithm { + EXACT, + FUZZY, } diff --git a/lib/apps/fuzzy.vala b/lib/apps/fuzzy.vala new file mode 100644 index 0000000..7745320 --- /dev/null +++ b/lib/apps/fuzzy.vala @@ -0,0 +1,73 @@ +namespace AstalApps { +private int fuzzy_match_string(string pattern, string str) { + const int unmatched_letter_penalty = -1; + int score = 100; + + if (pattern.length == 0) return score; + if (str.length < pattern.length) return int.MIN; + + bool found = fuzzy_match_recurse(pattern, str, score, true, out score); + score += unmatched_letter_penalty * (str.length - pattern.length); + + if(!found) score = -10; + + return score; +} + +private bool fuzzy_match_recurse(string pattern, string str, int score, bool first_char, out int result) { + result = score; + if (pattern.length == 0) return true; + + int match_idx = 0; + int offset = 0; + unichar search = pattern.casefold().get_char(0); + int best_score = int.MIN; + + while ((match_idx = str.casefold().substring(offset).index_of_char(search)) >= 0) { + offset += match_idx; + int subscore; + bool found = fuzzy_match_recurse( + pattern.substring(1), + str.substring(offset + 1), + compute_score(offset, first_char, str, offset), false, out subscore); + if(!found) break; + best_score = int.max(best_score, subscore); + offset++; + } + + if (best_score == int.MIN) return false; + result += best_score; + return true; +} + +private int compute_score(int jump, bool first_char, string match, int idx) { + const int adjacency_bonus = 15; + const int separator_bonus = 30; + const int camel_bonus = 30; + const int first_letter_bonus = 15; + const int leading_letter_penalty = -5; + const int max_leading_letter_penalty = -15; + + int score = 0; + + if (!first_char && jump == 0) { + score += adjacency_bonus; + } + if (!first_char || jump > 0) { + if (match[idx].isupper() && match[idx-1].islower()) { + score += camel_bonus; + } + if (match[idx].isalnum() && !match[idx-1].isalnum()) { + score += separator_bonus; + } + } + if (first_char && jump == 0) { + score += first_letter_bonus; + } + if (first_char) { + score += int.max(leading_letter_penalty * jump, max_leading_letter_penalty); + } + + return score; +} +} diff --git a/lib/apps/gir.py b/lib/apps/gir.py new file mode 120000 index 0000000..b5b4f1d --- /dev/null +++ b/lib/apps/gir.py @@ -0,0 +1 @@ +../gir.py
\ No newline at end of file diff --git a/lib/apps/meson.build b/lib/apps/meson.build index fb87e22..eb7a90b 100644 --- a/lib/apps/meson.build +++ b/lib/apps/meson.build @@ -39,34 +39,41 @@ deps = [ dependency('json-glib-1.0'), ] -sources = [ - config, - 'apps.vala', +sources = [config] + files( 'application.vala', + 'apps.vala', 'cli.vala', -] + 'fuzzy.vala', +) if get_option('lib') lib = library( meson.project_name(), sources, dependencies: deps, + vala_args: ['--vapi-comments'], vala_header: meson.project_name() + '.h', vala_vapi: meson.project_name() + '-' + api_version + '.vapi', - vala_gir: gir, version: meson.project_version(), install: true, - install_dir: [true, true, true, true], + install_dir: [true, true, true], ) - import('pkgconfig').generate( - lib, - name: meson.project_name(), - filebase: meson.project_name() + '-' + api_version, - version: meson.project_version(), - subdirs: meson.project_name(), - requires: deps, - install_dir: get_option('libdir') / 'pkgconfig', + pkgs = [] + foreach dep : deps + pkgs += ['--pkg=' + dep.name()] + endforeach + + gir_tgt = custom_target( + gir, + command: [find_program('python3'), files('gir.py'), meson.project_name(), gir] + + pkgs + + sources, + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', ) custom_target( @@ -79,10 +86,20 @@ if get_option('lib') ], input: lib, output: typelib, - depends: lib, + depends: [lib, gir_tgt], install: true, install_dir: get_option('libdir') / 'girepository-1.0', ) + + import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: deps, + install_dir: get_option('libdir') / 'pkgconfig', + ) endif if get_option('cli') diff --git a/lib/astal/gtk3/gir.py b/lib/astal/gtk3/gir.py new file mode 120000 index 0000000..16a3a64 --- /dev/null +++ b/lib/astal/gtk3/gir.py @@ -0,0 +1 @@ +../../gir.py
\ No newline at end of file diff --git a/core/meson.build b/lib/astal/gtk3/meson.build index a2606db..48d3058 100644 --- a/core/meson.build +++ b/lib/astal/gtk3/meson.build @@ -11,17 +11,8 @@ project( ], ) -prefix = get_option('prefix') libdir = get_option('prefix') / get_option('libdir') -pkgdatadir = prefix / get_option('datadir') / 'astal' - -assert( - get_option('lib') or get_option('cli'), - 'Either lib or cli option must be set to true.', -) - -if get_option('gjs') - install_subdir('gjs', install_dir: pkgdatadir) -endif +pkgdatadir = get_option('prefix') / get_option('datadir') / 'astal' +girpy = files('gir.py') subdir('src') diff --git a/lib/astal/gtk3/src/application.vala b/lib/astal/gtk3/src/application.vala new file mode 100644 index 0000000..82ee797 --- /dev/null +++ b/lib/astal/gtk3/src/application.vala @@ -0,0 +1,265 @@ +[DBus (name="io.Astal.Application")] +public class Astal.Application : Gtk.Application, AstalIO.Application { + private List<Gtk.CssProvider> css_providers = new List<Gtk.CssProvider>(); + private SocketService service; + private DBusConnection conn; + private string _instance_name = "astal"; + private string socket_path { get; private set; } + + /** + * Emitted when a new monitor is added to [[email protected]]. + */ + [DBus (visible=false)] + public signal void monitor_added(Gdk.Monitor monitor); + + /** + * Emitted when a monitor is disconnected from [[email protected]]. + */ + [DBus (visible=false)] + public signal void monitor_removed(Gdk.Monitor monitor); + + /** + * Emitted when a window that has been added using + * [[email protected]_window] changes its visibility . + */ + [DBus (visible=false)] + public signal void window_toggled(Gtk.Window window); + + /** + * Get all monitors from [[email protected]]. + */ + [DBus (visible=false)] + public List<weak Gdk.Monitor> monitors { + owned get { + var display = Gdk.Display.get_default(); + var list = new List<weak Gdk.Monitor>(); + for (var i = 0; i <= display.get_n_monitors(); ++i) { + var mon = display.get_monitor(i); + if (mon != null) { + list.append(mon); + } + } + return list; + } + } + + /** + * A unique instance name. + * + * This is the identifier used by the AstalIO package and the CLI. + */ + [DBus (visible=false)] + public string instance_name { + owned get { return _instance_name; } + construct set { + _instance_name = value != null ? value : "astal"; + application_id = @"io.Astal.$_instance_name"; + } + } + + /** + * Windows that has been added to this app using [[email protected]_window]. + */ + [DBus (visible=false)] + public List<Gtk.Window> windows { + get { return get_windows(); } + } + + private Gtk.Settings settings { + get { return Gtk.Settings.get_default(); } + } + + private Gdk.Screen screen { + get { return Gdk.Screen.get_default(); } + } + + /** + * Shortcut for [[email protected]:gtk_theme_name] + */ + [DBus (visible=false)] + public string gtk_theme { + owned get { return settings.gtk_theme_name; } + set { settings.gtk_theme_name = value; } + } + + /** + * Shortcut for [[email protected]:gtk_icon_theme_name] + */ + [DBus (visible=false)] + public string icon_theme { + owned get { return settings.gtk_icon_theme_name; } + set { settings.gtk_icon_theme_name = value; } + } + + /** + * Shortcut for [[email protected]:gtk_cursor_theme_name] + */ + [DBus (visible=false)] + public string cursor_theme { + owned get { return settings.gtk_cursor_theme_name; } + set { settings.gtk_cursor_theme_name = value; } + } + + /** + * Remove all [[email protected]] providers. + */ + [DBus (visible=false)] + public void reset_css() { + foreach(var provider in css_providers) { + Gtk.StyleContext.remove_provider_for_screen(screen, provider); + } + css_providers = new List<Gtk.CssProvider>(); + } + + /** + * Shortcut for [[email protected]_interactive_debugging]. + */ + public void inspector() throws DBusError, IOError { + Gtk.Window.set_interactive_debugging(true); + } + + /** + * Get a window by its [[email protected]:name] that has been added to this app + * using [[email protected]_window]. + */ + [DBus (visible=false)] + public Gtk.Window? get_window(string name) { + foreach(var win in windows) { + if (win.name == name) + return win; + } + + critical("no window with name \"%s\"".printf(name)); + return null; + } + + /** + * Toggle the visibility of a window by its [[email protected]:name] + * that has been added to this app using [[email protected]_window]. + */ + public void toggle_window(string window) throws Error { + var win = get_window(window); + if (win != null) { + win.visible = !win.visible; + } else { + throw new IOError.FAILED("window not found"); + } + } + + /** + * Add a new [[email protected]] provider. + * + * @param style Css string or a path to a css file. + */ + [DBus (visible=false)] + public void apply_css(string style, bool reset = false) { + var provider = new Gtk.CssProvider(); + + if (reset) + reset_css(); + + try { + if (FileUtils.test(style, FileTest.EXISTS)) + provider.load_from_path(style); + else + provider.load_from_data(style); + } catch (Error err) { + critical(err.message); + } + + Gtk.StyleContext.add_provider_for_screen( + screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_USER); + + css_providers.append(provider); + } + + /** + * Shortcut for [[email protected]_search_path]. + */ + [DBus (visible=false)] + public void add_icons(string? path) { + if (path != null) { + Gtk.IconTheme.get_default().prepend_search_path(path); + } + } + + /** + * Handler for an incoming request. + * + * @param msg Body of the message + * @param conn The connection which expects the response. + */ + [DBus (visible=false)] + public virtual void request(string msg, SocketConnection conn) { + AstalIO.write_sock.begin(conn, @"missing response implementation on $application_id"); + } + + /** + * Attempt to acquire the astal socket for this app identified by its [[email protected]:instance_name]. + * If the socket is in use by another app with the same name an [[email protected]_OCCUPIED] is thrown. + */ + [DBus (visible=false)] + public void acquire_socket() throws Error { + string path; + service = AstalIO.acquire_socket(this, out path); + socket_path = path; + + Bus.own_name( + BusType.SESSION, + application_id, + BusNameOwnerFlags.NONE, + (conn) => { + try { + this.conn = conn; + conn.register_object("/io/Astal/Application", this); + } catch (Error err) { + critical(err.message); + } + }, + () => {}, + () => {} + ); + } + + /** + * Quit and stop the socket if it was acquired. + */ + public new void quit() throws DBusError, IOError { + if (service != null) { + service.stop(); + service.close(); + } + + base.quit(); + } + + construct { + activate.connect(() => { + var display = Gdk.Display.get_default(); + display.monitor_added.connect((mon) => { + monitor_added(mon); + notify_property("monitors"); + }); + display.monitor_removed.connect((mon) => { + monitor_removed(mon); + notify_property("monitors"); + }); + }); + + window_added.connect((window) => { + ulong id1, id2; + id1 = window.notify["visible"].connect(() => window_toggled(window)); + id2 = window_removed.connect((removed) => { + if (removed == window) { + window.disconnect(id1); + this.disconnect(id2); + } + }); + }); + + shutdown.connect(() => { try { quit(); } catch(Error err) {} }); + Unix.signal_add(1, () => { try { quit(); } catch(Error err) {} }, Priority.HIGH); + Unix.signal_add(2, () => { try { quit(); } catch(Error err) {} }, Priority.HIGH); + Unix.signal_add(15, () => { try { quit(); } catch(Error err) {} }, Priority.HIGH); + } +} diff --git a/core/src/config.vala.in b/lib/astal/gtk3/src/config.vala.in index 88bfe9c..88bfe9c 100644 --- a/core/src/config.vala.in +++ b/lib/astal/gtk3/src/config.vala.in diff --git a/core/src/idle-inhibit.c b/lib/astal/gtk3/src/idle-inhibit.c index 48f2471..48f2471 100644 --- a/core/src/idle-inhibit.c +++ b/lib/astal/gtk3/src/idle-inhibit.c diff --git a/core/src/idle-inhibit.h b/lib/astal/gtk3/src/idle-inhibit.h index 5e9a3ab..5e9a3ab 100644 --- a/core/src/idle-inhibit.h +++ b/lib/astal/gtk3/src/idle-inhibit.h diff --git a/core/src/meson.build b/lib/astal/gtk3/src/meson.build index b5adda2..bf8f72a 100644 --- a/core/src/meson.build +++ b/lib/astal/gtk3/src/meson.build @@ -18,6 +18,7 @@ config = configure_file( ) pkgconfig_deps = [ + dependency('astal-io-0.1'), dependency('glib-2.0'), dependency('gio-unix-2.0'), dependency('gobject-2.0'), @@ -30,7 +31,6 @@ pkgconfig_deps = [ deps = pkgconfig_deps + meson.get_compiler('c').find_library('m') - wayland_protos = dependency('wayland-protocols') wayland_scanner = find_program('wayland-scanner') @@ -49,7 +49,7 @@ gen_private_code = generator( ) protocols = [ - join_paths(wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml') + join_paths(wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'), ] client_protocol_srcs = [] @@ -60,8 +60,7 @@ foreach protocol : protocols client_protocol_srcs += [client_header, code] endforeach -sources = [ - config, +vala_sources = [config] + files( 'widget/box.vala', 'widget/button.vala', 'widget/centerbox.vala', @@ -76,61 +75,71 @@ sources = [ 'widget/stack.vala', 'widget/widget.vala', 'widget/window.vala', - 'astal.vala', - 'file.vala', - 'process.vala', - 'time.vala', - 'variable.vala', - 'idle-inhibit.h', + 'application.vala', 'idle-inhibit.c', -] + client_protocol_srcs +) -if get_option('lib') - lib = library( - meson.project_name(), - sources, - dependencies: deps, - vala_args: ['--pkg', 'AstalInhibitManager'], - vala_header: meson.project_name() + '.h', - vala_vapi: meson.project_name() + '-' + api_version + '.vapi', - vala_gir: gir, - version: meson.project_version(), - install: true, - install_dir: [true, true, true, true], - ) - - import('pkgconfig').generate( - lib, - name: meson.project_name(), - filebase: meson.project_name() + '-' + api_version, - version: meson.project_version(), - subdirs: meson.project_name(), - requires: pkgconfig_deps, - install_dir: libdir / 'pkgconfig', - ) - - custom_target( - typelib, - command: [ - find_program('g-ir-compiler'), - '--output', '@OUTPUT@', - '--shared-library', libdir / '@PLAINNAME@', - meson.current_build_dir() / gir, - ], - input: lib, - output: typelib, - depends: lib, - install: true, - install_dir: libdir / 'girepository-1.0', - ) -endif - -if get_option('cli') - executable( +sources = vala_sources + client_protocol_srcs + files( + 'idle-inhibit.h', +) + +lib = library( + meson.project_name(), + sources, + dependencies: deps, + vala_args: ['--vapi-comments', '--pkg', 'AstalInhibitManager'], + vala_header: meson.project_name() + '.h', + vala_vapi: meson.project_name() + '-' + api_version + '.vapi', + version: meson.project_version(), + install: true, + install_dir: [true, true, true], +) + +pkgs = [] +foreach dep : pkgconfig_deps + pkgs += ['--pkg=' + dep.name()] +endforeach + +gir_tgt = custom_target( + gir, + command: [ + find_program('python3'), + girpy, meson.project_name(), - ['cli.vala', sources], - vala_args: ['--pkg', 'AstalInhibitManager'], - dependencies: deps, - install: true, - ) -endif + gir + ':src/' + gir, + ] + + pkgs + + vala_sources + + [meson.project_source_root() / 'src' / 'vapi' / 'AstalInhibitManager.vapi'], + + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', +) + +custom_target( + typelib, + command: [ + find_program('g-ir-compiler'), + '--output', '@OUTPUT@', + '--shared-library', libdir / '@PLAINNAME@', + meson.current_build_dir() / gir, + ], + input: lib, + output: typelib, + depends: [lib, gir_tgt], + install: true, + install_dir: libdir / 'girepository-1.0', +) + +import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: pkgconfig_deps, + install_dir: libdir / 'pkgconfig', +) diff --git a/core/src/vapi/AstalInhibitManager.vapi b/lib/astal/gtk3/src/vapi/AstalInhibitManager.vapi index 6232a3c..b2b3b34 100644 --- a/core/src/vapi/AstalInhibitManager.vapi +++ b/lib/astal/gtk3/src/vapi/AstalInhibitManager.vapi @@ -5,9 +5,8 @@ namespace Astal { public static unowned InhibitManager? get_default(); public Inhibitor inhibit (Gtk.Window window); } - + [CCode (cheader_filename = "idle-inhibit.h", free_function = "zwp_idle_inhibitor_v1_destroy")] [Compact] - public class Inhibitor { - } + public class Inhibitor { } } diff --git a/core/src/widget/box.vala b/lib/astal/gtk3/src/widget/box.vala index 943c821..d049161 100644 --- a/core/src/widget/box.vala +++ b/lib/astal/gtk3/src/widget/box.vala @@ -1,5 +1,7 @@ -namespace Astal { -public class Box : Gtk.Box { +public class Astal.Box : Gtk.Box { + /** + * Corresponds to [[email protected] :orientation]. + */ [CCode (notify = false)] public bool vertical { get { return orientation == Gtk.Orientation.VERTICAL; } @@ -48,15 +50,4 @@ public class Box : Gtk.Box { this.vertical = vertical; _set_children(children); } - - public Box.newh(List<weak Gtk.Widget> children) { - this.vertical = false; - _set_children(children); - } - - public Box.newv(List<weak Gtk.Widget> children) { - this.vertical = true; - _set_children(children); - } -} } diff --git a/core/src/widget/button.vala b/lib/astal/gtk3/src/widget/button.vala index ad60da1..2d3095a 100644 --- a/core/src/widget/button.vala +++ b/lib/astal/gtk3/src/widget/button.vala @@ -1,5 +1,10 @@ -namespace Astal { -public class Button : Gtk.Button { +/** + * This button has no extra functionality on top if its base [[email protected]] class. + * + * The purpose of this Button subclass is to have a destructable + * struct as the argument in GJS event handlers. + */ +public class Astal.Button : Gtk.Button { public signal void hover (HoverEvent event); public signal void hover_lost (HoverEvent event); public signal void click (ClickEvent event); @@ -32,7 +37,7 @@ public class Button : Gtk.Button { } } -public enum MouseButton { +public enum Astal.MouseButton { PRIMARY = 1, MIDDLE = 2, SECONDARY = 3, @@ -40,10 +45,10 @@ public enum MouseButton { FORWARD = 5, } -// these structs are here because gjs converts every event -// into a union Gdk.Event, which cannot be destructured -// and are not as convinent to work with as a struct -public struct ClickEvent { +/** + * Struct for [[email protected]] + */ +public struct Astal.ClickEvent { bool release; uint time; double x; @@ -60,7 +65,10 @@ public struct ClickEvent { } } -public struct HoverEvent { +/** + * Struct for [[email protected]] + */ +public struct Astal.HoverEvent { bool lost; uint time; double x; @@ -79,7 +87,10 @@ public struct HoverEvent { } } -public struct ScrollEvent { +/** + * Struct for [[email protected]] + */ +public struct Astal.ScrollEvent { uint time; double x; double y; @@ -98,4 +109,3 @@ public struct ScrollEvent { this.delta_y = event.delta_y; } } -} diff --git a/core/src/widget/centerbox.vala b/lib/astal/gtk3/src/widget/centerbox.vala index 0588828..d74a2c4 100644 --- a/core/src/widget/centerbox.vala +++ b/lib/astal/gtk3/src/widget/centerbox.vala @@ -1,5 +1,7 @@ -namespace Astal { -public class CenterBox : Gtk.Box { +public class Astal.CenterBox : Gtk.Box { + /** + * Corresponds to [[email protected] :orientation]. + */ [CCode (notify = false)] public bool vertical { get { return orientation == Gtk.Orientation.VERTICAL; } @@ -51,4 +53,3 @@ public class CenterBox : Gtk.Box { } } } -} diff --git a/core/src/widget/circularprogress.vala b/lib/astal/gtk3/src/widget/circularprogress.vala index 4e1410d..a3ecdf1 100644 --- a/core/src/widget/circularprogress.vala +++ b/lib/astal/gtk3/src/widget/circularprogress.vala @@ -1,9 +1,34 @@ -namespace Astal { -public class CircularProgress : Gtk.Bin { +/** + * CircularProgress is a subclass of [[email protected]] which provides a circular progress bar + * with customizable properties such as starting and ending points, + * progress value, and visual features like rounded ends and inversion of progress direction. + */ +public class Astal.CircularProgress : Gtk.Bin { + /** + * The starting point of the progress circle, + * where 0 represents 3 o'clock position or 0° degrees and 1 represents 360°. + */ public double start_at { get; set; } + + /** + * The cutoff point of the background color of the progress circle. + */ public double end_at { get; set; } + + /** + * The value which determines the arc of the drawn foreground color. + * Should be a value between 0 and 1. + */ public double value { get; set; } + + /** + * Inverts the progress direction, making it draw counterclockwise. + */ public bool inverted { get; set; } + + /** + * Renders rounded ends at both the start and the end of the progress bar. + */ public bool rounded { get; set; } construct { @@ -179,4 +204,3 @@ public class CircularProgress : Gtk.Bin { return true; } } -} diff --git a/core/src/widget/eventbox.vala b/lib/astal/gtk3/src/widget/eventbox.vala index 6b715cc..0b588e9 100644 --- a/core/src/widget/eventbox.vala +++ b/lib/astal/gtk3/src/widget/eventbox.vala @@ -1,5 +1,10 @@ -namespace Astal { -public class EventBox : Gtk.EventBox { +/** + * EventBox is a [[email protected]] subclass which is meant to fix an issue with its + * [[email protected]::enter_notify_event] and [[email protected]::leave_notify_event] when nesting EventBoxes + * + * Its css selector is `eventbox`. + */ +public class Astal.EventBox : Gtk.EventBox { public signal void hover (HoverEvent event); public signal void hover_lost (HoverEvent event); public signal void click (ClickEvent event); @@ -50,7 +55,10 @@ public class EventBox : Gtk.EventBox { } } -public struct MotionEvent { +/** + * Struct for [[email protected]] + */ +public struct Astal.MotionEvent { uint time; double x; double y; @@ -63,4 +71,3 @@ public struct MotionEvent { this.modifier = event.state; } } -} diff --git a/core/src/widget/icon.vala b/lib/astal/gtk3/src/widget/icon.vala index 4f1c7f1..9a20359 100644 --- a/core/src/widget/icon.vala +++ b/lib/astal/gtk3/src/widget/icon.vala @@ -1,16 +1,25 @@ -namespace Astal { -public Gtk.IconInfo? lookup_icon(string icon) { - var theme = Gtk.IconTheme.get_default(); - return theme.lookup_icon(icon, 16, Gtk.IconLookupFlags.USE_BUILTIN); -} - -public class Icon : Gtk.Image { +/** + * [[email protected]] subclass meant to be used only for icons. + * + * It's size is calculated from `font-size` css property. + * Its css selector is `icon`. + */ +public class Astal.Icon : Gtk.Image { private IconType type = IconType.NAMED; private double size { get; set; default = 14; } public new Gdk.Pixbuf pixbuf { get; set; } + public GLib.Icon g_icon { get; set; } + + /** + * Either a named icon or a path to a file. + */ public string icon { get; set; default = ""; } - public GLib.Icon g_icon {get; set;} + + public static Gtk.IconInfo? lookup_icon(string icon) { + var theme = Gtk.IconTheme.get_default(); + return theme.lookup_icon(icon, 16, Gtk.IconLookupFlags.USE_BUILTIN); + } private async void display_icon() { switch(type) { @@ -98,10 +107,9 @@ public class Icon : Gtk.Image { } } -private enum IconType { +private enum Astal.IconType { NAMED, FILE, PIXBUF, GICON, } -} diff --git a/core/src/widget/label.vala b/lib/astal/gtk3/src/widget/label.vala index 4063b6f..899cba9 100644 --- a/core/src/widget/label.vala +++ b/lib/astal/gtk3/src/widget/label.vala @@ -1,11 +1,17 @@ using Pango; public class Astal.Label : Gtk.Label { + /** + * Shortcut for setting [[email protected]:ellipsize] to [[email protected]] + */ public bool truncate { set { ellipsize = value ? EllipsizeMode.END : EllipsizeMode.NONE; } get { return ellipsize == EllipsizeMode.END; } } + /** + * Shortcut for setting [[email protected]:justify] to [[email protected]] + */ public new bool justify_fill { set { justify = value ? Gtk.Justification.FILL : Gtk.Justification.LEFT; } get { return justify == Gtk.Justification.FILL; } diff --git a/core/src/widget/levelbar.vala b/lib/astal/gtk3/src/widget/levelbar.vala index 1db2cc7..3e98afb 100644 --- a/core/src/widget/levelbar.vala +++ b/lib/astal/gtk3/src/widget/levelbar.vala @@ -1,5 +1,7 @@ -namespace Astal { -public class LevelBar : Gtk.LevelBar { +public class Astal.LevelBar : Gtk.LevelBar { + /** + * Corresponds to [[email protected] :orientation]. + */ [CCode (notify = false)] public bool vertical { get { return orientation == Gtk.Orientation.VERTICAL; } @@ -12,4 +14,3 @@ public class LevelBar : Gtk.LevelBar { }); } } -} diff --git a/core/src/widget/overlay.vala b/lib/astal/gtk3/src/widget/overlay.vala index 207aaa7..ed5f03b 100644 --- a/core/src/widget/overlay.vala +++ b/lib/astal/gtk3/src/widget/overlay.vala @@ -1,7 +1,11 @@ -namespace Astal { -public class Overlay : Gtk.Overlay { +public class Astal.Overlay : Gtk.Overlay { public bool pass_through { get; set; } + /** + * First [[email protected]:overlays] element. + * + * WARNING: setting this value will remove every overlay but the first. + */ public Gtk.Widget? overlay { get { return overlays.nth_data(0); } set { @@ -15,6 +19,9 @@ public class Overlay : Gtk.Overlay { } } + /** + * Sets the overlays of this Overlay. [[email protected]_overlay]. + */ public List<weak Gtk.Widget> overlays { owned get { return get_children(); } set { @@ -56,4 +63,3 @@ public class Overlay : Gtk.Overlay { set_overlay_pass_through(widget, pass_through); } } -} diff --git a/core/src/widget/scrollable.vala b/lib/astal/gtk3/src/widget/scrollable.vala index 1a0e081..57a440c 100644 --- a/core/src/widget/scrollable.vala +++ b/lib/astal/gtk3/src/widget/scrollable.vala @@ -1,5 +1,12 @@ -namespace Astal { -public class Scrollable : Gtk.ScrolledWindow { +/** + * Subclass of [[email protected]] which has its policy default to + * [[email protected]]. + * + * Its css selector is `scrollable`. + * Its child getter returns the child of the inner + * [[email protected]], instead of the viewport. + */ +public class Astal.Scrollable : Gtk.ScrolledWindow { private Gtk.PolicyType _hscroll = Gtk.PolicyType.AUTOMATIC; private Gtk.PolicyType _vscroll = Gtk.PolicyType.AUTOMATIC; @@ -39,4 +46,3 @@ public class Scrollable : Gtk.ScrolledWindow { return ch; } } -} diff --git a/core/src/widget/slider.vala b/lib/astal/gtk3/src/widget/slider.vala index 16e6bd2..97cfb69 100644 --- a/core/src/widget/slider.vala +++ b/lib/astal/gtk3/src/widget/slider.vala @@ -1,13 +1,20 @@ -namespace Astal { -public class Slider : Gtk.Scale { +/** + * Subclass of [[email protected]] which adds a signal and property for the drag state. + */ +public class Astal.Slider : Gtk.Scale { + /** + * Corresponds to [[email protected] :orientation]. + */ [CCode (notify = false)] public bool vertical { get { return orientation == Gtk.Orientation.VERTICAL; } set { orientation = value ? Gtk.Orientation.VERTICAL : Gtk.Orientation.HORIZONTAL; } } - // emitted when the user drags the slider - public signal void dragged (); + /** + * Emitted when the user drags the slider or uses keyboard arrows and its value changes. + */ + public signal void dragged(); construct { draw_value = false; @@ -46,23 +53,38 @@ public class Slider : Gtk.Scale { }); } + /** + * `true` when the user drags the slider or uses keyboard arrows. + */ public bool dragging { get; private set; } + /** + * Value of this slider. Defaults to `0`. + */ public double value { get { return adjustment.value; } set { if (!dragging) adjustment.value = value; } } + /** + * Minimum possible value of this slider. Defaults to `0`. + */ public double min { get { return adjustment.lower; } set { adjustment.lower = value; } } + /** + * Maximum possible value of this slider. Defaults to `1`. + */ public double max { get { return adjustment.upper; } set { adjustment.upper = value; } } + /** + * Size of step increments. Defaults to `0.05`. + */ public double step { get { return adjustment.step_increment; } set { adjustment.step_increment = value; } @@ -70,4 +92,3 @@ public class Slider : Gtk.Scale { // TODO: marks } -} diff --git a/core/src/widget/stack.vala b/lib/astal/gtk3/src/widget/stack.vala index 02f9959..4e856a6 100644 --- a/core/src/widget/stack.vala +++ b/lib/astal/gtk3/src/widget/stack.vala @@ -1,4 +1,12 @@ +/** + * Subclass of [[email protected]] that has a children setter which + * invokes [[email protected]_named] with the child's [[email protected]:name] property. + */ public class Astal.Stack : Gtk.Stack { + /** + * Same as [[email protected]:visible-child-name]. + */ + [CCode (notify = false)] public string shown { get { return visible_child_name; } set { visible_child_name = value; } @@ -23,4 +31,10 @@ public class Astal.Stack : Gtk.Stack { } } } + + construct { + notify["visible_child_name"].connect(() => { + notify_property("shown"); + }); + } } diff --git a/core/src/widget/widget.vala b/lib/astal/gtk3/src/widget/widget.vala index 2506bc8..2506bc8 100644 --- a/core/src/widget/widget.vala +++ b/lib/astal/gtk3/src/widget/widget.vala diff --git a/core/src/widget/window.vala b/lib/astal/gtk3/src/widget/window.vala index f1a377f..9287200 100644 --- a/core/src/widget/window.vala +++ b/lib/astal/gtk3/src/widget/window.vala @@ -1,34 +1,52 @@ using GtkLayerShell; -namespace Astal { -public enum WindowAnchor { - NONE = 0, - TOP = 1, - RIGHT = 2, - LEFT = 4, - BOTTOM = 8, +[Flags] +public enum Astal.WindowAnchor { + NONE, + TOP, + RIGHT, + LEFT, + BOTTOM, } -public enum Exclusivity { +public enum Astal.Exclusivity { NORMAL, + /** + * Request the compositor to allocate space for this window. + */ EXCLUSIVE, + /** + * Request the compositor to stack layers on top of each other. + */ IGNORE, } -public enum Layer { +public enum Astal.Layer { BACKGROUND = 0, // GtkLayerShell.Layer.BACKGROUND BOTTOM = 1, // GtkLayerShell.Layer.BOTTOM TOP = 2, // GtkLayerShell.Layer.TOP OVERLAY = 3, // GtkLayerShell.Layer.OVERLAY } -public enum Keymode { +public enum Astal.Keymode { + /** + * Window should not receive keyboard events. + */ NONE = 0, // GtkLayerShell.KeyboardMode.NONE - ON_DEMAND = 1, // GtkLayerShell.KeyboardMode.ON_DEMAND - EXCLUSIVE = 2, // GtkLayerShell.KeyboardMode.EXCLUSIVE + /** + * Window should have exclusive focus if it is on the top or overlay layer. + */ + EXCLUSIVE = 1, // GtkLayerShell.KeyboardMode.EXCLUSIVE + /** + * Focus and Unfocues the window as needed. + */ + ON_DEMAND = 2, // GtkLayerShell.KeyboardMode.ON_DEMAND } -public class Window : Gtk.Window { +/** + * Subclass of [[email protected]] which integrates GtkLayerShell as class fields. + */ +public class Astal.Window : Gtk.Window { private static bool check(string action) { if (!is_supported()) { critical(@"can not $action on window: layer shell not supported"); @@ -45,12 +63,18 @@ public class Window : Gtk.Window { if (check("initialize layer shell")) return; + // If the window has no size allocatoted when it gets mapped. + // It won't show up later either when it size changes by adding children. height_request = 1; width_request = 1; + init_for_window(this); inhibit_manager = InhibitManager.get_default(); } + /** + * When `true` it will permit inhibiting the idle behavior such as screen blanking, locking, and screensaving. + */ public bool inhibit { set { if (inhibit_manager == null) { @@ -75,12 +99,21 @@ public class Window : Gtk.Window { } } + /** + * Namespace of this window. This can be used to target the layer in compositor rules. + */ public string namespace { get { return get_namespace(this); } set { set_namespace(this, value); } } - public int anchor { + /** + * Edges to anchor the window to. + * + * If two perpendicular edges are anchored, the surface will be anchored to that corner. + * If two opposite edges are anchored, the window will be stretched across the screen in that direction. + */ + public WindowAnchor anchor { set { if (check("set anchor")) return; @@ -108,6 +141,9 @@ public class Window : Gtk.Window { } } + /** + * Exclusivity of this window. + */ public Exclusivity exclusivity { set { if (check("set exclusivity")) @@ -136,6 +172,9 @@ public class Window : Gtk.Window { } } + /** + * Which layer to appear this window on. + */ public Layer layer { get { return (Layer)get_layer(this); } set { @@ -146,6 +185,9 @@ public class Window : Gtk.Window { } } + /** + * Keyboard mode of this window. + */ public Keymode keymode { get { return (Keymode)get_keyboard_mode(this); } set { @@ -156,6 +198,9 @@ public class Window : Gtk.Window { } } + /** + * Which monitor to appear this window on. + */ public Gdk.Monitor gdkmonitor { get { return get_monitor(this); } set { @@ -219,8 +264,9 @@ public class Window : Gtk.Window { } /** - * CAUTION: the id might not be the same mapped by the compositor - * to reset and let the compositor map it pass a negative number + * Which monitor to appear this window on. + * + * CAUTION: the id might not be the same mapped by the compositor. */ public int monitor { set { @@ -245,11 +291,3 @@ public class Window : Gtk.Window { } } } - -/** - * CAUTION: the id might not be the same mapped by the compositor - */ -public uint get_num_monitors() { - return Gdk.Display.get_default().get_n_monitors(); -} -} diff --git a/lib/astal/gtk3/version b/lib/astal/gtk3/version new file mode 100644 index 0000000..4a36342 --- /dev/null +++ b/lib/astal/gtk3/version @@ -0,0 +1 @@ +3.0.0 diff --git a/lib/astal/io/application.vala b/lib/astal/io/application.vala new file mode 100644 index 0000000..09b61b5 --- /dev/null +++ b/lib/astal/io/application.vala @@ -0,0 +1,186 @@ +namespace AstalIO { +public errordomain AppError { + NAME_OCCUPIED, + TAKEOVER_FAILED, +} + +/** + * This interface is used as a placeholder for the Astal Application class. + * It is not meant to be used by consumers. + */ +public interface Application : Object { + public abstract void quit() throws Error; + public abstract void inspector() throws Error; + public abstract void toggle_window(string window) throws Error; + + public abstract string instance_name { owned get; construct set; } + public abstract void acquire_socket() throws Error; + public virtual void request(string msg, SocketConnection conn) throws Error { + write_sock.begin(conn, @"missing response implementation on $instance_name"); + } +} + +/** + * Starts a [[email protected]] and binds `XDG_RUNTIME_DIR/astal/<instance_name>.sock`. + * This socket is then used by the astal cli. Not meant for public usage, but for [[email protected]_socket]. + */ +public SocketService acquire_socket(Application app, out string sock) throws Error { + var name = app.instance_name; + foreach (var instance in get_instances()) { + if (instance == name) { + throw new AppError.NAME_OCCUPIED(@"$name is occupied"); + } + } + + var rundir = Environment.get_user_runtime_dir(); + var dir = @"$rundir/astal"; + var path = @"$dir/$name.sock"; + sock = path; + + if (!FileUtils.test(dir, FileTest.IS_DIR)) { + File.new_for_path(path).make_directory_with_parents(null); + } + + if (FileUtils.test(path, FileTest.EXISTS)) { + try { + File.new_for_path(path).delete(null); + } catch (Error err) { + throw new AppError.TAKEOVER_FAILED("could not delete previous socket"); + } + } + + var service = new SocketService(); + service.add_address( + new UnixSocketAddress(path), + SocketType.STREAM, + SocketProtocol.DEFAULT, + null, + null + ); + + service.incoming.connect((conn) => { + read_sock.begin(conn, (_, res) => { + try { + string message = read_sock.end(res); + app.request(message != null ? message.strip() : "", conn); + } catch (Error err) { + critical(err.message); + } + }); + return false; + }); + + return service; +} + +/** + * Get a list of running Astal.Application instances. + * It is the equivalent of `astal --list`. + */ +public static List<string> get_instances() { + var list = new List<string>(); + var prefix = "io.Astal."; + + try { + DBusImpl dbus = Bus.get_proxy_sync( + BusType.SESSION, + "org.freedesktop.DBus", + "/org/freedesktop/DBus" + ); + + foreach (var busname in dbus.list_names()) { + if (busname.has_prefix(prefix)) + list.append(busname.replace(prefix, "")); + } + } catch (Error err) { + critical(err.message); + } + + return list; +} + +/** + * Quit an an Astal instances. + * It is the equivalent of `astal --quit -i instance`. + */ +public static void quit_instance(string instance) throws Error { + IApplication proxy = Bus.get_proxy_sync( + BusType.SESSION, + "io.Astal." + instance, + "/io/Astal/Application" + ); + + proxy.quit(); +} + +/** + * Open the Gtk debug tool of an an Astal instances. + * It is the equivalent of `astal --inspector -i instance`. + */ +public static void open_inspector(string instance) throws Error { + IApplication proxy = Bus.get_proxy_sync( + BusType.SESSION, + "io.Astal." + instance, + "/io/Astal/Application" + ); + + proxy.inspector(); +} + +/** + * Toggle a Window of an Astal instances. + * It is the equivalent of `astal -i instance --toggle window`. + */ +public static void toggle_window_by_name(string instance, string window) throws Error { + IApplication proxy = Bus.get_proxy_sync( + BusType.SESSION, + "io.Astal." + instance, + "/io/Astal/Application" + ); + + proxy.toggle_window(window); +} + +/** + * Send a message to an Astal instances. + * It is the equivalent of `astal -i instance content of the message`. + */ +public static string send_message(string instance, string msg) throws Error { + var rundir = Environment.get_user_runtime_dir(); + var socket_path = @"$rundir/astal/$instance.sock"; + var client = new SocketClient(); + + var conn = client.connect(new UnixSocketAddress(socket_path), null); + conn.output_stream.write(msg.concat("\x04").data); + + var stream = new DataInputStream(conn.input_stream); + return stream.read_upto("\x04", -1, null, null); +} + +/** + * Read the socket of an Astal.Application instance. + */ +public async string read_sock(SocketConnection conn) throws IOError { + var stream = new DataInputStream(conn.input_stream); + return yield stream.read_upto_async("\x04", -1, Priority.DEFAULT, null, null); +} + +/** + * Write the socket of an Astal.Application instance. + */ +public async void write_sock(SocketConnection conn, string response) throws IOError { + yield conn.output_stream.write_async(@"$response\x04".data, Priority.DEFAULT); +} + +[DBus (name="io.Astal.Application")] +private interface IApplication : DBusProxy { + public abstract void quit() throws GLib.Error; + public abstract void inspector() throws GLib.Error; + public abstract void toggle_window(string window) throws GLib.Error; +} + +[DBus (name="org.freedesktop.DBus")] +private interface DBusImpl : DBusProxy { + public abstract string[] list_names() throws Error; +} +} diff --git a/core/src/cli.vala b/lib/astal/io/cli.vala index 0b60cd1..f69cf0b 100644 --- a/core/src/cli.vala +++ b/lib/astal/io/cli.vala @@ -1,23 +1,29 @@ -private static bool version; -private static bool help; -private static bool list; -private static bool quit; -private static bool inspector; -private static string? toggle_window; -private static string? instance_name; +static bool version; +static bool help; +static bool list; +static bool quit; +static bool inspector; +static string? toggle_window; +static string? instance_name; -private const GLib.OptionEntry[] options = { +const OptionEntry[] options = { { "version", 'v', OptionFlags.NONE, OptionArg.NONE, ref version, null, null }, { "help", 'h', OptionFlags.NONE, OptionArg.NONE, ref help, null, null }, { "list", 'l', OptionFlags.NONE, OptionArg.NONE, ref list, null, null }, { "quit", 'q', OptionFlags.NONE, OptionArg.NONE, ref quit, null, null }, - { "quit", 'q', OptionFlags.NONE, OptionArg.NONE, ref quit, null, null }, { "inspector", 'I', OptionFlags.NONE, OptionArg.NONE, ref inspector, null, null }, { "toggle-window", 't', OptionFlags.NONE, OptionArg.STRING, ref toggle_window, null, null }, { "instance", 'i', OptionFlags.NONE, OptionArg.STRING, ref instance_name, null, null }, { null }, }; +int err(string msg) { + var red = "\x1b[31m"; + var r = "\x1b[0m"; + printerr(@"$(red)error: $(r)$msg"); + return 1; +} + int main(string[] argv) { try { var opts = new OptionContext(); @@ -25,9 +31,8 @@ int main(string[] argv) { opts.set_help_enabled(false); opts.set_ignore_unknown_options(false); opts.parse(ref argv); - } catch (OptionError err) { - printerr (err.message); - return 1; + } catch (OptionError e) { + return err(e.message); } if (help) { @@ -46,7 +51,7 @@ int main(string[] argv) { } if (version) { - print(Astal.VERSION); + print(AstalIO.VERSION); return 0; } @@ -54,25 +59,31 @@ int main(string[] argv) { instance_name = "astal"; if (list) { - foreach (var name in Astal.Application.get_instances()) - stdout.printf("%s\n", name); + foreach (var name in AstalIO.get_instances()) + print(@"$name\n"); return 0; } - if (quit) { - Astal.Application.quit_instance(instance_name); - return 0; - } + try { + if (quit) { + AstalIO.quit_instance(instance_name); + return 0; + } - if (inspector) { - Astal.Application.open_inspector(instance_name); - return 0; - } + if (inspector) { + AstalIO.open_inspector(instance_name); + return 0; + } - if (toggle_window != null) { - Astal.Application.toggle_window_by_name(instance_name, toggle_window); - return 0; + if (toggle_window != null) { + AstalIO.toggle_window_by_name(instance_name, toggle_window); + return 0; + } + } catch (DBusError.SERVICE_UNKNOWN e) { + return err(@"there is no \"$instance_name\" instance runnning"); + } catch (Error e) { + return err(e.message); } var request = ""; @@ -80,8 +91,14 @@ int main(string[] argv) { request = request.concat(" ", argv[i]); } - var reply = Astal.Application.send_message(instance_name, request); - print("%s\n", reply); + try { + var reply = AstalIO.send_message(instance_name, request); + print("%s\n", reply); + } catch (IOError.NOT_FOUND e) { + return err(@"there is no \"$instance_name\" instance runnning"); + } catch (Error e) { + return err(e.message); + } return 0; } diff --git a/lib/astal/io/config.vala.in b/lib/astal/io/config.vala.in new file mode 100644 index 0000000..fe1e450 --- /dev/null +++ b/lib/astal/io/config.vala.in @@ -0,0 +1,6 @@ +namespace AstalIO { + public const int MAJOR_VERSION = @MAJOR_VERSION@; + public const int MINOR_VERSION = @MINOR_VERSION@; + public const int MICRO_VERSION = @MICRO_VERSION@; + public const string VERSION = "@VERSION@"; +} diff --git a/core/src/file.vala b/lib/astal/io/file.vala index d8acccc..57b6dc0 100644 --- a/core/src/file.vala +++ b/lib/astal/io/file.vala @@ -1,4 +1,7 @@ -namespace Astal { +namespace AstalIO { +/** + * Read the contents of a file synchronously. + */ public string read_file(string path) { var str = ""; try { @@ -9,12 +12,18 @@ public string read_file(string path) { return str; } +/** + * Read the contents of a file asynchronously. + */ public async string read_file_async(string path) throws Error { uint8[] content; yield File.new_for_path(path).load_contents_async(null, out content, null); return (string)content; } +/** + * Write content to a file synchronously. + */ public void write_file(string path, string content) { try { FileUtils.set_contents(path, content); @@ -23,20 +32,28 @@ public void write_file(string path, string content) { } } +/** + * Write content to a file asynchronously. + */ public async void write_file_async(string path, string content) throws Error { yield File.new_for_path(path).replace_contents_async( content.data, null, false, - GLib.FileCreateFlags.REPLACE_DESTINATION, + FileCreateFlags.REPLACE_DESTINATION, null, null); } +/** + * Monitor a file for changes. If the path is a directory, monitor it recursively. + * The callback will be called passed two parameters: the path of the file + * that changed and an [[email protected]] indicating the reason. + */ public FileMonitor? monitor_file(string path, Closure callback) { try { var file = File.new_for_path(path); - var mon = file.monitor(GLib.FileMonitorFlags.NONE); + var mon = file.monitor(FileMonitorFlags.NONE); mon.changed.connect((file, _file, event) => { var f = Value(Type.STRING); diff --git a/lib/astal/io/gir.py b/lib/astal/io/gir.py new file mode 100644 index 0000000..9ef680f --- /dev/null +++ b/lib/astal/io/gir.py @@ -0,0 +1,58 @@ +""" +Vala's generated gir does not contain comments, +so we use valadoc to generate them. However, they are formatted +for valadoc and not gi-docgen so we need to fix it. +""" + +import xml.etree.ElementTree as ET +import html +import sys +import subprocess + + +def fix_gir(name: str, gir: str, out: str): + namespaces = { + "": "http://www.gtk.org/introspection/core/1.0", + "c": "http://www.gtk.org/introspection/c/1.0", + "glib": "http://www.gtk.org/introspection/glib/1.0", + } + for prefix, uri in namespaces.items(): + ET.register_namespace(prefix, uri) + + tree = ET.parse(gir) + root = tree.getroot() + + for doc in root.findall(".//doc", namespaces): + if doc.text: + doc.text = ( + html.unescape(doc.text).replace("<para>", "").replace("</para>", "") + ) + + if (inc := root.find("c:include", namespaces)) is not None: + inc.set("name", f"{name}.h") + else: + print("no c:include tag found", file=sys.stderr) + exit(1) + + tree.write(out, encoding="utf-8", xml_declaration=True) + + +def valadoc(name: str, gir: str, args: list[str]): + cmd = ["valadoc", "-o", "docs", "--package-name", name, "--gir", gir, *args] + try: + subprocess.run(cmd, check=True, text=True, capture_output=True) + except subprocess.CalledProcessError as e: + print(e.stderr, file=sys.stderr) + exit(1) + + +if __name__ == "__main__": + name = sys.argv[1] + in_out = sys.argv[2].split(":") + args = sys.argv[3:] + + gir = in_out[0] + out = in_out[1] if len(in_out) > 1 else gir + + valadoc(name, gir, args) + fix_gir(name, gir, out) diff --git a/lib/astal/io/meson.build b/lib/astal/io/meson.build new file mode 100644 index 0000000..023dece --- /dev/null +++ b/lib/astal/io/meson.build @@ -0,0 +1,106 @@ +project( + 'astal-io', + 'vala', + 'c', + version: run_command('cat', join_paths(meson.project_source_root(), 'version')).stdout().strip(), + meson_version: '>= 0.62.0', + default_options: [ + 'warning_level=2', + 'werror=false', + 'c_std=gnu11', + ], +) + +version_split = meson.project_version().split('.') +api_version = version_split[0] + '.' + version_split[1] +gir = 'AstalIO-' + api_version + '.gir' +typelib = 'AstalIO-' + api_version + '.typelib' +libdir = get_option('prefix') / get_option('libdir') +pkgdatadir = get_option('prefix') / get_option('datadir') / 'astal' + +config = configure_file( + input: 'config.vala.in', + output: 'config.vala', + configuration: { + 'VERSION': meson.project_version(), + 'MAJOR_VERSION': version_split[0], + 'MINOR_VERSION': version_split[1], + 'MICRO_VERSION': version_split[2], + }, +) + +deps = [ + dependency('glib-2.0'), + dependency('gio-unix-2.0'), + dependency('gobject-2.0'), + dependency('gio-2.0'), +] + +sources = [config] + files( + 'application.vala', + 'file.vala', + 'process.vala', + 'time.vala', + 'variable.vala', +) + +lib = library( + meson.project_name(), + sources, + dependencies: deps, + vala_args: ['--vapi-comments'], + vala_header: meson.project_name() + '.h', + vala_vapi: meson.project_name() + '-' + api_version + '.vapi', + version: meson.project_version(), + install: true, + install_dir: [true, true, true], +) + +pkgs = [] +foreach dep : deps + pkgs += ['--pkg=' + dep.name()] +endforeach + +gir_tgt = custom_target( + gir, + command: [find_program('python3'), files('gir.py'), meson.project_name(), gir] + + pkgs + + sources, + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', +) + +custom_target( + typelib, + command: [ + find_program('g-ir-compiler'), + '--output', '@OUTPUT@', + '--shared-library', get_option('prefix') / get_option('libdir') / '@PLAINNAME@', + meson.current_build_dir() / gir, + ], + input: lib, + output: typelib, + depends: [lib, gir_tgt], + install: true, + install_dir: get_option('libdir') / 'girepository-1.0', +) + +import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: deps, + install_dir: get_option('libdir') / 'pkgconfig', +) + +executable( + 'astal', + ['cli.vala', sources], + dependencies: deps, + install: true, +) diff --git a/core/src/process.vala b/lib/astal/io/process.vala index 073fe93..cfd05b9 100644 --- a/core/src/process.vala +++ b/lib/astal/io/process.vala @@ -1,4 +1,7 @@ -public class Astal.Process : Object { +/** + * `Process` provides shortcuts for [[email protected]] with sane defaults. + */ +public class AstalIO.Process : Object { private void read_stream(DataInputStream stream, bool err) { stream.read_line_utf8_async.begin(Priority.DEFAULT, null, (_, res) => { try { @@ -23,34 +26,56 @@ public class Astal.Process : Object { private Subprocess process; public string[] argv { construct; get; } + + /** + * When the underlying subprocess writes to its stdout + * this signal is emitted with that line. + */ public signal void stdout (string out); + + /** + * When the underlying subprocess writes to its stderr + * this signal is emitted with that line. + */ public signal void stderr (string err); + /** + * Force quit the subprocess. + */ public void kill() { process.force_exit(); } + /** + * Send a signal to the subprocess. + */ public void signal(int signal_num) { process.send_signal(signal_num); } + /** + * Write a line to the subprocess' stdin synchronously. + */ public void write(string in) throws Error { in_stream.put_string(in); } - public void write_async(string in) { - in_stream.write_all_async.begin( - in.data, - Priority.DEFAULT, null, (_, res) => { - try { - in_stream.write_all_async.end(res, null); - } catch (Error err) { - printerr("%s\n", err.message); - } - } - ); + /** + * Write a line to the subprocess' stdin asynchronously. + */ + public async void write_async(string in) { + try { + yield in_stream.write_all_async(in.data, in.data.length, null, null); + } catch (Error err) { + printerr("%s\n", err.message); + } } + /** + * Start a new subprocess with the given command. + * + * The first element of the vector is executed with the remaining elements as the argument list. + */ public Process.subprocessv(string[] cmd) throws Error { Object(argv: cmd); process = new Subprocess.newv(cmd, @@ -65,12 +90,22 @@ public class Astal.Process : Object { read_stream(err_stream, false); } + /** + * Start a new subprocess with the given command + * which is parsed using [[email protected]_parse_argv]. + */ public static Process subprocess(string cmd) throws Error { string[] argv; Shell.parse_argv(cmd, out argv); return new Process.subprocessv(argv); } + /** + * Execute a command synchronously. + * The first element of the vector is executed with the remaining elements as the argument list. + * + * @return stdout of the subprocess + */ public static string execv(string[] cmd) throws Error { var process = new Subprocess.newv( cmd, @@ -88,12 +123,24 @@ public class Astal.Process : Object { throw new IOError.FAILED(err_str.strip()); } + /** + * Execute a command synchronously. + * The command is parsed using [[email protected]_parse_argv]. + * + * @return stdout of the subprocess + */ public static string exec(string cmd) throws Error { string[] argv; Shell.parse_argv(cmd, out argv); return Process.execv(argv); } + /** + * Execute a command asynchronously. + * The first element of the vector is executed with the remaining elements as the argument list. + * + * @return stdout of the subprocess + */ public static async string exec_asyncv(string[] cmd) throws Error { var process = new Subprocess.newv( cmd, @@ -111,6 +158,12 @@ public class Astal.Process : Object { throw new IOError.FAILED(err_str.strip()); } + /** + * Execute a command asynchronously. + * The command is parsed using [[email protected]_parse_argv]. + * + * @return stdout of the subprocess + */ public static async string exec_async(string cmd) throws Error { string[] argv; Shell.parse_argv(cmd, out argv); diff --git a/core/src/time.vala b/lib/astal/io/time.vala index 4034c04..a799f2b 100644 --- a/core/src/time.vala +++ b/lib/astal/io/time.vala @@ -1,11 +1,21 @@ -namespace Astal { -public class Time : Object { - public signal void now (); - public signal void cancelled (); +/** + * `Time` provides shortcuts for GLib timeout functions. + */ +public class AstalIO.Time : Object { private Cancellable cancellable; private uint timeout_id; private bool fulfilled = false; + /** + * Emitted when the timer ticks. + */ + public signal void now (); + + /** + * Emitted when the timere is cancelled. + */ + public signal void cancelled (); + construct { cancellable = new Cancellable(); cancellable.cancelled.connect(() => { @@ -27,6 +37,9 @@ public class Time : Object { }); } + /** + * Start an interval timer with default Priority. + */ public Time.interval_prio(uint interval, int prio = Priority.DEFAULT, Closure? fn) { connect_closure(fn); Idle.add_once(() => now()); @@ -36,6 +49,9 @@ public class Time : Object { }, prio); } + /** + * Start a timeout timer with default Priority. + */ public Time.timeout_prio(uint timeout, int prio = Priority.DEFAULT, Closure? fn) { connect_closure(fn); timeout_id = Timeout.add(timeout, () => { @@ -45,6 +61,9 @@ public class Time : Object { }, prio); } + /** + * Start an idle timer with default priority. + */ public Time.idle_prio(int prio = Priority.DEFAULT_IDLE, Closure? fn) { connect_closure(fn); timeout_id = Idle.add(() => { @@ -54,20 +73,39 @@ public class Time : Object { }, prio); } + /** + * Start an interval timer. Ticks immediately then every `interval` milliseconds. + * + * @param interval Tick every milliseconds. + * @param fn Optional callback. + */ public static Time interval(uint interval, Closure? fn) { return new Time.interval_prio(interval, Priority.DEFAULT, fn); } + /** + * Start a timeout timer which ticks after `timeout` milliseconds. + * + * @param timeout Tick after milliseconds. + * @param fn Optional callback. + */ public static Time timeout(uint timeout, Closure? fn) { return new Time.timeout_prio(timeout, Priority.DEFAULT, fn); } + /** + * Start a timer which will tick when there are no higher priority tasks pending. + * + * @param fn Optional callback. + */ public static Time idle(Closure? fn) { return new Time.idle_prio(Priority.DEFAULT_IDLE, fn); } + /** + * Cancel timer and emit [[email protected]::cancelled] + */ public void cancel() { cancellable.cancel(); } } -} diff --git a/core/src/variable.vala b/lib/astal/io/variable.vala index c7edb16..312a27a 100644 --- a/core/src/variable.vala +++ b/lib/astal/io/variable.vala @@ -1,5 +1,8 @@ -namespace Astal { -public class VariableBase : Object { +/* + * Base class for [[email protected]] mainly meant to be used + * in higher level language bindings such as Lua and Gjs. + */ +public class AstalIO.VariableBase : Object { public signal void changed (); public signal void dropped (); public signal void error (string err); @@ -14,7 +17,7 @@ public class VariableBase : Object { } } -public class Variable : VariableBase { +public class AstalIO.Variable : VariableBase { public Value value { owned get; set; } private uint poll_id = 0; @@ -193,4 +196,3 @@ public class Variable : VariableBase { dropped(); } } -} diff --git a/core/version b/lib/astal/io/version index 6e8bf73..6e8bf73 100644 --- a/core/version +++ b/lib/astal/io/version diff --git a/lib/battery/device.vala b/lib/battery/device.vala index a39d789..db69574 100644 --- a/lib/battery/device.vala +++ b/lib/battery/device.vala @@ -1,70 +1,250 @@ namespace AstalBattery { -public Device get_default() { - return Device.get_default(); + /** Get the DisplayDevice. */ + public Device get_default() { + return Device.get_default(); + } } -public class Device : Object { +/** + * Client for a UPower [[https://upower.freedesktop.org/docs/Device.html|device]]. + */ +public class AstalBattery.Device : Object { private static Device display_device; + + /** Get the DisplayDevice. */ public static Device? get_default() { - if (display_device != null) + if (display_device != null) { return display_device; + } try { - display_device = new Device("/org/freedesktop/UPower/devices/DisplayDevice"); - + display_device = new Device((ObjectPath)"/org/freedesktop/UPower/devices/DisplayDevice"); return display_device; } catch (Error error) { critical(error.message); } + return null; } private IUPowerDevice proxy; - public Device(string path) throws Error { + public Device(ObjectPath path) throws Error { proxy = Bus.get_proxy_sync(BusType.SYSTEM, "org.freedesktop.UPower", path); proxy.g_properties_changed.connect(sync); sync(); } + /** + * If it is [[email protected]], you will need to verify that the + * property power-supply has the value `true` before considering it as a laptop battery. + * Otherwise it will likely be the battery for a device of an unknown type. + */ public Type device_type { get; private set; } + + /** + * Native path of the power source. This is the sysfs path, + * for example /sys/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT0. + * It is blank if the device is being driven by a user space driver. + */ public string native_path { owned get; private set; } + + /** Name of the vendor of the battery. */ public string vendor { owned get; private set; } + + /** Name of the model of this battery. */ public string model { owned get; private set; } + + /** Unique serial number of the battery. */ public string serial { owned get; private set; } + + /** + * The point in time (seconds since the Epoch) + * that data was read from the power source. + */ public uint64 update_time { get; private set; } + + /** + * If the power device is used to supply the system. + * This would be set `true` for laptop batteries and UPS devices, + * but set to `false` for wireless mice or PDAs. + */ public bool power_supply { get; private set; } - public bool has_history { get; private set; } - public bool has_statistics { get; private set; } + + /** If the power device has history. */ + // TODO: public bool has_history { get; private set; } + + /** If the power device has statistics. */ + // TODO: public bool has_statistics { get; private set; } + + /** + * Whether power is currently being provided through line power. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]_POWER]. + */ public bool online { get; private set; } + + /** + * Amount of energy (measured in Wh) currently available in the power source. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public double energy { get; private set; } + + /** + * Amount of energy (measured in Wh) in the power source when it's considered to be empty. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public double energy_empty { get; private set; } + + /** + * Amount of energy (measured in Wh) in the power source when it's considered full. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public double energy_full { get; private set; } + + /** + * Amount of energy (measured in Wh) the power source is designed to hold when it's considered full. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public double energy_full_design { get; private set; } + + /** + * Amount of energy being drained from the source, measured in W. + * If positive, the source is being discharged, if negative it's being charged. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public double energy_rate { get; private set; } + + /** Voltage in the Cell or being recorded by the meter. */ public double voltage { get; private set; } + + /** + * The number of charge cycles as defined by the TCO certification, + * or -1 if that value is unknown or not applicable. + */ public int charge_cycles { get; private set; } + + /** Luminosity being recorded by the meter. */ public double luminosity { get; private set; } + + /** + * Number of seconds until the power source is considered empty. Is set to 0 if unknown. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public int64 time_to_empty { get; private set; } + + /** + * Number of seconds until the power source is considered full. Is set to 0 if unknown. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public int64 time_to_full { get; private set;} + + /** + * The amount of energy left in the power source expressed as a percentage between 0 and 1. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + * The percentage will be an approximation if [[email protected]:battery_level] + * is set to something other than None. + */ public double percentage { get; private set; } + + /** + * The temperature of the device in degrees Celsius. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public double temperature { get; private set; } + + /** + * If the power source is present in the bay. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public bool is_present { get; private set; } + + /** + * The battery power state. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public State state { get; private set; } + + /** + * If the power source is rechargeable. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public bool is_rechargable { get; private set; } + + /** + * The capacity of the power source expressed as a percentage between 0 and 1. + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public double capacity { get; private set; } + + /** + * Technology used in the battery: + * + * This property is only valid if [[email protected]:device_type] is [[email protected]]. + */ public Technology technology { get; private set; } + + /** Warning level of the battery. */ public WarningLevel warning_level { get; private set; } + + /** + * The level of the battery for devices which do not report a percentage + * but rather a coarse battery level. If the value is None. + * then the device does not support coarse battery reporting, + * and the [[email protected]:percentage] should be used instead. + */ public BatteryLevel battery_level { get; private set; } + + /** + * An icon name representing this Device. + * + * NOTE: [[email protected]:battery_icon_name] might be a better fit + * as it is calculated from percentage. + */ public string icon_name { owned get; private set; } + /** + * Indicates if [[email protected]:state] is charging or fully charged. + */ public bool charging { get; private set; } + + /** + * Indicates if [[email protected]:device_type] is not line power or unknown. + */ public bool is_battery { get; private set; } + + /** + * An icon name in the form of "battery-level-$percentage-$state-symbolic". + */ public string battery_icon_name { get; private set; } + + /** + * A string representation of this device's [[email protected]:device_type]. + */ public string device_type_name { get; private set; } + + /** + * An icon name that can be used to represent this device's [[email protected]:device_type]. + */ public string device_type_icon { get; private set; } - public void sync() { + // TODO: get_history + // TODO: get_statistics + + private void sync() { device_type = (Type)proxy.Type; native_path = proxy.native_path; vendor = proxy.vendor; @@ -72,8 +252,8 @@ public class Device : Object { serial = proxy.serial; update_time = proxy.update_time; power_supply = proxy.power_supply; - has_history = proxy.has_history; - has_statistics = proxy.has_statistics; + // TODO: has_history = proxy.has_history; + // TODO: has_statistics = proxy.has_statistics; online = proxy.online; energy = proxy.energy; energy_empty = proxy.energy_empty; @@ -90,7 +270,7 @@ public class Device : Object { is_present = proxy.is_present; state = (State)proxy.state; is_rechargable = proxy.is_rechargable; - capacity = proxy.capacity; + capacity = proxy.capacity / 100; technology = (Technology)proxy.technology; warning_level = (WarningLevel)proxy.warning_level; battery_level = (BatteryLevel)proxy.battery_level; @@ -115,7 +295,7 @@ public class Device : Object { } [CCode (type_signature = "u")] -public enum State { +public enum AstalBattery.State { UNKNOWN, CHARGING, DISCHARGING, @@ -126,7 +306,7 @@ public enum State { } [CCode (type_signature = "u")] -public enum Technology { +public enum AstalBattery.Technology { UNKNOWN, LITHIUM_ION, LITHIUM_POLYMER, @@ -137,7 +317,7 @@ public enum Technology { } [CCode (type_signature = "u")] -public enum WarningLevel { +public enum AstalBattery.WarningLevel { UNKNOWN, NONE, DISCHARGING, @@ -147,7 +327,7 @@ public enum WarningLevel { } [CCode (type_signature = "u")] -public enum BatteryLevel { +public enum AstalBattery.BatteryLevel { UNKNOWN, NONE, LOW, @@ -158,7 +338,7 @@ public enum BatteryLevel { } [CCode (type_signature = "u")] -public enum Type { +public enum AstalBattery.Type { UNKNOWN, LINE_POWER, BATTERY, @@ -190,7 +370,7 @@ public enum Type { BLUETOOTH_GENERIC; // TODO: add more icon names - public string? get_icon_name () { + internal string? get_icon_name () { switch (this) { case UPS: return "uninterruptible-power-supply"; @@ -213,7 +393,7 @@ public enum Type { } } - public unowned string? get_name () { + internal unowned string? get_name () { switch (this) { case LINE_POWER: return "Plugged In"; @@ -276,4 +456,3 @@ public enum Type { } } } -} diff --git a/lib/battery/gir.py b/lib/battery/gir.py new file mode 120000 index 0000000..b5b4f1d --- /dev/null +++ b/lib/battery/gir.py @@ -0,0 +1 @@ +../gir.py
\ No newline at end of file diff --git a/lib/battery/ifaces.vala b/lib/battery/ifaces.vala index e6eb849..e2d21fe 100644 --- a/lib/battery/ifaces.vala +++ b/lib/battery/ifaces.vala @@ -1,12 +1,11 @@ -namespace AstalBattery { [DBus (name = "org.freedesktop.UPower")] -interface IUPower : DBusProxy { - public abstract string[] enumerate_devices() throws Error; - public abstract string get_display_device() throws Error; +private interface AstalBattery.IUPower : DBusProxy { + public abstract ObjectPath[] enumerate_devices() throws Error; + public abstract ObjectPath get_display_device() throws Error; public abstract string get_critical_action() throws Error; - public signal void device_added(string object_path); - public signal void device_removed(string object_path); + public signal void device_added(ObjectPath object_path); + public signal void device_removed(ObjectPath object_path); public abstract string daemon_version { owned get; } public abstract bool on_battery { get; } @@ -15,10 +14,10 @@ interface IUPower : DBusProxy { } [DBus (name = "org.freedesktop.UPower.Device")] -public interface IUPowerDevice : DBusProxy { - public abstract HistoryDataPoint[] get_history (string type, uint32 timespan, uint32 resolution) throws GLib.Error; - public abstract StatisticsDataPoint[] get_statistics (string type) throws GLib.Error; - public abstract void refresh () throws GLib.Error; +private interface AstalBattery.IUPowerDevice : DBusProxy { + // public abstract HistoryDataPoint[] get_history (string type, uint32 timespan, uint32 resolution) throws GLib.Error; + // public abstract StatisticsDataPoint[] get_statistics (string type) throws GLib.Error; + // public abstract void refresh () throws GLib.Error; public abstract uint Type { get; } public abstract string native_path { owned get; } @@ -52,14 +51,13 @@ public interface IUPowerDevice : DBusProxy { public abstract string icon_name { owned get; } } -public struct HistoryDataPoint { - uint32 time; - double value; - uint32 state; -} - -public struct StatisticsDataPoint { - double value; - double accuracy; -} -} +// private struct AstalBattery.HistoryDataPoint { +// uint32 time; +// double value; +// uint32 state; +// } +// +// private struct AstalBattery.StatisticsDataPoint { +// double value; +// double accuracy; +// } diff --git a/lib/battery/meson.build b/lib/battery/meson.build index 584f66d..054e9db 100644 --- a/lib/battery/meson.build +++ b/lib/battery/meson.build @@ -41,34 +41,40 @@ pkgconfig_deps = [ deps = pkgconfig_deps + meson.get_compiler('c').find_library('m') -sources = [ - config, - 'ifaces.vala', +sources = [config] + files( 'device.vala', + 'ifaces.vala', 'upower.vala', -] +) if get_option('lib') lib = library( meson.project_name(), sources, dependencies: deps, + vala_args: ['--vapi-comments'], vala_header: meson.project_name() + '.h', vala_vapi: meson.project_name() + '-' + api_version + '.vapi', - vala_gir: gir, version: meson.project_version(), install: true, - install_dir: [true, true, true, true], + install_dir: [true, true, true], ) - import('pkgconfig').generate( - lib, - name: meson.project_name(), - filebase: meson.project_name() + '-' + api_version, - version: meson.project_version(), - subdirs: meson.project_name(), - requires: pkgconfig_deps, - install_dir: get_option('libdir') / 'pkgconfig', + pkgs = [] + foreach dep : pkgconfig_deps + pkgs += ['--pkg=' + dep.name()] + endforeach + + gir_tgt = custom_target( + gir, + command: [find_program('python3'), files('gir.py'), meson.project_name(), gir] + + pkgs + + sources, + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', ) custom_target( @@ -81,10 +87,20 @@ if get_option('lib') ], input: lib, output: typelib, - depends: lib, + depends: [lib, gir_tgt], install: true, install_dir: get_option('libdir') / 'girepository-1.0', ) + + import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: pkgconfig_deps, + install_dir: get_option('libdir') / 'pkgconfig', + ) endif if get_option('cli') diff --git a/lib/battery/upower.vala b/lib/battery/upower.vala index 9c18ffd..223633e 100644 --- a/lib/battery/upower.vala +++ b/lib/battery/upower.vala @@ -1,23 +1,40 @@ -namespace AstalBattery { -public class UPower : Object { +/** + * Client for the UPower [[https://upower.freedesktop.org/docs/UPower.html|dbus interface]]. + */ +public class AstalBattery.UPower : Object { private IUPower proxy; private HashTable<string, Device> _devices = new HashTable<string, Device>(str_hash, str_equal); + /** List of UPower devices. */ public List<weak Device> devices { owned get { return _devices.get_values(); } } + /** Emitted when a new device is connected. */ public signal void device_added(Device device); + + /** Emitted a new device is disconnected. */ public signal void device_removed(Device device); + /** A composite device that represents the battery status. */ public Device display_device { owned get { return Device.get_default(); }} public string daemon_version { owned get { return proxy.daemon_version; } } + + /** Indicates whether the system is running on battery power. */ public bool on_battery { get { return proxy.on_battery; } } + + /** Indicates if the laptop lid is closed where the display cannot be seen. */ public bool lid_is_closed { get { return proxy.lid_is_closed; } } + + /** Indicates if the system has a lid device. */ public bool lis_is_present { get { return proxy.lid_is_closed; } } + /** + * When the system's power supply is critical (critically low batteries or UPS), + * the system will take this action. + */ public string critical_action { owned get { try { @@ -41,8 +58,14 @@ public class UPower : Object { _devices.set(path, new Device(path)); proxy.device_added.connect((path) => { - _devices.set(path, new Device(path)); - notify_property("devices"); + try { + var d = new Device(path); + _devices.set(path, d); + device_added(d); + notify_property("devices"); + } catch (Error err) { + critical(err.message); + } }); proxy.device_removed.connect((path) => { @@ -55,4 +78,3 @@ public class UPower : Object { } } } -} diff --git a/lib/bluetooth/adapter.vala b/lib/bluetooth/adapter.vala index 0c9d00e..99a59fb 100644 --- a/lib/bluetooth/adapter.vala +++ b/lib/bluetooth/adapter.vala @@ -1,27 +1,10 @@ -namespace AstalBluetooth { -[DBus (name = "org.bluez.Adapter1")] -internal interface IAdapter : DBusProxy { - public abstract void remove_device(ObjectPath device) throws Error; - public abstract void start_discovery() throws Error; - public abstract void stop_discovery() throws Error; - - public abstract string[] uuids { owned get; } - public abstract bool discoverable { get; set; } - public abstract bool discovering { get; } - public abstract bool pairable { get; set; } - public abstract bool powered { get; set; } - public abstract string address { owned get; } - public abstract string alias { owned get; set; } - public abstract string modalias { owned get; } - public abstract string name { owned get; } - public abstract uint class { get; } - public abstract uint discoverable_timeout { get; set; } - public abstract uint pairable_timeout { get; set; } -} - -public class Adapter : Object { +/** + * Object representing an [[https://github.com/RadiusNetworks/bluez/blob/master/doc/adapter-api.txt|adapter]]. + */ +public class AstalBluetooth.Adapter : Object { private IAdapter proxy; - public string object_path { owned get; construct set; } + + internal string object_path { owned get; private set; } internal Adapter(IAdapter proxy) { this.proxy = proxy; @@ -37,53 +20,127 @@ public class Adapter : Object { }); } + /** + * List of 128-bit UUIDs that represents the available local services. + */ public string[] uuids { owned get { return proxy.uuids; } } + + /** + * Indicates that a device discovery procedure is active. + */ public bool discovering { get { return proxy.discovering; } } + + /** + * Local Device ID information in modalias format used by the kernel and udev. + */ public string modalias { owned get { return proxy.modalias; } } + + /** + * The Bluetooth system name (pretty hostname). + */ public string name { owned get { return proxy.name; } } + + /** + * The Bluetooth class of device. + */ public uint class { get { return proxy.class; } } + + /** + * The Bluetooth device address. + */ public string address { owned get { return proxy.address; } } + + /** + * Switch an adapter to discoverable or non-discoverable + * to either make it visible or hide it. + */ public bool discoverable { get { return proxy.discoverable; } set { proxy.discoverable = value; } } + + /** + * Switch an adapter to pairable or non-pairable. + */ public bool pairable { get { return proxy.pairable; } set { proxy.pairable = value; } } + + /** + * Switch an adapter on or off. + */ public bool powered { get { return proxy.powered; } set { proxy.powered = value; } } + + /** + * The Bluetooth friendly name. + * + * In case no alias is set, it will return [[email protected]:name]. + */ public string alias { owned get { return proxy.alias; } set { proxy.alias = value; } } + + /** + * The discoverable timeout in seconds. + * A value of zero means that the timeout is disabled + * and it will stay in discoverable/limited mode forever + * until [[email protected]_discovery] is invoked. + * The default value for the discoverable timeout should be `180`. + */ public uint discoverable_timeout { get { return proxy.discoverable_timeout; } set { proxy.discoverable_timeout = value; } } + + /** + * The pairable timeout in seconds. + * + * A value of zero means that the timeout is disabled and it will stay in pairable mode forever. + * The default value for pairable timeout should be disabled `0`. + */ public uint pairable_timeout { get { return proxy.pairable_timeout; } set { proxy.pairable_timeout = value; } } - public void remove_device(Device device) { - try { proxy.remove_device((ObjectPath)device.object_path); } catch (Error err) { critical(err.message); } + + /** + * This removes the remote device and the pairing information. + * + * Possible errors: `InvalidArguments`, `Failed`. + */ + public void remove_device(Device device) throws Error { + proxy.remove_device(device.object_path); } - public void start_discovery() { - try { proxy.start_discovery(); } catch (Error err) { critical(err.message); } + + /** + * This method starts the device discovery procedure. + * + * Possible errors: `NotReady`, `Failed`. + */ + public void start_discovery() throws Error { + proxy.start_discovery(); } - public void stop_discovery() { - try { proxy.stop_discovery(); } catch (Error err) { critical(err.message); } + + /** + * This method will cancel any previous [[email protected]_discovery] procedure. + * + * Possible errors: `NotReady`, `Failed`, `NotAuthorized`. + */ + public void stop_discovery() throws Error { + proxy.stop_discovery(); } } -} diff --git a/lib/bluetooth/bluetooth.vala b/lib/bluetooth/bluetooth.vala index ce086ba..6eb6b76 100644 --- a/lib/bluetooth/bluetooth.vala +++ b/lib/bluetooth/bluetooth.vala @@ -1,11 +1,21 @@ namespace AstalBluetooth { -public Bluetooth get_default() { - return Bluetooth.get_default(); + /** + * Gets the default singleton Bluetooth object. + */ + public Bluetooth get_default() { + return Bluetooth.get_default(); + } } -public class Bluetooth : Object { +/** + * Manager object for `org.bluez`. + */ +public class AstalBluetooth.Bluetooth : Object { private static Bluetooth _instance; + /** + * Gets the default singleton Bluetooth object. + */ public static Bluetooth get_default() { if (_instance == null) _instance = new Bluetooth(); @@ -21,30 +31,59 @@ public class Bluetooth : Object { private HashTable<string, Device> _devices = new HashTable<string, Device>(str_hash, str_equal); + /** + * Emitted when a new device is registered on the `org.bluez` bus. + */ public signal void device_added (Device device) { notify_property("devices"); } + /** + * Emitted when a device is unregistered on the `org.bluez` bus. + */ public signal void device_removed (Device device) { notify_property("devices"); } + /** + * Emitted when an adapter is registered on the `org.bluez` bus. + */ public signal void adapter_added (Adapter adapter) { notify_property("adapters"); } + /** + * Emitted when an adapter is unregistered on the `org.bluez` bus. + */ public signal void adapter_removed (Adapter adapter) { notify_property("adapters"); } + /** + * `true` if any of the [[email protected]:adapters] are powered. + */ public bool is_powered { get; private set; default = false; } + + /** + * `true` if any of the [[email protected]:devices] is connected. + */ public bool is_connected { get; private set; default = false; } + + /** + * The first registered adapter which is usually the only adapter. + */ public Adapter? adapter { get { return adapters.nth_data(0); } } + /** + * List of adapters available on the host device. + */ public List<weak Adapter> adapters { owned get { return _adapters.get_values(); } } + /** + * List of registered devices on the `org.bluez` bus. + */ public List<weak Device> devices { owned get { return _devices.get_values(); } } @@ -85,6 +124,10 @@ public class Bluetooth : Object { } } + /** + * Toggle the [[email protected]:powered] + * property of the [[email protected]:adapter]. + */ public void toggle() { adapter.powered = !adapter.powered; } @@ -178,4 +221,3 @@ public class Bluetooth : Object { return false; } } -} diff --git a/lib/bluetooth/device.vala b/lib/bluetooth/device.vala index 8fe086f..3f00cd9 100644 --- a/lib/bluetooth/device.vala +++ b/lib/bluetooth/device.vala @@ -1,37 +1,14 @@ -namespace AstalBluetooth { -[DBus (name = "org.bluez.Device1")] -internal interface IDevice : DBusProxy { - public abstract void cancel_pairing() throws Error; - public abstract async void connect() throws Error; - public abstract void connect_profile(string uuid) throws Error; - public abstract async void disconnect() throws Error; - public abstract void disconnect_profile(string uuid) throws Error; - public abstract void pair() throws Error; - - public abstract string[] uuids { owned get; } - public abstract bool blocked { get; set; } - public abstract bool connected { get; } - public abstract bool legacy_pairing { get; } - public abstract bool paired { get; } - public abstract bool trusted { get; set; } - public abstract int16 rssi { get; } - public abstract ObjectPath adapter { owned get; } - public abstract string address { owned get; } - public abstract string alias { owned get; set; } - public abstract string icon { owned get; } - public abstract string modalias { owned get; } - public abstract string name { owned get; } - public abstract uint16 appearance { get; } - public abstract uint32 class { get; } -} - -public class Device : Object { +/** + * Object representing a [[https://github.com/luetzel/bluez/blob/master/doc/device-api.txt|device]]. + */ +public class AstalBluetooth.Device : Object { private IDevice proxy; - public string object_path { owned get; construct set; } + + internal ObjectPath object_path { owned get; private set; } internal Device(IDevice proxy) { this.proxy = proxy; - this.object_path = proxy.g_object_path; + this.object_path = (ObjectPath)proxy.g_object_path; proxy.g_properties_changed.connect((props) => { var map = (HashTable<string, Variant>)props; foreach (var key in map.get_keys()) { @@ -43,64 +20,164 @@ public class Device : Object { }); } + /** + * List of 128-bit UUIDs that represents the available remote services. + */ public string[] uuids { owned get { return proxy.uuids; } } + + /** + * Indicates if the remote device is currently connected. + */ public bool connected { get { return proxy.connected; } } + + /** + * `true` if the device only supports the pre-2.1 pairing mechanism. + */ public bool legacy_pairing { get { return proxy.legacy_pairing; } } + + /** + * Indicates if the remote device is paired. + */ public bool paired { get { return proxy.paired; } } + + /** + * Received Signal Strength Indicator of the remote device (inquiry or advertising). + */ public int16 rssi { get { return proxy.rssi; } } + + /** + * The object path of the adapter the device belongs to. + */ public ObjectPath adapter { owned get { return proxy.adapter; } } + + /** + * The Bluetooth device address of the remote device. + */ public string address { owned get { return proxy.address; } } + + /** + * Proposed icon name. + */ public string icon { owned get { return proxy.icon; } } + + /** + * Remote Device ID information in modalias format used by the kernel and udev. + */ public string modalias { owned get { return proxy.modalias; } } + + /** + * The Bluetooth remote name. + * + * It is always better to use [[email protected]:alias]. + */ public string name { owned get { return proxy.name; } } + + /** + * External appearance of device, as found on GAP service. + */ public uint16 appearance { get { return proxy.appearance; } } + + /** + * The Bluetooth class of device of the remote device. + */ public uint32 class { get { return proxy.class; } } + + /** + * Indicates if this device is currently trying to be connected. + */ public bool connecting { get; private set; } + /** + * If set to `true` any incoming connections from the device will be immediately rejected. + */ public bool blocked { get { return proxy.blocked; } set { proxy.blocked = value; } } + /** + * Indicates if the remote is seen as trusted. + */ public bool trusted { get { return proxy.trusted; } set { proxy.trusted = value; } } + /** + * The name alias for the remote device. + * + * In case no alias is set, it will return the remote device [[email protected]:name]. + */ public string alias { owned get { return proxy.alias; } set { proxy.alias = value; } } - public void cancel_pairing() { - try { proxy.cancel_pairing(); } catch (Error err) { critical(err.message); } - } - - public async void connect_device() { + /** + * This is a generic method to connect any profiles + * the remote device supports that can be connected to. + * + * Possible errors: `NotReady`, `Failed`, `InProgress`, `AlreadyConnected`. + */ + public async void connect_device() throws Error { try { connecting = true; yield proxy.connect(); - } catch (Error err) { - critical(err.message); } finally { connecting = false; } } - public async void disconnect_device() { - try { yield proxy.disconnect(); } catch (Error err) { critical(err.message); } + /** + * This method gracefully disconnects all connected profiles. + * + * Possible errors: `NotConnected`. + */ + public async void disconnect_device() throws Error { + yield proxy.disconnect(); } - public void connect_profile(string uuid) { - try { proxy.connect_profile(uuid); } catch (Error err) { critical(err.message); } + /** + * This method connects a specific profile of this device. + * The UUID provided is the remote service UUID for the profile. + * + * Possible errors: `Failed`, `InProgress`, `InvalidArguments`, `NotAvailable`, `NotReady`. + * + * @param uuid the remote service UUID. + */ + public void connect_profile(string uuid) throws Error { + proxy.connect_profile(uuid); } - public void disconnect_profile(string uuid) { - try { proxy.disconnect_profile(uuid); } catch (Error err) { critical(err.message); } + /** + * This method disconnects a specific profile of this device. + * + * Possible errors: `Failed`, `InProgress`, `InvalidArguments`, `NotSupported`. + * + * @param uuid the remote service UUID. + */ + public void disconnect_profile(string uuid) throws Error { + proxy.disconnect_profile(uuid); } - public void pair() { - try { proxy.pair(); } catch (Error err) { critical(err.message); } + /** + * This method will connect to the remote device and initiate pairing. + * + * Possible errors: `InvalidArguments`, `Failed`, `AlreadyExists`, + * `AuthenticationCanceled`, `AuthenticationFailed`, `AuthenticationRejected`, + * `AuthenticationTimeout`, `ConnectionAttemptFailed`. + */ + public void pair() throws Error { + proxy.pair(); + } + + /** + * This method can be used to cancel a pairing operation + * initiated by [[email protected]]. + * + * Possible errors: `DoesNotExist`, `Failed`. + */ + public void cancel_pairing() throws Error { + proxy.cancel_pairing(); } -} } diff --git a/lib/bluetooth/gir.py b/lib/bluetooth/gir.py new file mode 120000 index 0000000..b5b4f1d --- /dev/null +++ b/lib/bluetooth/gir.py @@ -0,0 +1 @@ +../gir.py
\ No newline at end of file diff --git a/lib/bluetooth/interfaces.vala b/lib/bluetooth/interfaces.vala new file mode 100644 index 0000000..dcb1c4b --- /dev/null +++ b/lib/bluetooth/interfaces.vala @@ -0,0 +1,46 @@ +[DBus (name = "org.bluez.Adapter1")] +private interface AstalBluetooth.IAdapter : DBusProxy { + public abstract void remove_device(ObjectPath device) throws Error; + public abstract void start_discovery() throws Error; + public abstract void stop_discovery() throws Error; + + public abstract string[] uuids { owned get; } + public abstract bool discoverable { get; set; } + public abstract bool discovering { get; } + public abstract bool pairable { get; set; } + public abstract bool powered { get; set; } + public abstract string address { owned get; } + public abstract string alias { owned get; set; } + public abstract string modalias { owned get; } + public abstract string name { owned get; } + public abstract uint class { get; } + public abstract uint discoverable_timeout { get; set; } + public abstract uint pairable_timeout { get; set; } +} + +[DBus (name = "org.bluez.Device1")] +private interface AstalBluetooth.IDevice : DBusProxy { + public abstract void cancel_pairing() throws Error; + public abstract async void connect() throws Error; + public abstract void connect_profile(string uuid) throws Error; + public abstract async void disconnect() throws Error; + public abstract void disconnect_profile(string uuid) throws Error; + public abstract void pair() throws Error; + + public abstract string[] uuids { owned get; } + public abstract bool blocked { get; set; } + public abstract bool connected { get; } + public abstract bool legacy_pairing { get; } + public abstract bool paired { get; } + public abstract bool trusted { get; set; } + public abstract int16 rssi { get; } + public abstract ObjectPath adapter { owned get; } + public abstract string address { owned get; } + public abstract string alias { owned get; set; } + public abstract string icon { owned get; } + public abstract string modalias { owned get; } + public abstract string name { owned get; } + public abstract uint16 appearance { get; } + public abstract uint32 class { get; } +} + diff --git a/lib/bluetooth/meson.build b/lib/bluetooth/meson.build index 934d380..347b463 100644 --- a/lib/bluetooth/meson.build +++ b/lib/bluetooth/meson.build @@ -33,34 +33,41 @@ deps = [ dependency('gio-2.0'), ] -sources = [ - config, - 'utils.vala', - 'device.vala', +sources = [config] + files( 'adapter.vala', 'bluetooth.vala', -] + 'device.vala', + 'interfaces.vala', + 'utils.vala', +) lib = library( meson.project_name(), sources, dependencies: deps, + vala_args: ['--vapi-comments'], vala_header: meson.project_name() + '.h', vala_vapi: meson.project_name() + '-' + api_version + '.vapi', - vala_gir: gir, version: meson.project_version(), install: true, - install_dir: [true, true, true, true], + install_dir: [true, true, true], ) -import('pkgconfig').generate( - lib, - name: meson.project_name(), - filebase: meson.project_name() + '-' + api_version, - version: meson.project_version(), - subdirs: meson.project_name(), - requires: deps, - install_dir: get_option('libdir') / 'pkgconfig', +pkgs = [] +foreach dep : deps + pkgs += ['--pkg=' + dep.name()] +endforeach + +gir_tgt = custom_target( + gir, + command: [find_program('python3'), files('gir.py'), meson.project_name(), gir] + + pkgs + + sources, + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', ) custom_target( @@ -73,7 +80,17 @@ custom_target( ], input: lib, output: typelib, - depends: lib, + depends: [lib, gir_tgt], install: true, install_dir: get_option('libdir') / 'girepository-1.0', ) + +import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: deps, + install_dir: get_option('libdir') / 'pkgconfig', +) diff --git a/lib/gir.py b/lib/gir.py new file mode 100644 index 0000000..a0a81dc --- /dev/null +++ b/lib/gir.py @@ -0,0 +1,67 @@ +""" +Vala's generated gir does not contain comments, +so we use valadoc to generate them. However, they are formatted +for valadoc and not gi-docgen so we need to fix it. +""" + +import xml.etree.ElementTree as ET +import html +import sys +import subprocess +import re + + +# valac fails on gi-docgen compliant markdown +# gi-docgen removes valac compliant ulink +# so we use vala notation and turn it into markdown +def ulink_to_markdown(text: str): + pattern = r'<ulink url="(.*?)">(.*?)</ulink>' + return re.sub(pattern, r"[\2](\1)", text) + + +def fix_gir(name: str, gir: str, out: str): + namespaces = { + "": "http://www.gtk.org/introspection/core/1.0", + "c": "http://www.gtk.org/introspection/c/1.0", + "glib": "http://www.gtk.org/introspection/glib/1.0", + } + for prefix, uri in namespaces.items(): + ET.register_namespace(prefix, uri) + + tree = ET.parse(gir) + root = tree.getroot() + + for doc in root.findall(".//doc", namespaces): + if doc.text: + doc.text = ulink_to_markdown( + html.unescape(doc.text).replace("<para>", "").replace("</para>", "") + ) + + if (inc := root.find("c:include", namespaces)) is not None: + inc.set("name", f"{name}.h") + else: + print("no c:include tag found", file=sys.stderr) + exit(1) + + tree.write(out, encoding="utf-8", xml_declaration=True) + + +def valadoc(name: str, gir: str, args: list[str]): + cmd = ["valadoc", "-o", "docs", "--package-name", name, "--gir", gir, *args] + try: + subprocess.run(cmd, check=True, text=True, capture_output=True) + except subprocess.CalledProcessError as e: + print(e.stderr, file=sys.stderr) + exit(1) + + +if __name__ == "__main__": + name = sys.argv[1] + in_out = sys.argv[2].split(":") + args = sys.argv[3:] + + gir = in_out[0] + out = in_out[1] if len(in_out) > 1 else gir + + valadoc(name, gir, args) + fix_gir(name, gir, out) diff --git a/lib/hyprland/client.vala b/lib/hyprland/client.vala index 3df644b..3f2d0fb 100644 --- a/lib/hyprland/client.vala +++ b/lib/hyprland/client.vala @@ -73,10 +73,11 @@ public class Client : Object { } } +[Flags] public enum Fullscreen { CURRENT = -1, NONE = 0, - FULLSCREEN = 1, - MAXIMIZED = 2, + MAXIMIZED = 1, + FULLSCREEN = 2, } } diff --git a/lib/hyprland/hyprland.vala b/lib/hyprland/hyprland.vala index 3886486..ea95cab 100644 --- a/lib/hyprland/hyprland.vala +++ b/lib/hyprland/hyprland.vala @@ -158,43 +158,43 @@ public class Hyprland : Object { out DataInputStream stream ) throws Error { conn = connection("socket"); - conn.output_stream.write(message.data, null); - stream = new DataInputStream(conn.input_stream); + if (conn != null) { + conn.output_stream.write(message.data, null); + stream = new DataInputStream(conn.input_stream); + } else { + stream = null; + critical("could not write to the Hyprland socket"); + } } public string message(string message) { - SocketConnection conn; - DataInputStream stream; + SocketConnection? conn; + DataInputStream? stream; try { write_socket(message, out conn, out stream); - return stream.read_upto("\x04", -1, null, null); + if (stream != null && conn != null) { + var res = stream.read_upto("\x04", -1, null, null); + conn.close(null); + return res; + } } catch (Error err) { critical(err.message); - } finally { - try { - if (conn != null) - conn.close(null); - } catch (Error err) { - critical(err.message); - } } return ""; } public async string message_async(string message) { - SocketConnection conn; - DataInputStream stream; + SocketConnection? conn; + DataInputStream? stream; try { write_socket(message, out conn, out stream); - return yield stream.read_upto_async("\x04", -1, Priority.DEFAULT, null, null); - } catch (Error err) { - critical(err.message); - } finally { - try { + if (stream != null && conn != null) { + var res = yield stream.read_upto_async("\x04", -1, Priority.DEFAULT, null, null); conn.close(null); - } catch (Error err) { - critical(err.message); + return res; } + } catch (Error err) { + critical(err.message); } return ""; } diff --git a/lib/mpris/gir.py b/lib/mpris/gir.py new file mode 120000 index 0000000..b5b4f1d --- /dev/null +++ b/lib/mpris/gir.py @@ -0,0 +1 @@ +../gir.py
\ No newline at end of file diff --git a/lib/mpris/ifaces.vala b/lib/mpris/ifaces.vala index 4a9d715..298a288 100644 --- a/lib/mpris/ifaces.vala +++ b/lib/mpris/ifaces.vala @@ -1,19 +1,18 @@ -namespace AstalMpris { [DBus (name="org.freedesktop.DBus")] -internal interface DBusImpl : DBusProxy { - public abstract string[] list_names () throws GLib.Error; - public signal void name_owner_changed (string name, string old_owner, string new_owner); +private interface AstalMpris.DBusImpl : DBusProxy { + public abstract string[] list_names() throws GLib.Error; + public signal void name_owner_changed(string name, string old_owner, string new_owner); } [DBus (name="org.freedesktop.DBus.Properties")] -internal interface PropsIface : DBusProxy { - public abstract HashTable<string, Variant> get_all (string iface); +private interface AstalMpris.PropsIface : DBusProxy { + public abstract HashTable<string, Variant> get_all(string iface); } [DBus (name="org.mpris.MediaPlayer2")] -internal interface IMpris : PropsIface { - public abstract void raise () throws GLib.Error; - public abstract void quit () throws GLib.Error; +private interface AstalMpris.IMpris : PropsIface { + public abstract void raise() throws GLib.Error; + public abstract void quit() throws GLib.Error; public abstract bool can_quit { get; } public abstract bool fullscreen { get; set; } @@ -27,18 +26,18 @@ internal interface IMpris : PropsIface { } [DBus (name="org.mpris.MediaPlayer2.Player")] -internal interface IPlayer : IMpris { - public abstract void next () throws GLib.Error; - public abstract void previous () throws GLib.Error; - public abstract void pause () throws GLib.Error; - public abstract void play_pause () throws GLib.Error; - public abstract void stop () throws GLib.Error; - public abstract void play () throws GLib.Error; - public abstract void seek (int64 offset) throws GLib.Error; - public abstract void set_position (ObjectPath track_id, int64 position) throws GLib.Error; - public abstract void open_uri (string uri) throws GLib.Error; +private interface AstalMpris.IPlayer : IMpris { + public abstract void next() throws GLib.Error; + public abstract void previous() throws GLib.Error; + public abstract void pause() throws GLib.Error; + public abstract void play_pause() throws GLib.Error; + public abstract void stop() throws GLib.Error; + public abstract void play() throws GLib.Error; + public abstract void seek(int64 offset) throws GLib.Error; + public abstract void set_position(ObjectPath track_id, int64 position) throws GLib.Error; + public abstract void open_uri(string uri) throws GLib.Error; - public signal void seeked (int64 position); + public signal void seeked(int64 position); public abstract string playback_status { owned get; } public abstract string loop_status { owned get; set; } @@ -57,4 +56,3 @@ internal interface IPlayer : IMpris { public abstract bool can_seek { get; } public abstract bool can_control { get; } } -} diff --git a/lib/mpris/meson.build b/lib/mpris/meson.build index c9a5c53..bf215c9 100644 --- a/lib/mpris/meson.build +++ b/lib/mpris/meson.build @@ -38,34 +38,40 @@ deps = [ dependency('json-glib-1.0'), ] -sources = [ - config, +sources = [config] + files( 'ifaces.vala', - 'player.vala', 'mpris.vala', -] + 'player.vala', +) if get_option('lib') lib = library( meson.project_name(), sources, dependencies: deps, + vala_args: ['--vapi-comments'], vala_header: meson.project_name() + '.h', vala_vapi: meson.project_name() + '-' + api_version + '.vapi', - vala_gir: gir, version: meson.project_version(), install: true, - install_dir: [true, true, true, true], + install_dir: [true, true, true], ) - import('pkgconfig').generate( - lib, - name: meson.project_name(), - filebase: meson.project_name() + '-' + api_version, - version: meson.project_version(), - subdirs: meson.project_name(), - requires: deps, - install_dir: get_option('libdir') / 'pkgconfig', + pkgs = [] + foreach dep : deps + pkgs += ['--pkg=' + dep.name()] + endforeach + + gir_tgt = custom_target( + gir, + command: [find_program('python3'), files('gir.py'), meson.project_name(), gir] + + pkgs + + sources, + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', ) custom_target( @@ -78,10 +84,20 @@ if get_option('lib') ], input: lib, output: typelib, - depends: lib, + depends: [lib, gir_tgt], install: true, install_dir: get_option('libdir') / 'girepository-1.0', ) + + import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: deps, + install_dir: get_option('libdir') / 'pkgconfig', + ) endif if get_option('cli') diff --git a/lib/mpris/mpris.vala b/lib/mpris/mpris.vala index 0e55a2e..8eaffa5 100644 --- a/lib/mpris/mpris.vala +++ b/lib/mpris/mpris.vala @@ -1,12 +1,24 @@ namespace AstalMpris { -public Mpris get_default() { - return Mpris.get_default(); + /** + * Gets the default singleton Mpris instance. + */ + public Mpris get_default() { + return Mpris.get_default(); + } } -public class Mpris : Object { +/** + * Object that monitors dbus for players to appear and disappear. + */ +public class AstalMpris.Mpris : Object { internal static string PREFIX = "org.mpris.MediaPlayer2."; private static Mpris instance; + private DBusImpl proxy; + + /** + * Gets the default singleton Mpris instance. + */ public static Mpris get_default() { if (instance == null) instance = new Mpris(); @@ -14,15 +26,23 @@ public class Mpris : Object { return instance; } - private DBusImpl proxy; - private HashTable<string, Player> _players = new HashTable<string, Player> (str_hash, str_equal); + /** + * List of currently available players. + */ public List<weak Player> players { owned get { return _players.get_values(); } } - public signal void player_added (Player player); - public signal void player_closed (Player player); + /** + * Emitted when a new mpris Player appears. + */ + public signal void player_added(Player player); + + /** + * Emitted when a Player disappears. + */ + public signal void player_closed(Player player); construct { try { @@ -53,14 +73,15 @@ public class Mpris : Object { var p = new Player(busname); _players.set(busname, p); - p.closed.connect(() => { - player_closed(p); - _players.remove(busname); - notify_property("players"); + p.notify["available"].connect(() => { + if (!p.available) { + player_closed(p); + _players.remove(busname); + notify_property("players"); + } }); player_added(p); notify_property("players"); } } -} diff --git a/lib/mpris/player.vala b/lib/mpris/player.vala index 6764d2b..b72c15e 100644 --- a/lib/mpris/player.vala +++ b/lib/mpris/player.vala @@ -1,75 +1,179 @@ -namespace AstalMpris { -public class Player : Object { +/** + * Object which tracks players through their mpris dbus interface. + * The most simple way is to use [[email protected]] which tracks every player, + * but [[email protected]] can be constructed for a dedicated players too. + */ +public class AstalMpris.Player : Object { private static string COVER_CACHE = Environment.get_user_cache_dir() + "/astal/mpris"; private IPlayer proxy; - - public signal void appeared () { available = true; } - public signal void closed () { available = false; } + private uint pollid; // periodically notify position // identifiers - public string bus_name { owned get; construct set; } - public bool available { get; private set; } + public string bus_name { owned get; private set; } - // periodically notify position - private uint pollid; + /** + * Indicates if [[email protected]:bus_name] is available on dbus. + */ + public bool available { get; private set; } // mpris + + /** + * Brings the player's user interface to the front + * using any appropriate mechanism available. + * + * The media player may be unable to control how its user interface is displayed, + * or it may not have a graphical user interface at all. + * In this case, the [[email protected]:can_raise] is `false` and this method does nothing. + */ public void raise() { - try { proxy.raise(); } catch (Error error) { critical(error.message); } + try { proxy.raise(); } catch (Error err) { critical(err.message); } } - public void quit() { - try { proxy.quit(); } catch (Error error) { critical(error.message); } + /** + * Causes the media player to stop running. + * + * The media player may refuse to allow clients to shut it down. + * In this case, the [[email protected]:can_quit] property is false and this method does nothing. + */ + public void quit() throws Error { + try { proxy.quit(); } catch (Error err) { critical(err.message); } } + /** + * Indicates if [[email protected]] has any effect. + */ public bool can_quit { get; private set; } + + /** + * Indicates if the player is occupying the fullscreen. This is typically used for videos. + * Use [[email protected]_fullscreen] to toggle fullscreen state. + */ public bool fullscreen { get; private set; } + + /** + * Indicates if [[email protected]_fullscreen] has any effect. + */ public bool can_set_fullscreen { get; private set; } + + /** + * Indicates if [[email protected]] has any effect. + */ public bool can_raise { get; private set; } - public bool has_track_list { get; private set; } + + // TODO: Tracklist interface + // public bool has_track_list { get; private set; } + + /** + * A human friendly name to identify the player. + */ public string identity { owned get; private set; } + + /** + * The base name of a .desktop file + */ public string entry { owned get; private set; } + + /** + * The URI schemes supported by the media player. + * + * This can be viewed as protocols supported by the player in almost all cases. + * Almost every media player will include support for the "file" scheme. + * Other common schemes are "http" and "rtsp". + */ public string[] supported_uri_schemas { owned get; private set; } + + /** + * The mime-types supported by the player. + */ public string[] supported_mime_types { owned get; private set; } + /** + * Toggle [[email protected]:fullscreen] state. + */ public void toggle_fullscreen() { if (!can_set_fullscreen) - critical("can not set fullscreen on " + bus_name); + critical(@"can not set fullscreen on $bus_name"); proxy.fullscreen = !fullscreen; } - // player + /** + * Skips to the next track in the tracklist. + * If there is no next track (and endless playback and track repeat are both off), stop playback. + * If [[email protected]:can_go_next] is `false` this method has no effect. + */ public void next() { try { proxy.next(); } catch (Error error) { critical(error.message); } } + /** + * Skips to the previous track in the tracklist. + * If there is no previous track (and endless playback and track repeat are both off), stop playback. + * If [[email protected]:can_go_previous] is `false` this method has no effect. + */ public void previous() { try { proxy.previous(); } catch (Error error) { critical(error.message); } } + /** + * Pauses playback. + * If playback is already paused, this has no effect. + * If [[email protected]:can_pause] is `false` this method has no effect. + */ public void pause() { try { proxy.pause(); } catch (Error error) { critical(error.message); } } + /** + * Pauses playback. + * If playback is already paused, resumes playback. + * If playback is stopped, starts playback. + */ public void play_pause() { try { proxy.play_pause(); } catch (Error error) { critical(error.message); } } + /** + * Stops playback. + * If playback is already stopped, this has no effect. + * If [[email protected]:can_control] is `false` this method has no effect. + */ public void stop() { try { proxy.stop(); } catch (Error error) { critical(error.message); } } + /** + * Starts or resumes playback. + * If already playing, this has no effect. + * If paused, playback resumes from the current position. + * If [[email protected]:can_play] is `false` this method has no effect. + */ public void play() { try { proxy.play(); } catch (Error error) { critical(error.message); } } + /** + * uri scheme should be an element of [[email protected]:supported_uri_schemas] + * and the mime-type should match one of the elements of [[email protected]:supported_mime_types]. + * + * @param uri Uri of the track to load. + */ public void open_uri(string uri) { try { proxy.open_uri(uri); } catch (Error error) { critical(error.message); } } + /** + * Change [[email protected]:loop_status] from none to track, + * from track to playlist, from playlist to none. + */ public void loop() { + if (loop_status == Loop.UNSUPPORTED) { + critical(@"loop is unsupported by $bus_name"); + return; + } + switch (loop_status) { case Loop.NONE: loop_status = Loop.TRACK; @@ -85,15 +189,21 @@ public class Player : Object { } } + /** + * Toggle [[email protected]:shuffle_status]. + */ public void shuffle() { + if (shuffle_status == Shuffle.UNSUPPORTED) { + critical(@"shuffle is unsupported by $bus_name"); + return; + } + shuffle_status = shuffle_status == Shuffle.ON ? Shuffle.OFF : Shuffle.ON; } - public signal void seeked (int64 position); - - public double _get_position() { + private double _get_position() { try { var reply = proxy.call_sync( "org.freedesktop.DBus.Properties.Get", @@ -130,63 +240,175 @@ public class Player : Object { private Shuffle _shuffle_status = Shuffle.UNSUPPORTED; private double _volume = -1; + /** + * The current loop/repeat status. + */ public Loop loop_status { get { return _loop_status; } set { proxy.loop_status = value.to_string(); } } + /** + * The current playback rate. + */ public double rate { get { return _rate; } set { proxy.rate = value; } } + /** + * The current shuffle status. + */ public Shuffle shuffle_status { get { return _shuffle_status; } set { proxy.shuffle = value == Shuffle.ON; } } + /** + * The current volume level between 0 and 1. + */ public double volume { get { return _volume; } set { proxy.volume = value; } } + /** + * The current position of the track in seconds. + * To get a progress percentage simply divide this with [[email protected]:length]. + */ public double position { get { return _get_position(); } set { _set_position(value); } } + /** + * The current playback status. + */ public PlaybackStatus playback_status { get; private set; } + + /** + * The minimum value which the [[email protected]:rate] can take. + */ public double minimum_rate { get; private set; } + + /** + * The maximum value which the [[email protected]:rate] can take. + */ public double maximum_rate { get; private set; } + + /** + * Indicates if invoking [[email protected]] has effect. + */ public bool can_go_next { get; private set; } + + /** + * Indicates if invoking [[email protected]] has effect. + */ public bool can_go_previous { get; private set; } + + /** + * Indicates if invoking [[email protected]] has effect. + */ public bool can_play { get; private set; } + + /** + * Indicates if invoking [[email protected]] has effect. + */ public bool can_pause { get; private set; } + + /** + * Indicates if setting [[email protected]:position] has effect. + */ public bool can_seek { get; private set; } - public bool can_control { get; private set; } - // metadata - [CCode (notify = false)] - public HashTable<string,Variant> metadata { owned get; private set; } + /** + * Indicates if the player can be controlled with + * methods such as [[email protected]_pause]. + */ + public bool can_control { get; private set; } + /** + * Metadata hashtable of this player. + * In languages that cannot introspect this + * use [[email protected]_meta]. + */ + [CCode (notify = false)] // notified manually in sync + public HashTable<string, Variant> metadata { owned get; private set; } + + /** + * Currently playing track's id. + */ public string trackid { owned get; private set; } + + /** + * Length of the currently playing track in seconds. + */ public double length { get; private set; } + + /** + * The location of an image representing the track or album. + * You should always prefer to use [[email protected]:cover_art]. + */ public string art_url { owned get; private set; } + /** + * Title of the currently playing album. + */ public string album { owned get; private set; } + + /** + * Artists of the currently playing album. + */ public string album_artist { owned get; private set; } + + /** + * Artists of the currently playing track. + */ public string artist { owned get; private set; } + + /** + * Lyrics of the currently playing track. + */ public string lyrics { owned get; private set; } + + /** + * Title of the currently playing track. + */ public string title { owned get; private set; } + + /** + * Composers of the currently playing track. + */ public string composer { owned get; private set; } + + /** + * Comments of the currently playing track. + */ public string comments { owned get; private set; } - // cached cover art + /** + * Path of the cached [[email protected]:art_url]. + */ public string cover_art { owned get; private set; } + /** + * Lookup a key from [[email protected]:metadata]. + * This method is useful for languages that fail to introspect hashtables. + */ + public Variant? get_meta(string key) { + return metadata.lookup(key); + } + + /** + * Construct a Player that tracks a dbus name. For example "org.mpris.MediaPlayer2.spotify". + * The "org.mpris.MediaPlayer2." prefix can be leftout so simply "spotify" would mean the same. + * [[email protected]:available] indicates whether the player is actually running or not. + * + * @param name dbus name of the player. + */ public Player(string name) { - Object(bus_name: name.has_prefix("org.mpris.MediaPlayer2.") - ? name : "org.mpris.MediaPlayer2." + name); + bus_name = name.has_prefix("org.mpris.MediaPlayer2.") + ? name : @"org.mpris.MediaPlayer2.$name"; } private void sync() { @@ -195,7 +417,7 @@ public class Player : Object { fullscreen = proxy.fullscreen; can_set_fullscreen = proxy.can_set_fullscreen; can_raise = proxy.can_raise; - has_track_list = proxy.has_track_list; + // has_track_list = proxy.has_track_list; identity = proxy.identity; entry = proxy.desktop_entry; supported_uri_schemas = proxy.supported_uri_schemas; @@ -310,10 +532,6 @@ public class Player : Object { } } - public Variant? get_meta(string key) { - return metadata.lookup(key); - } - private string get_str(string key) { if (metadata.get(key) == null) return ""; @@ -349,7 +567,7 @@ public class Player : Object { } } - public void try_proxy() throws Error { + private void try_proxy() throws Error { if (proxy != null) return; @@ -360,13 +578,14 @@ public class Player : Object { ); if (proxy.g_name_owner != null) - appeared(); + available = false; proxy.notify["g-name-owner"].connect(() => { - if (proxy.g_name_owner != null) - appeared(); - else - closed(); + if (proxy.g_name_owner != null) { + available = true; + } else { + available = false; + } }); proxy.g_properties_changed.connect(sync); @@ -387,12 +606,12 @@ public class Player : Object { } } -public enum PlaybackStatus { +public enum AstalMpris.PlaybackStatus { PLAYING, PAUSED, STOPPED; - public static PlaybackStatus from_string(string? str) { + internal static PlaybackStatus from_string(string? str) { switch (str) { case "Playing": return PLAYING; @@ -404,7 +623,7 @@ public enum PlaybackStatus { } } - public string to_string() { + internal string to_string() { switch (this) { case PLAYING: return "Playing"; @@ -417,13 +636,16 @@ public enum PlaybackStatus { } } -public enum Loop { +public enum AstalMpris.Loop { UNSUPPORTED, + /** The playback will stop when there are no more tracks to play. */ NONE, + /** The current track will start again from the begining once it has finished playing. */ TRACK, + /** The playback loops through a list of tracks. */ PLAYLIST; - public static Loop from_string(string? str) { + internal static Loop from_string(string? str) { switch (str) { case "None": return NONE; @@ -436,7 +658,7 @@ public enum Loop { } } - public string? to_string() { + internal string? to_string() { switch (this) { case NONE: return "None"; @@ -450,16 +672,18 @@ public enum Loop { } } -public enum Shuffle { +public enum AstalMpris.Shuffle { UNSUPPORTED, + /** Playback is progressing through a playlist in some other order. */ ON, + /** Playback is progressing linearly through a playlist. */ OFF; - public static Shuffle from_bool(bool b) { + internal static Shuffle from_bool(bool b) { return b ? Shuffle.ON : Shuffle.OFF; } - public string? to_string() { + internal string? to_string() { switch (this) { case OFF: return "Off"; @@ -470,4 +694,3 @@ public enum Shuffle { } } } -} diff --git a/lib/notifd/gir.py b/lib/notifd/gir.py new file mode 120000 index 0000000..b5b4f1d --- /dev/null +++ b/lib/notifd/gir.py @@ -0,0 +1 @@ +../gir.py
\ No newline at end of file diff --git a/lib/notifd/meson.build b/lib/notifd/meson.build index b6ef59a..3d4de95 100644 --- a/lib/notifd/meson.build +++ b/lib/notifd/meson.build @@ -3,7 +3,7 @@ project( 'vala', 'c', version: run_command('cat', join_paths(meson.project_source_root(), 'version')).stdout().strip(), - meson_version: '>= 0.62.0', + meson_version: '>= 0.63.0', default_options: [ 'warning_level=2', 'werror=false', @@ -53,84 +53,30 @@ if get_option('lib') meson.project_name(), sources, dependencies: deps, - vala_args: ['--vapi-comments', '--ccode'], + vala_args: ['--vapi-comments'], vala_header: meson.project_name() + '.h', vala_vapi: meson.project_name() + '-' + api_version + '.vapi', - vala_gir: gir, version: meson.project_version(), install: true, - install_dir: [true, true, true, true], + install_dir: [true, true, true], ) - # import('gnome').generate_gir( - # lib, - # sources: [], - # nsversion: api_version, - # namespace: namespace, - # symbol_prefix: meson.project_name().replace('-', '_'), - # identifier_prefix: namespace, - # includes: ['GObject-2.0'], - # header: meson.project_name() + '.h', - # export_packages: meson.project_name() + '-' + api_version, - # install: true, - # ) + pkgs = [] + foreach dep : deps + pkgs += ['--pkg=' + dep.name()] + endforeach - # custom_target( - # gir, - # command: [ - # find_program('g-ir-scanner'), - # '--namespace=' + namespace, - # '--nsversion=' + api_version, - # '--library=' + meson.project_name(), - # '--include=GObject-2.0', - # '--output=' + gir, - # '--symbol-prefix=' + meson.project_name().replace('-', '_'), - # '--identifier-prefix=' + namespace, - # ] - # + pkgs - # + ['@INPUT@'], - # output: gir, - # depends: lib, - # input: meson.current_build_dir() / meson.project_name() + '.h', - # install: true, - # install_dir: get_option('datadir') / 'gir-1.0', - # ) - - # custom_target( - # gir, - # command: [ - # find_program('g-ir-scanner'), - # '--namespace=' + namespace, - # '--nsversion=' + api_version, - # '--library=' + meson.project_name(), - # '--include=GObject-2.0', - # '--output=' + gir, - # '--symbol-prefix=' + meson.project_name().replace('-', '_'), - # '--identifier-prefix=' + namespace, - # ] - # + pkgs - # + ['@INPUT@'], - # input: lib.extract_all_objects(), - # output: gir, - # depends: lib, - # install: true, - # install_dir: get_option('datadir') / 'gir-1.0', - # ) - - # pkgs = [] - # foreach dep : deps - # pkgs += ['--pkg=' + dep.name()] - # endforeach - # - # gir_tgt = custom_target( - # gir, - # command: [find_program('valadoc'), '-o', 'docs', '--gir', gir] + pkgs + sources, - # input: sources, - # depends: lib, - # output: gir, - # install: true, - # install_dir: get_option('datadir') / 'gir-1.0', - # ) + gir_tgt = custom_target( + gir, + command: [find_program('python3'), files('gir.py'), meson.project_name(), gir] + + pkgs + + sources, + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', + ) custom_target( typelib, @@ -142,7 +88,7 @@ if get_option('lib') ], input: lib, output: typelib, - depends: lib, + depends: [lib, gir_tgt], install: true, install_dir: get_option('libdir') / 'girepository-1.0', ) diff --git a/lib/notifd/notifd.vala b/lib/notifd/notifd.vala index 6ca25fa..807e40a 100644 --- a/lib/notifd/notifd.vala +++ b/lib/notifd/notifd.vala @@ -1,5 +1,5 @@ /** - * Get the singleton instance of {@link Notifd} + * Get the singleton instance of [[email protected]] */ namespace AstalNotifd { public Notifd get_default() { @@ -74,7 +74,7 @@ public class AstalNotifd.Notifd : Object { } /** - * Gets the {@link Notification} with id or null if there is no such Notification. + * Gets the [[email protected]] with id or null if there is no such Notification. */ public Notification get_notification(uint id) { return proxy != null ? proxy.get_notification(id) : daemon.get_notification(id); @@ -85,7 +85,7 @@ public class AstalNotifd.Notifd : Object { } /** - * Emitted when the daemon receives a {@link Notification}. + * Emitted when the daemon receives a [[email protected]]. * * @param id The ID of the Notification. * @param replaced Indicates if an existing Notification was replaced. @@ -93,7 +93,7 @@ public class AstalNotifd.Notifd : Object { public signal void notified(uint id, bool replaced); /** - * Emitted when a {@link Notification} is resolved. + * Emitted when a [[email protected]] is resolved. * * @param id The ID of the Notification. * @param reason The reason how the Notification was resolved. diff --git a/lib/notifd/notification.vala b/lib/notifd/notification.vala index 5db3fe2..527a352 100644 --- a/lib/notifd/notification.vala +++ b/lib/notifd/notification.vala @@ -38,19 +38,24 @@ public class AstalNotifd.Notification : Object { public int expire_timeout { internal set; get; } /** - * List of {@link Action} of the notification. + * List of [[email protected]] of the notification. * - * Can be invoked by calling {@link Notification.invoke} with the action's id. + * Can be invoked by calling [[email protected]] with the action's id. */ public List<Action?> actions { get { return _actions; } } /** Path of an image */ public string image { get { return get_str_hint("image-path"); } } - /** Indicates whether {@link Action} identifier should be interpreted as a named icon. */ + /** + * Indicates whether [[email protected]] + * identifier should be interpreted as a named icon. + */ public bool action_icons { get { return get_bool_hint("action-icons"); } } - /** [[https://specifications.freedesktop.org/notification-spec/latest/categories.html|Category of the notification.]] */ + /** + * [[https://specifications.freedesktop.org/notification-spec/latest/categories.html]] + */ public string category { get { return get_str_hint("category"); } } /** Specifies the name of the desktop filename representing the calling program. */ @@ -71,13 +76,19 @@ public class AstalNotifd.Notification : Object { /** Indicates that the notification should be excluded from persistency. */ public bool transient { get { return get_bool_hint("transient"); } } - /** Specifies the X location on the screen that the notification should point to. The "y" hint must also be specified. */ + /** + * Specifies the X location on the screen that the notification should point to. + * The "y" hint must also be specified. + */ public int x { get { return get_int_hint("x"); } } - /** Specifies the Y location on the screen that the notification should point to. The "x" hint must also be specified. */ + /** + * Specifies the Y location on the screen that the notification should point to. + * The "x" hint must also be specified. + */ public int y { get { return get_int_hint("y"); } } - /** {@link Urgency} level of the notification. */ + /** [[email protected]] level of the notification. */ public Urgency urgency { get { return get_byte_hint("urgency"); } } internal Notification( @@ -141,24 +152,23 @@ public class AstalNotifd.Notification : Object { } /** - * Emitted when this {@link Notification} is resolved. + * Emitted when this this notification is resolved. * * @param reason The reason how the Notification was resolved. */ public signal void resolved(ClosedReason reason); /** - * Emitted when the user dismisses this {@link Notification} + * Emitted when the user dismisses this notification. * * @see dismiss */ public signal void dismissed(); /** - * Emitted when an {@link Action} of this {@link Notification} is invoked. + * Emitted when an [[email protected]] of this notification is invoked. * * @param action_id id of the invoked action - * @see invoke */ public signal void invoked(string action_id); @@ -171,7 +181,7 @@ public class AstalNotifd.Notification : Object { public void dismiss() { dismissed(); } /** - * Invoke an {@link Action} of this {@link Notification} + * Invoke an [[email protected]] of this notification. * * Note that this method just notifies the client that this action was invoked * by the user. If for example this notification persists through the lifetime diff --git a/lib/tray/gir.py b/lib/tray/gir.py new file mode 120000 index 0000000..b5b4f1d --- /dev/null +++ b/lib/tray/gir.py @@ -0,0 +1 @@ +../gir.py
\ No newline at end of file diff --git a/lib/tray/meson.build b/lib/tray/meson.build index 421f33d..fbb6672 100644 --- a/lib/tray/meson.build +++ b/lib/tray/meson.build @@ -3,7 +3,7 @@ project( 'vala', 'c', version: run_command('cat', join_paths(meson.project_source_root(), 'version')).stdout().strip(), - meson_version: '>= 0.62.0', + meson_version: '>= 0.63.0', default_options: [ 'warning_level=2', 'werror=false', @@ -18,8 +18,9 @@ assert( version_split = meson.project_version().split('.') api_version = version_split[0] + '.' + version_split[1] -gir = 'AstalTray-' + api_version + '.gir' -typelib = 'AstalTray-' + api_version + '.typelib' +namespace = 'AstalTray' +gir = namespace + '-' + api_version + '.gir' +typelib = namespace + '-' + api_version + '.typelib' config = configure_file( input: 'config.vala.in', @@ -61,7 +62,7 @@ dbusmenu_libs = run_command( check: true, ).stdout().strip() -sources = [config, 'tray.vala', 'watcher.vala', 'trayItem.vala'] +sources = [config] + files('tray.vala', 'watcher.vala', 'trayItem.vala') if get_option('lib') lib = library( @@ -70,23 +71,29 @@ if get_option('lib') dependencies: deps, vala_header: meson.project_name() + '.h', vala_vapi: meson.project_name() + '-' + api_version + '.vapi', - vala_gir: gir, - vala_args: ['--pkg', 'DbusmenuGtk3-0.4', '--pkg', 'Dbusmenu-0.4'], + vala_args: ['--vapi-comments', '--pkg', 'DbusmenuGtk3-0.4', '--pkg', 'Dbusmenu-0.4'], version: meson.project_version(), c_args: dbusmenu_cflags.split(' '), link_args: dbusmenu_libs.split(' '), install: true, - install_dir: [true, true, true, true], + install_dir: true, ) - import('pkgconfig').generate( - lib, - name: meson.project_name(), - filebase: meson.project_name() + '-' + api_version, - version: meson.project_version(), - subdirs: meson.project_name(), - requires: deps, - install_dir: get_option('libdir') / 'pkgconfig', + pkgs = ['--pkg', 'DbusmenuGtk3-0.4', '--pkg', 'Dbusmenu-0.4'] + foreach dep : deps + pkgs += ['--pkg=' + dep.name()] + endforeach + + gir_tgt = custom_target( + gir, + command: [find_program('python3'), files('gir.py'), meson.project_name(), gir] + + pkgs + + sources, + input: sources, + depends: lib, + output: gir, + install: true, + install_dir: get_option('datadir') / 'gir-1.0', ) custom_target( @@ -99,10 +106,35 @@ if get_option('lib') ], input: lib, output: typelib, - depends: lib, + depends: [lib, gir_tgt], install: true, install_dir: get_option('libdir') / 'girepository-1.0', ) + + import('pkgconfig').generate( + lib, + name: meson.project_name(), + filebase: meson.project_name() + '-' + api_version, + version: meson.project_version(), + subdirs: meson.project_name(), + requires: deps, + install_dir: get_option('libdir') / 'pkgconfig', + ) + # + # custom_target( + # typelib, + # command: [ + # find_program('g-ir-compiler'), + # '--output', '@OUTPUT@', + # '--shared-library', get_option('prefix') / get_option('libdir') / '@PLAINNAME@', + # meson.current_build_dir() / gir, + # ], + # input: lib, + # output: typelib, + # depends: lib, + # install: true, + # install_dir: get_option('libdir') / 'girepository-1.0', + # ) endif if get_option('cli') diff --git a/lib/tray/tray.vala b/lib/tray/tray.vala index 09b0643..4ea6765 100644 --- a/lib/tray/tray.vala +++ b/lib/tray/tray.vala @@ -2,7 +2,7 @@ namespace AstalTray { [DBus (name="org.kde.StatusNotifierWatcher")] internal interface IWatcher : Object { public abstract string[] RegisteredStatusNotifierItems { owned get; } - public abstract int ProtocolVersion { owned get; } + public abstract int ProtocolVersion { get; } public abstract void RegisterStatusNotifierItem(string service, BusName sender) throws DBusError, IOError; public abstract void RegisterStatusNotifierHost(string service) throws DBusError, IOError; @@ -12,13 +12,19 @@ internal interface IWatcher : Object { public signal void StatusNotifierHostRegistered(); public signal void StatusNotifierHostUnregistered(); } - +/** + * Get the singleton instance of [[email protected]] + */ public Tray get_default() { return Tray.get_default(); } public class Tray : Object { private static Tray? instance; + + /** + * Get the singleton instance of [[email protected]] + */ public static unowned Tray get_default() { if (instance == null) instance = new Tray(); @@ -32,13 +38,22 @@ public class Tray : Object { private HashTable<string, TrayItem> _items = new HashTable<string, TrayItem>(str_hash, str_equal); + /** + * List of currently registered tray items + */ public List<weak TrayItem> items { owned get { return _items.get_values(); }} - public signal void item_added(string service) { + /** + * emitted when a new tray item was added. + */ + public signal void item_added(string item_id) { notify_property("items"); } - public signal void item_removed(string service) { + /** + * emitted when a tray item was removed. + */ + public signal void item_removed(string item_id) { notify_property("items"); } @@ -128,8 +143,11 @@ public class Tray : Object { item_removed(service); } - public TrayItem get_item(string service) { - return _items.get(service); + /** + * gets the TrayItem with the given item-id. + */ + public TrayItem get_item(string item_id) { + return _items.get(item_id); } } } diff --git a/lib/tray/trayItem.vala b/lib/tray/trayItem.vala index d5e8603..db0e6d4 100644 --- a/lib/tray/trayItem.vala +++ b/lib/tray/trayItem.vala @@ -57,12 +57,12 @@ public enum Status { [DBus (name="org.kde.StatusNotifierItem")] internal interface IItem : DBusProxy { public abstract string Title { owned get; } - public abstract Category Category { owned get; } - public abstract Status Status { owned get; } + public abstract Category Category { get; } + public abstract Status Status { get; } public abstract Tooltip? ToolTip { owned get; } public abstract string Id { owned get; } public abstract string? IconThemePath { owned get; } - public abstract bool ItemIsMenu { owned get; } + public abstract bool ItemIsMenu { get; } public abstract ObjectPath? Menu { owned get; } public abstract string IconName { owned get; } public abstract Pixmap[] IconPixmap { owned get; } @@ -88,11 +88,23 @@ public class TrayItem : Object { private IItem proxy; private List<ulong> connection_ids; + + /** The Title of the TrayItem */ public string title { owned get { return proxy.Title; } } + + /** The category this item belongs to */ public Category category { get { return proxy.Category; } } + + /** the current status of this item */ public Status status { get { return proxy.Status; } } + + /** the tooltip of this item */ public Tooltip? tooltip { owned get { return proxy.ToolTip; } } - + + /** + * a markup representation of the tooltip. This is basically equvivalent + * to `tooltip.title \n tooltip.description` + */ public string tooltip_markup { owned get { if (proxy.ToolTip == null) @@ -106,10 +118,30 @@ public class TrayItem : Object { } } + /** the id of the item. This id is specified by the tray app.*/ public string id { owned get { return proxy.Id ;} } - public string icon_theme_path { owned get { return proxy.IconThemePath ;} } + + /** + * If set, this only supports the menu, so showing the menu should be prefered + * over calling [[email protected]]. + */ public bool is_menu { get { return proxy.ItemIsMenu ;} } - + + /** + * the icon theme path, where to look for the [[email protected]:icon-name]. + * + * It is recommended to use the [[email protected]:gicon] property, + * which does the icon lookups for you. + */ + public string icon_theme_path { owned get { return proxy.IconThemePath ;} } + + /** + * the name of the icon. This should be looked up in the [[email protected]:icon-theme-path] + * if set or in the currently used icon theme otherwise. + * + * It is recommended to use the [[email protected]:gicon] property, + * which does the icon lookups for you. + */ public string icon_name { owned get { return proxy.Status == Status.NEEDS_ATTENTION @@ -117,17 +149,30 @@ public class TrayItem : Object { : proxy.IconName; } } - + + /** + * a pixbuf containing the icon. + * + * It is recommended to use the [[email protected]:gicon] property, + * which does the icon lookups for you. + */ public Gdk.Pixbuf icon_pixbuf { owned get { return _get_icon_pixbuf(); } } + /** + * contains the items icon. This property is intended to be used with the gicon property + * of the Icon widget and the recommended way to display the icon. + * This property unifies the [[email protected]:icon-name], + * [[email protected]:icon-theme-path] and [[email protected]:icon-pixbuf] properties. + */ public GLib.Icon gicon { get; private set; } + /** the id of the item used to uniquely identify the TrayItems by this lib.*/ public string item_id { get; private set; } public signal void changed(); public signal void ready(); - public TrayItem(string service, string path) { + internal TrayItem(string service, string path) { connection_ids = new List<ulong>(); item_id = service + path; setup_proxy.begin(service, path, (_, res) => setup_proxy.end(res)); @@ -229,7 +274,10 @@ public class TrayItem : Object { } ); } - + + /** + * send an activate request to the tray app. + */ public void activate(int x, int y) { try { proxy.Activate(x, y); @@ -239,6 +287,9 @@ public class TrayItem : Object { } } + /** + * send a secondary activate request to the tray app. + */ public void secondary_activate(int x, int y) { try { proxy.SecondaryActivate(x, y); @@ -248,6 +299,10 @@ public class TrayItem : Object { } } + /** + * send a scroll request to the tray app. + * valid values for the orientation are "horizontal" and "vertical". + */ public void scroll(int delta, string orientation) { try { proxy.Scroll(delta, orientation); @@ -257,7 +312,9 @@ public class TrayItem : Object { } } - + /** + * creates a new Gtk Menu for this item. + */ public Gtk.Menu? create_menu() { if (proxy.Menu == null) return null; @@ -267,7 +324,7 @@ public class TrayItem : Object { proxy.Menu); } - public Gdk.Pixbuf? _get_icon_pixbuf() { + private Gdk.Pixbuf? _get_icon_pixbuf() { Pixmap[] pixmaps = proxy.Status == Status.NEEDS_ATTENTION ? proxy.AttentionIconPixmap : proxy.IconPixmap; diff --git a/nix/devshell.nix b/nix/devshell.nix index 936f4b4..f5aa18c 100644 --- a/nix/devshell.nix +++ b/nix/devshell.nix @@ -6,11 +6,11 @@ ps.lgi (ps.luaPackages.toLuaModule (pkgs.stdenv.mkDerivation { name = "astal"; - src = "${self}/core/lua"; + src = "${self}/lang/lua"; dontBuild = true; installPhase = '' mkdir -p $out/share/lua/${ps.lua.luaversion}/astal - cp -r astal/* $out/share/lua/${ps.lua.luaversion}/astal + cp -r * $out/share/lua/${ps.lua.luaversion}/astal ''; })) ]); @@ -28,7 +28,9 @@ ninja vala gtk3 + gtk4 gtk-layer-shell + gtk4-layer-shell json-glib pam gvfs diff --git a/nix/doc/gi-docgen.patch b/nix/doc/gi-docgen.patch new file mode 100644 index 0000000..0ecb4bd --- /dev/null +++ b/nix/doc/gi-docgen.patch @@ -0,0 +1,17 @@ +diff --git a/gidocgen/gir/parser.py b/gidocgen/gir/parser.py +index e62835d..7ee60fa 100644 +--- a/gidocgen/gir/parser.py ++++ b/gidocgen/gir/parser.py +@@ -288,7 +288,11 @@ class GirParser: + + content = child.text or "" + +- return ast.Doc(content=content, filename=child.attrib['filename'], line=int(child.attrib['line'])) ++ return ast.Doc( ++ content=content, ++ filename=child.attrib.get('filename', ''), ++ line=int(child.attrib.get('line', 0)), ++ ) + + def _maybe_parse_source_position(self, node: ET.Element) -> T.Optional[ast.SourcePosition]: + child = node.find('core:source-position', GI_NAMESPACES) diff --git a/nix/lua.nix b/nix/lua.nix index 6b0b802..d4221f1 100644 --- a/nix/lua.nix +++ b/nix/lua.nix @@ -12,11 +12,11 @@ defaults: { ps.lgi (ps.luaPackages.toLuaModule (pkgs.stdenvNoCC.mkDerivation { name = "astal"; - src = "${astal}/core/lua"; + src = "${astal}/lang/lua/astal"; dontBuild = true; installPhase = '' mkdir -p $out/share/lua/${ps.lua.luaversion}/astal - cp -r astal/* $out/share/lua/${ps.lua.luaversion}/astal + cp -r * $out/share/lua/${ps.lua.luaversion}/astal ''; })) (ps.luaPackages.toLuaModule (pkgs.stdenvNoCC.mkDerivation { @@ -46,7 +46,8 @@ in extraPackages ++ [ lua - astal.packages.${pkgs.system}.default + astal.packages.${pkgs.system}.io + astal.packages.${pkgs.system}.astal3 ]; installPhase = '' |