@gjsify/utils 0.4.0 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +44 -41
- package/src/base64.ts +0 -78
- package/src/byte-array.ts +0 -12
- package/src/callable.ts +0 -63
- package/src/cli.ts +0 -10
- package/src/defer.ts +0 -11
- package/src/encoding.ts +0 -36
- package/src/error.ts +0 -38
- package/src/file.ts +0 -12
- package/src/fs.ts +0 -24
- package/src/gio-errors.ts +0 -156
- package/src/gio.ts +0 -67
- package/src/globals.ts +0 -13
- package/src/index.ts +0 -18
- package/src/log.spec.ts +0 -32
- package/src/main-loop.ts +0 -62
- package/src/message.ts +0 -11
- package/src/microtask.ts +0 -4
- package/src/next-tick.spec.ts +0 -116
- package/src/next-tick.ts +0 -112
- package/src/path.ts +0 -52
- package/src/structured-clone.ts +0 -402
- package/src/test.ts +0 -5
- package/tsconfig.json +0 -38
- package/tsconfig.tsbuildinfo +0 -1
package/package.json
CHANGED
|
@@ -1,44 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
"name": "@gjsify/utils",
|
|
3
|
+
"version": "0.4.4",
|
|
4
|
+
"description": "Utils module for gjsify",
|
|
5
|
+
"module": "lib/esm/index.js",
|
|
6
|
+
"types": "lib/types/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib"
|
|
9
|
+
],
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./lib/types/index.d.ts",
|
|
14
|
+
"default": "./lib/esm/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./main-loop": {
|
|
17
|
+
"types": "./lib/types/main-loop.d.ts",
|
|
18
|
+
"default": "./lib/esm/main-loop.js"
|
|
19
|
+
}
|
|
12
20
|
},
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clear": "rm -rf lib tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
|
|
23
|
+
"check": "tsc --noEmit",
|
|
24
|
+
"build": "gjsify run build:gjsify && gjsify run build:types",
|
|
25
|
+
"build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.{mts,ts}'",
|
|
26
|
+
"build:types": "tsc",
|
|
27
|
+
"build:test": "gjsify run build:test:gjs",
|
|
28
|
+
"build:test:gjs": "gjsify build src/test.ts --app gjs --outfile test.gjs.js",
|
|
29
|
+
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:gjs",
|
|
30
|
+
"test:gjs": "gjsify run test.gjs.js"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"gjs",
|
|
34
|
+
"node",
|
|
35
|
+
"fs"
|
|
36
|
+
],
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@gjsify/cli": "^0.4.4",
|
|
39
|
+
"typescript": "^6.0.3"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@girs/gio-2.0": "2.88.0-4.0.0-rc.15",
|
|
43
|
+
"@girs/giounix-2.0": "2.0.0-4.0.0-rc.15",
|
|
44
|
+
"@girs/gjs": "4.0.0-rc.15",
|
|
45
|
+
"@girs/glib-2.0": "2.88.0-4.0.0-rc.15"
|
|
16
46
|
}
|
|
17
|
-
|
|
18
|
-
"scripts": {
|
|
19
|
-
"clear": "rm -rf lib tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
|
|
20
|
-
"check": "tsc --noEmit",
|
|
21
|
-
"build": "yarn build:gjsify && yarn build:types",
|
|
22
|
-
"build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.{mts,ts}'",
|
|
23
|
-
"build:types": "tsc",
|
|
24
|
-
"build:test": "yarn build:test:gjs",
|
|
25
|
-
"build:test:gjs": "gjsify build src/test.ts --app gjs --outfile test.gjs.js",
|
|
26
|
-
"test": "yarn build:gjsify && yarn build:test && yarn test:gjs",
|
|
27
|
-
"test:gjs": "gjsify run test.gjs.js"
|
|
28
|
-
},
|
|
29
|
-
"keywords": [
|
|
30
|
-
"gjs",
|
|
31
|
-
"node",
|
|
32
|
-
"fs"
|
|
33
|
-
],
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"@gjsify/cli": "^0.4.0",
|
|
36
|
-
"typescript": "^6.0.3"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@girs/gio-2.0": "2.88.0-4.0.0-rc.15",
|
|
40
|
-
"@girs/giounix-2.0": "2.0.0-4.0.0-rc.15",
|
|
41
|
-
"@girs/gjs": "4.0.0-rc.15",
|
|
42
|
-
"@girs/glib-2.0": "2.88.0-4.0.0-rc.15"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
47
|
+
}
|
package/src/base64.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// Base64 encoding/decoding utilities for GJS
|
|
2
|
-
// Shared by @gjsify/buffer and @gjsify/string_decoder
|
|
3
|
-
// Reference: RFC 4648
|
|
4
|
-
|
|
5
|
-
const B64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
6
|
-
const B64_LOOKUP = new Uint8Array(256);
|
|
7
|
-
for (let i = 0; i < B64_CHARS.length; i++) B64_LOOKUP[B64_CHARS.charCodeAt(i)] = i;
|
|
8
|
-
|
|
9
|
-
/** Decode a base64 string to a binary string. Uses native atob when available. */
|
|
10
|
-
export function atobPolyfill(str: string): string {
|
|
11
|
-
if (typeof globalThis.atob === 'function') return globalThis.atob(str);
|
|
12
|
-
const cleaned = str.replace(/[=\s]/g, '');
|
|
13
|
-
let result = '';
|
|
14
|
-
let bits = 0;
|
|
15
|
-
let collected = 0;
|
|
16
|
-
for (let i = 0; i < cleaned.length; i++) {
|
|
17
|
-
bits = (bits << 6) | B64_LOOKUP[cleaned.charCodeAt(i)];
|
|
18
|
-
collected += 6;
|
|
19
|
-
if (collected >= 8) {
|
|
20
|
-
collected -= 8;
|
|
21
|
-
result += String.fromCharCode((bits >> collected) & 0xff);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return result;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Encode a binary string to base64. Uses native btoa when available. */
|
|
28
|
-
export function btoaPolyfill(str: string): string {
|
|
29
|
-
if (typeof globalThis.btoa === 'function') return globalThis.btoa(str);
|
|
30
|
-
let result = '';
|
|
31
|
-
let i = 0;
|
|
32
|
-
for (; i + 2 < str.length; i += 3) {
|
|
33
|
-
const n = (str.charCodeAt(i) << 16) | (str.charCodeAt(i + 1) << 8) | str.charCodeAt(i + 2);
|
|
34
|
-
result += B64_CHARS[(n >> 18) & 63] + B64_CHARS[(n >> 12) & 63] + B64_CHARS[(n >> 6) & 63] + B64_CHARS[n & 63];
|
|
35
|
-
}
|
|
36
|
-
if (i + 1 === str.length) {
|
|
37
|
-
const n = str.charCodeAt(i) << 16;
|
|
38
|
-
result += B64_CHARS[(n >> 18) & 63] + B64_CHARS[(n >> 12) & 63] + '==';
|
|
39
|
-
} else if (i + 2 === str.length) {
|
|
40
|
-
const n = (str.charCodeAt(i) << 16) | (str.charCodeAt(i + 1) << 8);
|
|
41
|
-
result += B64_CHARS[(n >> 18) & 63] + B64_CHARS[(n >> 12) & 63] + B64_CHARS[(n >> 6) & 63] + '=';
|
|
42
|
-
}
|
|
43
|
-
return result;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Decode a base64 string directly to Uint8Array (avoids lossy atob string round-trip). */
|
|
47
|
-
export function base64Decode(str: string): Uint8Array {
|
|
48
|
-
const cleaned = str.replace(/[=\s]/g, '');
|
|
49
|
-
const bytes = new Uint8Array((cleaned.length * 3) >> 2);
|
|
50
|
-
let bits = 0;
|
|
51
|
-
let collected = 0;
|
|
52
|
-
let pos = 0;
|
|
53
|
-
for (let i = 0; i < cleaned.length; i++) {
|
|
54
|
-
bits = (bits << 6) | B64_LOOKUP[cleaned.charCodeAt(i)];
|
|
55
|
-
collected += 6;
|
|
56
|
-
if (collected >= 8) {
|
|
57
|
-
collected -= 8;
|
|
58
|
-
bytes[pos++] = (bits >> collected) & 0xff;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return bytes.subarray(0, pos);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Encode a Uint8Array to base64 string. */
|
|
65
|
-
export function base64Encode(bytes: Uint8Array): string {
|
|
66
|
-
let result = '';
|
|
67
|
-
const len = bytes.length;
|
|
68
|
-
for (let i = 0; i < len; i += 3) {
|
|
69
|
-
const b0 = bytes[i];
|
|
70
|
-
const b1 = i + 1 < len ? bytes[i + 1] : 0;
|
|
71
|
-
const b2 = i + 2 < len ? bytes[i + 2] : 0;
|
|
72
|
-
result += B64_CHARS[b0 >> 2];
|
|
73
|
-
result += B64_CHARS[((b0 & 3) << 4) | (b1 >> 4)];
|
|
74
|
-
result += i + 1 < len ? B64_CHARS[((b1 & 0xf) << 2) | (b2 >> 6)] : '=';
|
|
75
|
-
result += i + 2 < len ? B64_CHARS[b2 & 0x3f] : '=';
|
|
76
|
-
}
|
|
77
|
-
return result;
|
|
78
|
-
}
|
package/src/byte-array.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type GLib from '@girs/glib-2.0';
|
|
2
|
-
|
|
3
|
-
declare const imports: { byteArray: { fromGBytes(input: GLib.Bytes): Uint8Array } };
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Convert GLib.Bytes to Uint8Array using GJS's byteArray module.
|
|
7
|
-
* This wraps the GJS-specific `imports.byteArray.fromGBytes()` API
|
|
8
|
-
* with proper typing to eliminate `as any` casts throughout the codebase.
|
|
9
|
-
*/
|
|
10
|
-
export function gbytesToUint8Array(bytes: GLib.Bytes): Uint8Array {
|
|
11
|
-
return imports.byteArray.fromGBytes(bytes);
|
|
12
|
-
}
|
package/src/callable.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// Legacy `.call(this)` compatibility shim for ES6 classes.
|
|
2
|
-
//
|
|
3
|
-
// Reference: refs/node/lib/internal/streams/legacy.js (Node core Stream() as a
|
|
4
|
-
// regular function, deliberately callable via .call()).
|
|
5
|
-
// Reference: refs/readable-stream/lib/internal/streams/legacy.js (same pattern).
|
|
6
|
-
// Implements the legacy callable pattern for our class-based hierarchy so
|
|
7
|
-
// pre-ES2015 CJS consumers can do `Cls.call(this)` + `util.inherits(Sub, Cls)`.
|
|
8
|
-
// Without this shim, packages that do `EventEmitter.call(this)` or
|
|
9
|
-
// `Stream.call(this)` crash with:
|
|
10
|
-
// TypeError: Class constructor Foo cannot be invoked without 'new'
|
|
11
|
-
//
|
|
12
|
-
// Copyright (c) Node.js contributors. MIT license.
|
|
13
|
-
// Modifications: implemented as a Proxy wrapper for GJSify's ES6 classes.
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Wrap an ES6 class so it supports both the modern `new Cls(...)` pattern and
|
|
17
|
-
* the legacy `Cls.call(thisArg, ...)` / `Cls(...)` (no-`new`) patterns.
|
|
18
|
-
*
|
|
19
|
-
* The `apply` trap has two modes:
|
|
20
|
-
*
|
|
21
|
-
* 1. **`Cls.call(thisArg, ...)`** — a real consumer instance is provided.
|
|
22
|
-
* We materialise a temporary instance via `Reflect.construct` (so field
|
|
23
|
-
* initializers and constructor bodies run normally) and transplant its
|
|
24
|
-
* own property descriptors onto `thisArg`. This is how Node-era CJS
|
|
25
|
-
* consumers + `util.inherits(Sub, Cls)` chains expect to subclass our
|
|
26
|
-
* ES6 classes.
|
|
27
|
-
*
|
|
28
|
-
* 2. **`Cls(...)`** (called as a plain function — `thisArg` is `undefined`
|
|
29
|
-
* in strict mode or `globalThis` in sloppy mode) — we treat the call as
|
|
30
|
-
* a constructor call and return a fresh `new Cls(...)`. Node's stream
|
|
31
|
-
* constructors implement this guard explicitly:
|
|
32
|
-
* `if (!(this instanceof PassThrough)) return new PassThrough(...)`
|
|
33
|
-
* so consumers like `merge2` invoke `Stream.PassThrough(opts)` without
|
|
34
|
-
* `new` and rely on the result being a real instance. Without this
|
|
35
|
-
* branch the apply trap would crash with "undefined is not a non-null
|
|
36
|
-
* object" when it tried to `Object.defineProperty(thisArg, …)`.
|
|
37
|
-
*
|
|
38
|
-
* The default Proxy traps pass `construct`, `get` and `getPrototypeOf`
|
|
39
|
-
* straight through, so `new Wrapped()`, `Wrapped.prototype` (consulted by
|
|
40
|
-
* `util.inherits`) and `instance instanceof Wrapped` all behave identically
|
|
41
|
-
* to the underlying class.
|
|
42
|
-
*/
|
|
43
|
-
export function makeCallable<T extends new (...args: any[]) => any>(Cls: T): T {
|
|
44
|
-
return new Proxy(Cls, {
|
|
45
|
-
apply(target, thisArg: object | undefined | null, args: any[]) {
|
|
46
|
-
// No-`new` invocation (`Cls(...)`): no usable receiver to mutate
|
|
47
|
-
// — return a freshly constructed instance instead. globalThis is
|
|
48
|
-
// also treated as "no receiver" because that is what a sloppy-
|
|
49
|
-
// mode plain function call surfaces.
|
|
50
|
-
if (thisArg == null || thisArg === globalThis) {
|
|
51
|
-
return Reflect.construct(target, args, target);
|
|
52
|
-
}
|
|
53
|
-
// `Cls.call(thisArg, ...)`: transplant a fresh instance's own
|
|
54
|
-
// properties onto the caller-supplied receiver.
|
|
55
|
-
const tmp = Reflect.construct(target, args, target);
|
|
56
|
-
for (const key of Reflect.ownKeys(tmp)) {
|
|
57
|
-
const desc = Object.getOwnPropertyDescriptor(tmp, key);
|
|
58
|
-
if (desc) Object.defineProperty(thisArg, key, desc);
|
|
59
|
-
}
|
|
60
|
-
return thisArg;
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}
|
package/src/cli.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import GLib from '@girs/glib-2.0';
|
|
2
|
-
const byteArray = imports.byteArray;
|
|
3
|
-
|
|
4
|
-
export const cli = (commandLine: string): string => {
|
|
5
|
-
const [res, out, err, status] = GLib.spawn_command_line_sync(commandLine);
|
|
6
|
-
|
|
7
|
-
if(err.byteLength) throw new Error(byteArray.toString(err));
|
|
8
|
-
|
|
9
|
-
return byteArray.toString(out);
|
|
10
|
-
};
|
package/src/defer.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Defer an event emission to the next macrotask, matching Node.js behavior
|
|
3
|
-
* for server 'listening', 'close', and 'error' events.
|
|
4
|
-
*/
|
|
5
|
-
export function deferEmit(
|
|
6
|
-
emitter: { emit(event: string | symbol, ...args: unknown[]): boolean },
|
|
7
|
-
event: string,
|
|
8
|
-
...args: unknown[]
|
|
9
|
-
): void {
|
|
10
|
-
setTimeout(() => emitter.emit(event, ...args), 0);
|
|
11
|
-
}
|
package/src/encoding.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// Shared encoding normalization utilities.
|
|
2
|
-
// Used by buffer, string_decoder, crypto, and other packages that deal with encodings.
|
|
3
|
-
|
|
4
|
-
/** Canonical encoding names (matches BufferEncoding from @types/node). */
|
|
5
|
-
export type Encoding = 'utf8' | 'ascii' | 'latin1' | 'base64' | 'base64url' | 'hex' | 'utf16le' | 'binary' | 'ucs2' | 'ucs-2' | 'utf-8';
|
|
6
|
-
|
|
7
|
-
const VALID_ENCODINGS = ['utf8', 'ascii', 'latin1', 'binary', 'base64', 'base64url', 'hex', 'ucs2', 'utf16le'];
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Normalize an encoding string to a canonical encoding value.
|
|
11
|
-
* Returns 'utf8' as default for undefined/null/empty input.
|
|
12
|
-
*/
|
|
13
|
-
export function normalizeEncoding(enc?: string): Encoding {
|
|
14
|
-
if (!enc || enc === 'utf8' || enc === 'utf-8') return 'utf8';
|
|
15
|
-
const lower = ('' + enc).toLowerCase().replace(/-/g, '');
|
|
16
|
-
switch (lower) {
|
|
17
|
-
case 'utf8': return 'utf8';
|
|
18
|
-
case 'ascii': return 'ascii';
|
|
19
|
-
case 'latin1': case 'binary': return 'latin1';
|
|
20
|
-
case 'base64': return 'base64';
|
|
21
|
-
case 'base64url': return 'base64url';
|
|
22
|
-
case 'hex': return 'hex';
|
|
23
|
-
case 'ucs2': case 'utf16le': return 'utf16le';
|
|
24
|
-
default: return 'utf8';
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Check that an encoding string is valid. Throws TypeError if not.
|
|
30
|
-
*/
|
|
31
|
-
export function checkEncoding(encoding: string): void {
|
|
32
|
-
const lower = ('' + encoding).toLowerCase().replace(/-/g, '');
|
|
33
|
-
if (!VALID_ENCODINGS.includes(lower)) {
|
|
34
|
-
throw new TypeError(`Unknown encoding: ${encoding}`);
|
|
35
|
-
}
|
|
36
|
-
}
|
package/src/error.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Defines the static Error.captureStackTrace method,
|
|
3
|
-
* this is not present in SpiderMonkey because it comes from V8
|
|
4
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#static_methods
|
|
5
|
-
* @see https://nodejs.org/dist/latest-v18.x/docs/api/errors.html#errorcapturestacktracetargetobject-constructoropt
|
|
6
|
-
*/
|
|
7
|
-
export const initErrorV8Methods = (ErrorConstructor: typeof Error) => {
|
|
8
|
-
// See https://nodejs.org/dist/latest-v18.x/docs/api/errors.html#errorcapturestacktracetargetobject-constructoropt
|
|
9
|
-
if (!(Error as any).captureStackTrace) {
|
|
10
|
-
/**
|
|
11
|
-
* A non-standard V8 function.
|
|
12
|
-
* Creates a .stack property on targetObject, which when accessed returns a string representing the location in the code at which Error.captureStackTrace() was called.
|
|
13
|
-
* @param targetObject
|
|
14
|
-
* @param constructorOpt
|
|
15
|
-
*/
|
|
16
|
-
(Error as any).captureStackTrace = function(targetObject: object, constructorOpt?: Function) {
|
|
17
|
-
const container = new Error();
|
|
18
|
-
|
|
19
|
-
const target = constructorOpt || targetObject;
|
|
20
|
-
|
|
21
|
-
Object.defineProperty(target, 'stack', {
|
|
22
|
-
configurable: true,
|
|
23
|
-
get: function getStack() {
|
|
24
|
-
var stack = container.stack;
|
|
25
|
-
|
|
26
|
-
Object.defineProperty(this, 'stack', {
|
|
27
|
-
value: stack
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
return stack;
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// TODO Error.stackTraceLimit()
|
|
37
|
-
// TODO Error.prepareStackTrace()
|
|
38
|
-
}
|
package/src/file.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import GLib from '@girs/glib-2.0';
|
|
2
|
-
|
|
3
|
-
const byteArray = imports.byteArray;
|
|
4
|
-
|
|
5
|
-
export const readJSON = (path: string) => {
|
|
6
|
-
const [ok, contents] = GLib.file_get_contents(path);
|
|
7
|
-
if (ok) {
|
|
8
|
-
const map = JSON.parse(byteArray.toString(contents));
|
|
9
|
-
return map;
|
|
10
|
-
}
|
|
11
|
-
throw new Error(`Error on require "${path}"`);
|
|
12
|
-
}
|
package/src/fs.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import Gio from '@girs/gio-2.0';
|
|
2
|
-
import GioUnix from '@girs/giounix-2.0';
|
|
3
|
-
/** Check if a file descriptor exists */
|
|
4
|
-
export const existsFD = (fd: number) => {
|
|
5
|
-
try {
|
|
6
|
-
let stream = GioUnix.InputStream.new(fd, false);
|
|
7
|
-
stream.close(null);
|
|
8
|
-
// File descriptor 12345 exists
|
|
9
|
-
return true
|
|
10
|
-
} catch (error) {
|
|
11
|
-
// File descriptor 12345 does not exist
|
|
12
|
-
return false
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function existsSync(path: string) {
|
|
17
|
-
// TODO: accept buffer and URL too
|
|
18
|
-
if (typeof path !== 'string' || path === '') {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const file = Gio.File.new_for_path(path);
|
|
23
|
-
return file.query_exists(null);
|
|
24
|
-
}
|
package/src/gio-errors.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
// Shared Gio.IOErrorEnum → Node.js error code mapping.
|
|
2
|
-
// Used by fs, net, http, dns, child-process, and other packages that wrap Gio operations.
|
|
3
|
-
//
|
|
4
|
-
// The enum values are numeric constants from GLib — we use numbers directly
|
|
5
|
-
// to avoid importing Gio just for error handling (keeps this usable in Node.js tests too).
|
|
6
|
-
|
|
7
|
-
/** Map from Gio.IOErrorEnum numeric values to Node.js error code strings. */
|
|
8
|
-
export const GIO_ERROR_TO_NODE: Record<number, string> = {
|
|
9
|
-
0: 'EIO', // FAILED
|
|
10
|
-
1: 'ENOENT', // NOT_FOUND
|
|
11
|
-
2: 'EEXIST', // EXISTS
|
|
12
|
-
3: 'EISDIR', // IS_DIRECTORY
|
|
13
|
-
4: 'ENOTDIR', // NOT_DIRECTORY
|
|
14
|
-
5: 'ENOTEMPTY', // NOT_EMPTY
|
|
15
|
-
6: 'ENOENT', // NOT_REGULAR_FILE
|
|
16
|
-
7: 'ENFILE', // TOO_MANY_OPEN_FILES
|
|
17
|
-
9: 'EACCES', // NOT_MOUNTABLE_FILE
|
|
18
|
-
10: 'ENFILE', // FILENAME_TOO_LONG
|
|
19
|
-
11: 'EINVAL', // INVALID_FILENAME
|
|
20
|
-
12: 'ELOOP', // TOO_MANY_LINKS
|
|
21
|
-
13: 'ENOSPC', // NO_SPACE
|
|
22
|
-
14: 'EACCES', // PERMISSION_DENIED
|
|
23
|
-
17: 'ELOOP', // TOO_MANY_LINKS (duplicate guard)
|
|
24
|
-
19: 'ENOSPC', // NO_SPACE (duplicate guard)
|
|
25
|
-
20: 'ENOTSUP', // NOT_SUPPORTED
|
|
26
|
-
22: 'EMFILE', // TOO_MANY_OPEN_FILES
|
|
27
|
-
24: 'EROFS', // READ_ONLY
|
|
28
|
-
25: 'ECANCELED', // CANCELLED
|
|
29
|
-
26: 'EBUSY', // BUSY
|
|
30
|
-
27: 'ETIMEDOUT', // TIMED_OUT
|
|
31
|
-
28: 'EHOSTUNREACH', // HOST_NOT_FOUND (was WOULD_BLOCK)
|
|
32
|
-
30: 'EHOSTUNREACH', // HOST_NOT_FOUND
|
|
33
|
-
31: 'ENETUNREACH', // NETWORK_UNREACHABLE
|
|
34
|
-
32: 'ECONNREFUSED', // CONNECTION_REFUSED (legacy value)
|
|
35
|
-
33: 'EADDRINUSE', // ADDRESS_IN_USE
|
|
36
|
-
34: 'ECONNRESET', // CONNECTION_CLOSED (mapped to reset)
|
|
37
|
-
36: 'EPIPE', // BROKEN_PIPE
|
|
38
|
-
38: 'ENETUNREACH', // NETWORK_UNREACHABLE (actual GJS value)
|
|
39
|
-
39: 'ECONNREFUSED', // CONNECTION_REFUSED (actual GJS value)
|
|
40
|
-
40: 'ECONNREFUSED', // PROXY_FAILED
|
|
41
|
-
41: 'EACCES', // PROXY_AUTH_FAILED
|
|
42
|
-
44: 'ECONNRESET', // CONNECTION_CLOSED (actual GJS value)
|
|
43
|
-
46: 'EMSGSIZE', // MESSAGE_TOO_LARGE
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export interface NodeErrorDetails {
|
|
47
|
-
path?: string;
|
|
48
|
-
dest?: string;
|
|
49
|
-
address?: string;
|
|
50
|
-
port?: number;
|
|
51
|
-
hostname?: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Node.js-style ErrnoException (defined locally to avoid @types/node dependency). */
|
|
55
|
-
export interface ErrnoException extends Error {
|
|
56
|
-
errno?: number;
|
|
57
|
-
code?: string;
|
|
58
|
-
path?: string;
|
|
59
|
-
syscall?: string;
|
|
60
|
-
address?: string;
|
|
61
|
-
port?: number;
|
|
62
|
-
hostname?: string;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Create a Node.js-style ErrnoException from a Gio error.
|
|
67
|
-
* Works for fs, net, dns, child-process, and other modules.
|
|
68
|
-
*/
|
|
69
|
-
export function createNodeError(
|
|
70
|
-
err: unknown,
|
|
71
|
-
syscall: string,
|
|
72
|
-
details?: NodeErrorDetails
|
|
73
|
-
): ErrnoException {
|
|
74
|
-
const errObj = err as { code?: number; message?: string } | null | undefined;
|
|
75
|
-
const code = GIO_ERROR_TO_NODE[errObj?.code ?? -1] || 'EIO';
|
|
76
|
-
|
|
77
|
-
let msg = `${code}: ${errObj?.message || 'unknown error'}, ${syscall}`;
|
|
78
|
-
if (details?.path) msg += ` '${details.path}'`;
|
|
79
|
-
if (details?.dest) msg += ` -> '${details.dest}'`;
|
|
80
|
-
if (details?.address) msg += ` ${details.address}`;
|
|
81
|
-
if (details?.port != null) msg += `:${details.port}`;
|
|
82
|
-
|
|
83
|
-
const error = new Error(msg) as ErrnoException;
|
|
84
|
-
error.code = code;
|
|
85
|
-
error.syscall = syscall;
|
|
86
|
-
error.errno = -(errObj?.code || 0);
|
|
87
|
-
|
|
88
|
-
if (details?.path) error.path = details.path;
|
|
89
|
-
if (details?.address) error.address = details.address;
|
|
90
|
-
if (details?.port != null) error.port = details.port;
|
|
91
|
-
|
|
92
|
-
return error;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Check if a Gio error is a "not found" error.
|
|
97
|
-
*/
|
|
98
|
-
export function isNotFoundError(err: unknown): boolean {
|
|
99
|
-
const errObj = err as { code?: number | string } | null | undefined;
|
|
100
|
-
return errObj?.code === 1 || errObj?.code === 'ENOENT';
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Map from GLib.FileError numeric values to Node.js error code strings.
|
|
105
|
-
* Distinct from Gio.IOErrorEnum — GLib.IOChannel.new_file() and some other
|
|
106
|
-
* low-level GLib APIs throw GLib.FileError (domain "g-file-error"), which
|
|
107
|
-
* has different numeric values than Gio.IOErrorEnum (domain "g-io-error-quark").
|
|
108
|
-
*/
|
|
109
|
-
export const GLIB_FILE_ERROR_TO_NODE: Record<number, string> = {
|
|
110
|
-
0: 'EEXIST',
|
|
111
|
-
1: 'EISDIR',
|
|
112
|
-
2: 'EACCES',
|
|
113
|
-
3: 'ENAMETOOLONG',
|
|
114
|
-
4: 'ENOENT',
|
|
115
|
-
5: 'ENOTDIR',
|
|
116
|
-
6: 'ENXIO',
|
|
117
|
-
7: 'ENODEV',
|
|
118
|
-
8: 'EROFS',
|
|
119
|
-
11: 'ELOOP',
|
|
120
|
-
12: 'ENOSPC',
|
|
121
|
-
13: 'ENOMEM',
|
|
122
|
-
14: 'EMFILE',
|
|
123
|
-
15: 'ENFILE',
|
|
124
|
-
16: 'EBADF',
|
|
125
|
-
17: 'EINVAL',
|
|
126
|
-
18: 'EPIPE',
|
|
127
|
-
21: 'EIO',
|
|
128
|
-
22: 'EPERM',
|
|
129
|
-
24: 'EIO',
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Map a GLib.FileError to a Node.js-style ErrnoException. Counterpart to
|
|
134
|
-
* `createNodeError` for the Gio.IOErrorEnum case; kept separate because the
|
|
135
|
-
* enum domains differ.
|
|
136
|
-
*/
|
|
137
|
-
export function createGLibFileError(
|
|
138
|
-
err: unknown,
|
|
139
|
-
syscall: string,
|
|
140
|
-
details?: NodeErrorDetails,
|
|
141
|
-
): ErrnoException {
|
|
142
|
-
const errObj = err as { code?: number; message?: string } | null | undefined;
|
|
143
|
-
const code = GLIB_FILE_ERROR_TO_NODE[errObj?.code ?? -1] ?? 'EIO';
|
|
144
|
-
|
|
145
|
-
let msg = `${code}: ${errObj?.message || 'unknown error'}, ${syscall}`;
|
|
146
|
-
if (details?.path) msg += ` '${details.path}'`;
|
|
147
|
-
if (details?.dest) msg += ` -> '${details.dest}'`;
|
|
148
|
-
|
|
149
|
-
const error = new Error(msg) as ErrnoException;
|
|
150
|
-
error.code = code;
|
|
151
|
-
error.syscall = syscall;
|
|
152
|
-
error.errno = -(errObj?.code || 0);
|
|
153
|
-
if (details?.path) error.path = details.path;
|
|
154
|
-
|
|
155
|
-
return error;
|
|
156
|
-
}
|
package/src/gio.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import Gio from '@girs/gio-2.0';
|
|
2
|
-
import GLib from '@girs/glib-2.0';
|
|
3
|
-
|
|
4
|
-
const byteArray = imports.byteArray;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Generic promise wrapper for Gio async/finish method pairs.
|
|
8
|
-
*
|
|
9
|
-
* Example:
|
|
10
|
-
* const stream = await gioAsync<Gio.InputStream>(session, 'send_async', 'send_finish', msg, priority, null);
|
|
11
|
-
*/
|
|
12
|
-
export function gioAsync<T>(
|
|
13
|
-
obj: any,
|
|
14
|
-
asyncMethod: string,
|
|
15
|
-
finishMethod: string,
|
|
16
|
-
...args: any[]
|
|
17
|
-
): Promise<T> {
|
|
18
|
-
return new Promise<T>((resolve, reject) => {
|
|
19
|
-
obj[asyncMethod](...args, (_self: any, asyncRes: Gio.AsyncResult) => {
|
|
20
|
-
try {
|
|
21
|
-
resolve(obj[finishMethod](asyncRes));
|
|
22
|
-
} catch (error) {
|
|
23
|
-
reject(error);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Promise wrapper around `Gio.InputStream.read_bytes_async` / `read_bytes_finish`.
|
|
31
|
-
* Returns a `Uint8Array` or `null` if the end of the stream is reached.
|
|
32
|
-
*/
|
|
33
|
-
export async function readBytesAsync(
|
|
34
|
-
inputStream: Gio.InputStream,
|
|
35
|
-
count = 4096,
|
|
36
|
-
ioPriority = GLib.PRIORITY_DEFAULT,
|
|
37
|
-
cancellable: Gio.Cancellable | null = null
|
|
38
|
-
): Promise<Uint8Array | null> {
|
|
39
|
-
return new Promise<Uint8Array | null>((resolve, reject) => {
|
|
40
|
-
inputStream.read_bytes_async(count, ioPriority, cancellable, (_self, asyncRes) => {
|
|
41
|
-
try {
|
|
42
|
-
const res = inputStream.read_bytes_finish(asyncRes);
|
|
43
|
-
if (res.get_size() === 0) {
|
|
44
|
-
return resolve(null);
|
|
45
|
-
}
|
|
46
|
-
return resolve(byteArray.fromGBytes(res));
|
|
47
|
-
} catch (error) {
|
|
48
|
-
reject(error);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Async generator that yields `Uint8Array` chunks from a `Gio.InputStream`.
|
|
56
|
-
*/
|
|
57
|
-
export async function* inputStreamAsyncIterator(
|
|
58
|
-
inputStream: Gio.InputStream,
|
|
59
|
-
count = 4096,
|
|
60
|
-
ioPriority = GLib.PRIORITY_DEFAULT,
|
|
61
|
-
cancellable: Gio.Cancellable | null = null
|
|
62
|
-
): AsyncGenerator<Uint8Array> {
|
|
63
|
-
let chunk: Uint8Array | null;
|
|
64
|
-
while ((chunk = await readBytesAsync(inputStream, count, ioPriority, cancellable)) !== null) {
|
|
65
|
-
yield chunk;
|
|
66
|
-
}
|
|
67
|
-
}
|
package/src/globals.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Shared utility for registering global polyfills.
|
|
2
|
-
// Used by web packages (abort-controller, dom-exception, streams, webcrypto, etc.)
|
|
3
|
-
// to consistently register globals only when they're missing.
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Register a value as a global property if it doesn't already exist.
|
|
7
|
-
* This is a no-op in environments where the global is already defined (e.g. Node.js).
|
|
8
|
-
*/
|
|
9
|
-
export function registerGlobal(name: string, value: unknown): void {
|
|
10
|
-
if (typeof (globalThis as any)[name] === 'undefined') {
|
|
11
|
-
(globalThis as any)[name] = value;
|
|
12
|
-
}
|
|
13
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export * from './callable.js';
|
|
2
|
-
export * from './base64.js';
|
|
3
|
-
export * from './byte-array.js';
|
|
4
|
-
export * from './cli.js';
|
|
5
|
-
export * from './defer.js';
|
|
6
|
-
export * from './encoding.js';
|
|
7
|
-
export * from './globals.js';
|
|
8
|
-
export * from './error.js';
|
|
9
|
-
export * from './file.js';
|
|
10
|
-
export * from './fs.js';
|
|
11
|
-
export * from './gio.js';
|
|
12
|
-
export * from './gio-errors.js';
|
|
13
|
-
export * from './message.js';
|
|
14
|
-
export * from './microtask.js';
|
|
15
|
-
export * from './next-tick.js';
|
|
16
|
-
export * from './path.js';
|
|
17
|
-
export * from './structured-clone.js';
|
|
18
|
-
export * from './main-loop.js';
|
package/src/log.spec.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { describe, it, assert, spy } from '@gjsify/unit';
|
|
2
|
-
// import { logSignals } from '@gjsify/utils';
|
|
3
|
-
// import type { StructuredLogData } from '@gjsify/utils';
|
|
4
|
-
|
|
5
|
-
const createUncaughtException = async () => {
|
|
6
|
-
throw new Error("top level error");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const sleep = (ms: number) => {
|
|
10
|
-
return new Promise(resolve => setTimeout(resolve, ms))
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default async () => {
|
|
14
|
-
await describe('logSignals', async () => {
|
|
15
|
-
// TODO: Fix this test
|
|
16
|
-
|
|
17
|
-
// await it("should emit an uncaughtException event on a top level throw", async () => {
|
|
18
|
-
// const onUnhandledRejection = spy((_self, _data: StructuredLogData, _promiseData) => {});
|
|
19
|
-
|
|
20
|
-
// const signalHandlerId = logSignals.connect("unhandledRejection", onUnhandledRejection);
|
|
21
|
-
|
|
22
|
-
// createUncaughtException();
|
|
23
|
-
|
|
24
|
-
// await sleep(10);
|
|
25
|
-
|
|
26
|
-
// logSignals.disconnect(signalHandlerId)
|
|
27
|
-
|
|
28
|
-
// assert.strictEqual(onUnhandledRejection.calls.length, 1, "onUnhandledRejection should be called.")
|
|
29
|
-
// // assert.strictEqual(onUnhandledRejection.calls[0].arguments[0], error)
|
|
30
|
-
// })
|
|
31
|
-
});
|
|
32
|
-
}
|