diff options
author | Aylur <[email protected]> | 2024-05-25 14:44:50 +0200 |
---|---|---|
committer | Aylur <[email protected]> | 2024-05-25 14:44:50 +0200 |
commit | 58fa1ab9be7ee8fd4a8e96865121a54d613978cc (patch) | |
tree | 56f01ba49fd2929690a16ac05a4af8f763e6b30b /js/src | |
parent | a7e25a4a5fcf4de89fe5a149a9aaf50a92be7af1 (diff) |
separate node and gjs into its own package
Diffstat (limited to 'js/src')
-rw-r--r-- | js/src/application.ts | 28 | ||||
-rw-r--r-- | js/src/astalify.ts | 213 | ||||
-rw-r--r-- | js/src/binding.ts | 78 | ||||
-rw-r--r-- | js/src/process.ts | 83 | ||||
-rw-r--r-- | js/src/time.ts | 27 | ||||
-rw-r--r-- | js/src/variable.ts | 250 |
6 files changed, 0 insertions, 679 deletions
diff --git a/js/src/application.ts b/js/src/application.ts deleted file mode 100644 index 10f840e..0000000 --- a/js/src/application.ts +++ /dev/null @@ -1,28 +0,0 @@ -export type RequestHandler = { - (request: string, res: (response: string) => void): void -} - -export type Config = Partial<{ - instanceName: string - gtkTheme: string - iconTheme: string - cursorTheme: string - css: string - requestHandler: RequestHandler - hold: boolean -}> - -export function runJS(body: string): Promise<any> { - return new Promise((res, rej) => { - try { - const fn = Function(`return (async function() { - ${body.includes(";") ? body : `return ${body};`} - })`) - fn()() - .then(res) - .catch(rej) - } catch (error) { - rej(error) - } - }) -} diff --git a/js/src/astalify.ts b/js/src/astalify.ts deleted file mode 100644 index bc24db6..0000000 --- a/js/src/astalify.ts +++ /dev/null @@ -1,213 +0,0 @@ -import Binding, { kebabify, type Connectable, type Subscribable } from "./binding.js" - -export type Widget<C extends { new(...args: any): any }> = InstanceType<C> & { - className: string - css: string - cursor: Cursor - hook( - object: Connectable, - signal: string, - callback: (self: Widget<C>, ...args: any[]) => void, - ): Widget<C> - hook( - object: Subscribable, - callback: (self: Widget<C>, ...args: any[]) => void, - ): Widget<C> -} - -export default function <G extends { Bin: any, Container: any, Widget: any }>( - Gtk: G, - setter: (prop: string) => `set${string}`, - Astal: { - cssSetter: (w: any, css: string) => void, - cssGetter: (w: any) => string | null, - classSetter: (w: any, name: string[]) => void, - classGetter: (w: any) => string[], - cursorSetter: (w: any, cursor: string) => void, - cursorGetter: (w: any) => string | null, - }, -) { - function hook( - self: any, - object: Connectable | Subscribable, - signalOrCallback: string | ((self: any, ...args: any[]) => void), - callback?: (self: any, ...args: any[]) => void, - ) { - if (typeof object.connect === "function" && callback) { - const id = object.connect(signalOrCallback, (_: any, ...args: unknown[]) => { - callback(self, ...args) - }) - self.connect("destroy", () => { - (object.disconnect as Connectable["disconnect"])(id) - }) - } - - else if (typeof object.subscribe === "function" && typeof signalOrCallback === "function") { - const unsub = object.subscribe((...args: unknown[]) => { - signalOrCallback(self, ...args) - }) - self.connect("destroy", unsub) - } - - return self - } - - function setChild(parent: any, child: any) { - if (parent instanceof Gtk.Bin) { - if (parent.get_child()) - parent.remove(parent.get_child()!) - } - if (parent instanceof Gtk.Container) - parent.add(child) - } - - function ctor(self: any, config: any, ...children: any[]) { - const { setup, child, ...props } = config - props.visible ??= true - - const bindings = Object.keys(props).reduce((acc: any, prop) => { - if (props[prop] instanceof Binding) { - const bind = [prop, props[prop]] - prop === "child" - ? setChild(self, props[prop].get()) - : self[setter(prop)](props[prop].get()) - - delete props[prop] - return [...acc, bind] - } - return acc - }, []) - - const onHandlers = Object.keys(props).reduce((acc: any, key) => { - if (key.startsWith("on")) { - const sig = kebabify(key).split("-").slice(1).join("-") - const handler = [sig, props[key]] - delete props[key] - return [...acc, handler] - } - return acc - }, []) - - Object.assign(self, props) - Object.assign(self, { - hook(obj: any, sig: any, callback: any) { - return hook(self, obj, sig, callback) - }, - }) - - if (child instanceof Binding) { - setChild(self, child.get()) - self.connect("destroy", child.subscribe(v => { - setChild(self, v) - })) - } else if (self instanceof Gtk.Container && child instanceof Gtk.Widget) { - self.add(child) - } - - for (const [signal, callback] of onHandlers) - self.connect(signal, callback) - - if (self instanceof Gtk.Container && children) { - for (const child of children) - self.add(child) - } - - for (const [prop, bind] of bindings) { - self.connect("destroy", bind.subscribe((v: any) => { - self[`${setter(prop)}`](v) - })) - } - - setup?.(self) - return self - } - - return function proxify< - C extends { new(...args: any[]): any }, - >(klass: C) { - Object.defineProperty(klass.prototype, "className", { - get() { return Astal.classGetter(this).join(" ") }, - set(v) { Astal.classSetter(this, v.split(/\s+/)) }, - }) - - Object.defineProperty(klass.prototype, "css", { - get() { return Astal.cssGetter(this) }, - set(v) { Astal.cssSetter(this, v) }, - }) - - Object.defineProperty(klass.prototype, "cursor", { - get() { return Astal.cursorGetter(this) }, - set(v) { Astal.cursorSetter(this, v) }, - }) - - const proxy = new Proxy(klass, { - construct(_, [conf, ...children]) { - const self = new klass - return ctor(self, conf, ...children) - }, - apply(_t, _a, [conf, ...children]) { - const self = new klass - return ctor(self, conf, ...children) - }, - }) - - return proxy - } -} - - -type BindableProps<T> = { - [K in keyof T]: Binding<NonNullable<T[K]>> | T[K]; -} - -export type ConstructProps< - Self extends { new(...args: any[]): any }, - Props = unknown, - Signals = unknown -> = { - [Key in `on${string}`]: (self: Widget<Self>) => unknown -} & Partial<Signals> & BindableProps<Props & { - className?: string - css?: string - cursor?: string -}> & { - onDestroy?: (self: Widget<Self>) => unknown - onDraw?: (self: Widget<Self>) => unknown - setup?: (self: Widget<Self>) => void -} - -type Cursor = - | "default" - | "help" - | "pointer" - | "context-menu" - | "progress" - | "wait" - | "cell" - | "crosshair" - | "text" - | "vertical-text" - | "alias" - | "copy" - | "no-drop" - | "move" - | "not-allowed" - | "grab" - | "grabbing" - | "all-scroll" - | "col-resize" - | "row-resize" - | "n-resize" - | "e-resize" - | "s-resize" - | "w-resize" - | "ne-resize" - | "nw-resize" - | "sw-resize" - | "se-resize" - | "ew-resize" - | "ns-resize" - | "nesw-resize" - | "nwse-resize" - | "zoom-in" - | "zoom-out" diff --git a/js/src/binding.ts b/js/src/binding.ts deleted file mode 100644 index a8b6d55..0000000 --- a/js/src/binding.ts +++ /dev/null @@ -1,78 +0,0 @@ -export const kebabify = (str: string) => str - .replace(/([a-z])([A-Z])/g, "$1-$2") - .replaceAll("_", "-") - .toLowerCase() - -export interface Subscribable<T = unknown> { - subscribe(callback: () => void): () => void - get(): T - [key: string]: any -} - -export interface Connectable { - connect(signal: string, callback: (...args: any[]) => unknown): number - disconnect(id: number): void - [key: string]: any -} - -export default class Binding<Value> { - private emitter: Subscribable<Value> | Connectable - private prop?: string - private transformFn = (v: any) => v - - static bind< - T extends Connectable, - P extends keyof T, - >(object: T, property: P): Binding<T[P]> - - static bind<T>(object: Subscribable<T>): Binding<T> - - static bind(emitter: Connectable | Subscribable, prop?: string) { - return new Binding(emitter, prop) - } - - private constructor(emitter: Connectable | Subscribable<Value>, prop?: string) { - this.emitter = emitter - this.prop = prop && kebabify(prop) - } - - toString() { - return `Binding<${this.emitter}${this.prop ? `, "${this.prop}"` : ""}>` - } - - as<T>(fn: (v: Value) => T): Binding<T> { - const bind = new Binding(this.emitter, this.prop) - bind.transformFn = (v: Value) => fn(this.transformFn(v)) - return bind as unknown as Binding<T> - } - - get(): Value { - if (typeof this.emitter.get === "function") - return this.transformFn(this.emitter.get()) - - if (typeof this.prop === "string") - return this.transformFn(this.emitter[this.prop]) - - throw Error("can not get value of binding") - } - - subscribe(callback: (value: Value) => void): () => void { - if (typeof this.emitter.subscribe === "function") { - return this.emitter.subscribe(() => { - callback(this.get()) - }) - } - else if (typeof this.emitter.connect === "function") { - const signal = `notify::${this.prop}` - const id = this.emitter.connect(signal, () => { - callback(this.get()) - }) - return () => { - (this.emitter.disconnect as Connectable["disconnect"])(id) - } - } - throw Error(`${this.emitter} is not bindable`) - } -} - -export const { bind } = Binding diff --git a/js/src/process.ts b/js/src/process.ts deleted file mode 100644 index 537aba8..0000000 --- a/js/src/process.ts +++ /dev/null @@ -1,83 +0,0 @@ -type Proc = { - connect(sig: "stdout" | "stderr", fn: (_: any, out: string) => void): number -} - -type Config<P extends Proc> = { - defaultOut(stdout: string): void - defaultErr(stdout: string): void - subprocess(cmd: string): P - subprocessv(cmd: string[]): P - exec(cmd: string): string | null - execv(cmd: string[]): string | null - execAsync(cmd: string): P - execAsyncv(cmd: string[]): P -} - -type Args<Out = void, Err = void> = { - cmd: string | string[], - out?: (stdout: string) => Out, - err?: (stderr: string) => Err, -} - -export default function <P extends Proc>(config: Config<P>) { - function args<O, E>(argsOrCmd: Args | string | string[], onOut: O, onErr: E) { - const params = Array.isArray(argsOrCmd) || typeof argsOrCmd === "string" - return { - cmd: params ? argsOrCmd : argsOrCmd.cmd, - err: params ? onErr : argsOrCmd.err || onErr, - out: params ? onOut : argsOrCmd.out || onOut, - } - } - - function subprocess(args: Args): P - function subprocess( - cmd: string | string[], - onOut?: (stdout: string) => void, - onErr?: (stderr: string) => void, - ): P - function subprocess( - argsOrCmd: Args | string | string[], - onOut: (stdout: string) => void = config.defaultOut, - onErr: (stderr: string) => void = config.defaultErr, - ) { - const { cmd, err, out } = args(argsOrCmd, onOut, onErr) - const proc = Array.isArray(cmd) - ? config.subprocessv(cmd) - : config.subprocess(cmd) - - proc.connect("stdout", (_, stdout: string) => out(stdout)) - proc.connect("stderr", (_, stderr: string) => err(stderr)) - return proc - } - - function exec<Out = string, Err = string>( - args: Args<Out, Err> - ): Out | Err - function exec<Out = string, Err = string>( - cmd: string | string[], - onOut?: (stdout: string) => Out, - onErr?: (stderr: string) => Err, - ): Out | Err - function exec<Out = string, Err = string>( - argsOrCmd: Args<Out, Err> | string | string[], - onOut: (stdout: string) => Out = out => out as Out, - onErr: (stderr: string) => Err = out => out as Err, - ): Out | Err { - const { cmd, err, out } = args(argsOrCmd, onOut, onErr) - return Array.isArray(cmd) - ? out(config.execv(cmd)!) as Out - : err(config.exec(cmd)!) as Err - } - - function execAsync(cmd: string | string[]): Promise<string> { - const proc = Array.isArray(cmd) - ? config.execAsyncv(cmd) - : config.execAsync(cmd) - return new Promise((resolve, reject) => { - proc.connect("stdout", (_, out: string) => resolve(out)) - proc.connect("stderr", (_, err: string) => reject(err)) - }) - } - - return { subprocess, exec, execAsync } -} diff --git a/js/src/time.ts b/js/src/time.ts deleted file mode 100644 index ce98c9a..0000000 --- a/js/src/time.ts +++ /dev/null @@ -1,27 +0,0 @@ -interface Time { - connect(sig: "now", fn: () => void): number - cancel(): void -} - -export default function Time<T extends Time>(Time: { - interval(interval: number, closure: any): T - timeout(timeout: number, closure: any): T - idle(closure: any): T -}) { - function interval(interval: number, callback: () => void) { - const t = Time.interval(interval, null) - t.connect("now", callback) - return t - } - function timeout(timeout: number, callback: () => void) { - const t = Time.timeout(timeout, null) - t.connect("now", callback) - return t - } - function idle(callback: () => void) { - const t = Time.idle(null) - t.connect("now", callback) - return t - } - return { interval, timeout, idle } -} diff --git a/js/src/variable.ts b/js/src/variable.ts deleted file mode 100644 index 1d4e07f..0000000 --- a/js/src/variable.ts +++ /dev/null @@ -1,250 +0,0 @@ -import Binding, { type Connectable } from "./binding.js" - -type VariableBase = { - emit(sig: "error" | "changed" | "dropped", ...args: any[]): void - connect(sig: "error" | "changed" | "dropped", fn: (...args: any[]) => void): number - disconnect(id: number): void - runDispose?(): void // node, deno - run_dispose?(): void // gjs -} - -type VariableBaseCtor = { - new(): VariableBase -} - -type Time = any -type Process = any - -type Config = { - defaultErrHandler(err: any): void - VariableBase: VariableBaseCtor - interval(n: number, fn: () => void): Time - execAsync(cmd: string | string[]): Promise<string> - subprocess(args: { - cmd: string | string[], - out: (s: string) => void, - err: (s: string) => void - }): Process -} - -// @ts-expect-error missing values -export const config: Config = {} - -class VariableWrapper<T> extends Function { - private variable!: VariableBase - private errHandler? = config.defaultErrHandler - - private _value: T - private _poll?: Time - private _watch?: Process - - private pollInterval = 1000 - private pollExec?: string[] | string - private pollTransform?: (stdout: string, prev: T) => T - private pollFn?: (prev: T) => T | Promise<T> - - private watchTransform?: (stdout: string, prev: T) => T - private watchExec?: string[] | string - - constructor(init: T) { - super() - this._value = init - this.variable = new config.VariableBase - this.variable.connect("dropped", () => { - this.stopWatch() - this.stopPoll() - }) - this.variable.connect("error", (_, err) => this.errHandler?.(err)) - return new Proxy(this, { - apply: (target, _, args) => target._call(args[0]), - }) - } - - private _call<R = T>(transform?: (value: T) => R): Binding<R> { - const b = Binding.bind(this) - return transform ? b.as(transform) : b as unknown as Binding<R> - } - - toString() { - return String(`Variable<${this.get()}>`) - } - - get(): T { return this._value } - set(value: T) { - if (value !== this._value) { - this._value = value - this.variable.emit("changed") - } - } - - startPoll() { - if (this._poll) - return - - if (this.pollFn) { - this._poll = config.interval(this.pollInterval, () => { - const v = this.pollFn!(this.get()) - if (v instanceof Promise) { - v.then(v => this.set(v)) - .catch(err => this.variable.emit("error", err)) - } else { - this.set(v) - } - }) - } else if (this.pollExec) { - this._poll = config.interval(this.pollInterval, () => { - config.execAsync(this.pollExec!) - .then(v => this.set(this.pollTransform!(v, this.get()))) - .catch(err => this.variable.emit("error", err)) - }) - } - } - - startWatch() { - if (this._watch) - return - - this._watch = config.subprocess({ - cmd: this.watchExec!, - out: out => this.set(this.watchTransform!(out, this.get())), - err: err => this.variable.emit("error", err), - }) - } - - stopPoll() { - this._poll?.cancel() - delete this._poll - } - - stopWatch() { - this._watch?.kill() - delete this._watch - } - - isPolling() { return !!this._poll } - isWatching() { return !!this._watch } - - drop() { - this.variable.emit("dropped") - this.variable.runDispose?.() - this.variable.run_dispose?.() - } - - onDropped(callback: () => void) { - this.variable.connect("dropped", callback) - return this as unknown as Variable<T> - } - - onError(callback: (err: string) => void) { - delete this.errHandler - this.variable.connect("error", (_, err) => callback(err)) - return this as unknown as Variable<T> - } - - subscribe(callback: (value: T) => void) { - const id = this.variable.connect("changed", () => { - callback(this.get()) - }) - return () => this.variable.disconnect(id) - } - - poll( - interval: number, - exec: string | string[], - transform?: (stdout: string, prev: T) => T - ): Variable<T> - - poll( - interval: number, - callback: (prev: T) => T | Promise<T> - ): Variable<T> - - poll( - interval: number, - exec: string | string[] | ((prev: T) => T | Promise<T>), - transform: (stdout: string, prev: T) => T = out => out as T, - ) { - this.stopPoll() - this.pollInterval = interval - this.pollTransform = transform - if (typeof exec === "function") { - this.pollFn = exec - delete this.pollExec - } else { - this.pollExec = exec - delete this.pollFn - } - this.startPoll() - return this as unknown as Variable<T> - } - - watch( - exec: string | string[], - transform: (stdout: string, prev: T) => T = out => out as T, - ) { - this.stopWatch() - this.watchExec = exec - this.watchTransform = transform - this.startWatch() - return this as unknown as Variable<T> - } - - observe( - objs: Array<[obj: Connectable, signal: string]>, - callback: (...args: any[]) => T): Variable<T> - - observe( - obj: Connectable, - signal: string, - callback: (...args: any[]) => T): Variable<T> - - observe( - objs: Connectable | Array<[obj: Connectable, signal: string]>, - sigOrFn: string | ((...args: any[]) => T), - callback?: (...args: any[]) => T, - ) { - const f = typeof sigOrFn === "function" ? sigOrFn : callback ?? (() => this.get()) - const set = (_: Connectable, ...args: any[]) => this.set(f(...args)) - - if (Array.isArray(objs)) { - for (const obj of objs) { - const [o, s] = obj - o.connect(s, set) - } - } else { - if (typeof sigOrFn === "string") - objs.connect(sigOrFn, set) - } - - return this as unknown as Variable<T> - } - - static derive<V, - const Deps extends Array<Variable<any> | Binding<any>>, - Args extends { - [K in keyof Deps]: Deps[K] extends Variable<infer T> - ? T : Deps[K] extends Binding<infer T> ? T : never - }, - >(deps: Deps, fn: (...args: Args) => V) { - const update = () => fn(...deps.map(d => d.get()) as Args) - const derived = new Variable(update()) - const unsubs = deps.map(dep => dep.subscribe(() => derived.set(update()))) - derived.onDropped(() => unsubs.map(unsub => unsub())) - return derived - } -} - -export interface Variable<T> extends Omit<VariableWrapper<T>, "bind"> { - <R>(transform: (value: T) => R): Binding<R> - (): Binding<T> -} - -export const Variable = new Proxy(VariableWrapper as any, { - apply: (_t, _a, args) => new VariableWrapper(args[0]), -}) as { - derive: typeof VariableWrapper["derive"] - <T>(init: T): Variable<T> - new <T>(init: T): Variable<T> -} - -export default Variable |