@gjsify/oxfmt-native 0.4.44
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/README.md +45 -0
- package/lib/esm/_virtual/_rolldown/runtime.js +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/types/index.d.ts +46 -0
- package/meson.build +87 -0
- package/package.json +74 -0
- package/prebuilds/linux-x86_64/GjsifyOxfmt-1.0.gir +65 -0
- package/prebuilds/linux-x86_64/GjsifyOxfmt-1.0.typelib +0 -0
- package/prebuilds/linux-x86_64/libgjsify_oxfmt.so +0 -0
- package/prebuilds/linux-x86_64/libgjsifyoxfmt.so +0 -0
- package/src/rust/Cargo.lock +613 -0
- package/src/rust/Cargo.toml +38 -0
- package/src/rust/src/lib.rs +274 -0
- package/src/vala/gjsify-oxfmt-glue.c +63 -0
- package/src/vala/gjsify-oxfmt-glue.h +55 -0
- package/src/vala/gjsify-oxfmt.h +46 -0
- package/src/vala/oxfmt.vala +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @gjsify/oxfmt-native
|
|
2
|
+
|
|
3
|
+
A native Rust cdylib + Vala/GObject bridge that wraps oxc's formatter ([oxfmt](https://oxc.rs/docs/guide/usage/formatter)) and exposes it to GJS via `gi://`. This is the formatter engine used by `gjsify format` / `gjsify fix` under GJS — npm's `oxfmt` is a Rust N-API binary that cannot load in GJS, so this bridge is how gjsify formats without a Node runtime. The bridge links oxfmt's pure-Rust CLI core, so the full CLI surface runs in-process: `.oxfmtrc(.json)` + `.editorconfig` resolution, ignore handling, parallel file walking, `--write` / `--check` / `--list-different`. Ships prebuilt `.so` + `.gir` + `.typelib` for Linux.
|
|
4
|
+
|
|
5
|
+
Part of the [gjsify](https://github.com/gjsify/gjsify) project — Node.js and Web APIs for GJS (GNOME JavaScript).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gjsify install @gjsify/oxfmt-native
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { hasNativeOxfmt, format, runOxfmt } from '@gjsify/oxfmt-native';
|
|
17
|
+
|
|
18
|
+
if (hasNativeOxfmt()) {
|
|
19
|
+
// Single-shot in-memory format (Prettier-compatible defaults)
|
|
20
|
+
console.log(format('const x:number=1', 'input.ts'));
|
|
21
|
+
// => "const x: number = 1;\n"
|
|
22
|
+
|
|
23
|
+
// Full oxfmt CLI in-process (argv WITHOUT the program name).
|
|
24
|
+
// Honors .oxfmtrc(.json) / .editorconfig, prints to stdout/stderr,
|
|
25
|
+
// returns the process exit code.
|
|
26
|
+
const code = runOxfmt(['--check', '--config', '/abs/.oxfmtrc.json', 'src']);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Not covered (requires oxfmt's Node-API host by design): the embedded CSS/HTML/Vue/Markdown Prettier `ExternalFormatter`, JS/TS config files (`.oxfmtrc.ts`), `--init` / `--migrate`, LSP and stdin mode.
|
|
31
|
+
|
|
32
|
+
Under normal usage `@gjsify/oxfmt-native` is consumed automatically by the gjsify CLI (`gjsify format`, `gjsify fix`) — direct use is only needed when embedding the formatter in custom tooling.
|
|
33
|
+
|
|
34
|
+
## Building from source
|
|
35
|
+
|
|
36
|
+
The Rust shim path-deps into the `refs/oxc` submodule (pinned to the `oxfmt_v*` tag matching the workspace's npm `oxfmt` devDependency — `oxc_formatter` is yanked on crates.io, the formatter lives in-tree only):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git submodule update --init refs/oxc
|
|
40
|
+
gjsify workspace @gjsify/oxfmt-native build:prebuilds # needs meson + vala + cargo
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});export{__name};
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";function gi(){return globalThis.imports?.gi}let e=null,t=!1,n=null;function loadNativeOxfmt(){if(t)return e;t=!0;try{let t=gi();if(!t)return n=Error(`imports.gi not available — not running under GJS?`),null;let r=t.GjsifyOxfmt;return r?(e=r,e):(n=Error(`GjsifyOxfmt typelib not found on GI_TYPELIB_PATH`),null)}catch(t){return n=t instanceof Error?t:Error(String(t)),e=null,null}}function hasNativeOxfmt(){return loadNativeOxfmt()!==null}function getOxfmtLoadError(){return n}function format(e,t=`input.ts`){let r=loadNativeOxfmt();if(!r)throw n??Error(`@gjsify/oxfmt-native: prebuild not available`);let i=gi()?.GLib;if(!i)throw Error(`@gjsify/oxfmt-native: GLib not available (not running under GJS?)`);let a=new i.Bytes(new TextEncoder().encode(e)),o=new r.Formatter().format(t,a)?.get_data()??new Uint8Array;return new TextDecoder().decode(o)}function runOxfmt(e){let t=loadNativeOxfmt();if(!t)throw n??Error(`@gjsify/oxfmt-native: prebuild not available`);return new t.Formatter().run(e)}export{format,getOxfmtLoadError,hasNativeOxfmt,loadNativeOxfmt,runOxfmt};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Minimal structural type of the `gi://GjsifyOxfmt` `Formatter` GObject. */
|
|
2
|
+
interface FormatterInstance {
|
|
3
|
+
/** Format `code`, typed from `filename`'s extension. Throws on fatal error. */
|
|
4
|
+
format(filename: string | null, code: unknown): unknown;
|
|
5
|
+
/** Run the oxfmt CLI in-process (argv WITHOUT program name) → exit code. */
|
|
6
|
+
run(args: string[]): number;
|
|
7
|
+
}
|
|
8
|
+
interface FormatterCtor {
|
|
9
|
+
new (): FormatterInstance;
|
|
10
|
+
}
|
|
11
|
+
export interface NativeOxfmtModule {
|
|
12
|
+
Formatter: FormatterCtor;
|
|
13
|
+
}
|
|
14
|
+
export declare function loadNativeOxfmt(): NativeOxfmtModule | null;
|
|
15
|
+
/** True when the native oxfmt prebuild is loadable under the current runtime. */
|
|
16
|
+
export declare function hasNativeOxfmt(): boolean;
|
|
17
|
+
/** The error from the last failed `loadNativeOxfmt()`, if any. */
|
|
18
|
+
export declare function getOxfmtLoadError(): Error | null;
|
|
19
|
+
/**
|
|
20
|
+
* Format JS/TS/JSX `code` via oxc's formatter, under GJS, without Node.
|
|
21
|
+
* `filename` selects the dialect by extension (default: TypeScript).
|
|
22
|
+
* Throws if the native prebuild is unavailable or formatting fails.
|
|
23
|
+
*/
|
|
24
|
+
export declare function format(code: string, filename?: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Run the full oxfmt CLI in-process, under GJS, without Node.
|
|
27
|
+
*
|
|
28
|
+
* `args` are the CLI arguments WITHOUT the program name
|
|
29
|
+
* (`process.argv.slice(2)` shaped) — e.g.
|
|
30
|
+
* `['--check', '--config', '/abs/.oxfmtrc.json', 'src']`. This covers the
|
|
31
|
+
* complete pure-Rust oxfmt surface: `.oxfmtrc(.json)` + `.editorconfig`
|
|
32
|
+
* resolution, ignore handling, parallel file walking, `--write` /
|
|
33
|
+
* `--check` / `--list-different`. Reports to stdout/stderr exactly like
|
|
34
|
+
* the npm `oxfmt` binary. The working directory is the current process
|
|
35
|
+
* working directory.
|
|
36
|
+
*
|
|
37
|
+
* Not covered (requires oxfmt's Node-API host): embedded CSS/HTML/Vue/
|
|
38
|
+
* Markdown via the Prettier ExternalFormatter, JS/TS config files
|
|
39
|
+
* (`.oxfmtrc.ts`), `--init` / `--migrate`, LSP and stdin mode.
|
|
40
|
+
*
|
|
41
|
+
* Returns the process exit code (0 = success, 1 = config error or
|
|
42
|
+
* `--check` mismatch, 2 = no files found / format failed). Throws if the
|
|
43
|
+
* native prebuild is unavailable.
|
|
44
|
+
*/
|
|
45
|
+
export declare function runOxfmt(args: string[]): number;
|
|
46
|
+
export {};
|
package/meson.build
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
project('GjsifyOxfmt', ['c', 'vala'], version: '1.0')
|
|
2
|
+
|
|
3
|
+
# Required system packages (Fedora 43+):
|
|
4
|
+
# dnf install vala meson ninja-build cargo
|
|
5
|
+
# and the refs/oxc submodule:
|
|
6
|
+
# git submodule update --init refs/oxc
|
|
7
|
+
#
|
|
8
|
+
# Pipeline:
|
|
9
|
+
# src/rust/ → cargo builds libgjsify_oxfmt.so (cdylib, against refs/oxc)
|
|
10
|
+
# src/vala/ → vala compiles GjsifyOxfmt-1.0.so + GIR + typelib
|
|
11
|
+
# The Vala lib links against the Rust cdylib via -lgjsify_oxfmt.
|
|
12
|
+
|
|
13
|
+
cc = meson.get_compiler('c')
|
|
14
|
+
|
|
15
|
+
vala_deps = [
|
|
16
|
+
dependency('glib-2.0'),
|
|
17
|
+
dependency('gobject-2.0'),
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
# ----------------------------------------------------------------------------
|
|
21
|
+
# Rust cdylib (cargo)
|
|
22
|
+
#
|
|
23
|
+
# Single custom_target combining `cargo build` and copying the resulting
|
|
24
|
+
# cdylib into the meson build dir under the expected name, so meson tracks
|
|
25
|
+
# it as a build artifact and serializes the Vala link step behind it.
|
|
26
|
+
# ----------------------------------------------------------------------------
|
|
27
|
+
cargo = find_program('cargo')
|
|
28
|
+
|
|
29
|
+
rust_sources = files(
|
|
30
|
+
'src/rust/Cargo.toml',
|
|
31
|
+
'src/rust/src/lib.rs',
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
rust_target_dir = meson.current_build_dir() / 'cargo-target'
|
|
35
|
+
|
|
36
|
+
rust_cdylib = custom_target('gjsify-oxfmt-rust',
|
|
37
|
+
input: rust_sources,
|
|
38
|
+
output: 'libgjsify_oxfmt.so',
|
|
39
|
+
command: ['sh', '-c',
|
|
40
|
+
'cargo build --release --manifest-path "$1" --target-dir "$2" && cp "$2/release/libgjsify_oxfmt.so" "$3"',
|
|
41
|
+
'sh',
|
|
42
|
+
meson.current_source_dir() / 'src/rust/Cargo.toml',
|
|
43
|
+
rust_target_dir,
|
|
44
|
+
'@OUTPUT@',
|
|
45
|
+
],
|
|
46
|
+
build_by_default: true,
|
|
47
|
+
install: false,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# ----------------------------------------------------------------------------
|
|
51
|
+
# Vala library + GIR + typelib
|
|
52
|
+
# ----------------------------------------------------------------------------
|
|
53
|
+
sources = files(
|
|
54
|
+
'src/vala/gjsify-oxfmt-glue.c',
|
|
55
|
+
'src/vala/oxfmt.vala',
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
inc = include_directories('src/vala')
|
|
59
|
+
|
|
60
|
+
# Tell ld where to find libgjsify_oxfmt.so (placed there by rust_cdylib)
|
|
61
|
+
link_args = ['-L' + meson.current_build_dir(), '-lgjsify_oxfmt']
|
|
62
|
+
|
|
63
|
+
libGjsifyOxfmt = library('gjsifyoxfmt', sources,
|
|
64
|
+
dependencies: vala_deps,
|
|
65
|
+
include_directories: inc,
|
|
66
|
+
vala_gir: meson.project_name() + '-1.0.gir',
|
|
67
|
+
link_args: link_args,
|
|
68
|
+
link_depends: rust_cdylib,
|
|
69
|
+
install: true,
|
|
70
|
+
install_dir: [true, true, true, true],
|
|
71
|
+
install_rpath: '$ORIGIN',
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
g_ir_compiler = find_program('g-ir-compiler')
|
|
75
|
+
|
|
76
|
+
custom_target(meson.project_name() + '-1.0.typelib',
|
|
77
|
+
command: [
|
|
78
|
+
g_ir_compiler,
|
|
79
|
+
'--shared-library', 'libgjsifyoxfmt.so',
|
|
80
|
+
'--output', '@OUTPUT@',
|
|
81
|
+
meson.current_build_dir() / meson.project_name() + '-1.0.gir',
|
|
82
|
+
],
|
|
83
|
+
output: meson.project_name() + '-1.0.typelib',
|
|
84
|
+
depends: libGjsifyOxfmt,
|
|
85
|
+
install: true,
|
|
86
|
+
install_dir: get_option('libdir') / 'girepository-1.0',
|
|
87
|
+
)
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gjsify/oxfmt-native",
|
|
3
|
+
"version": "0.4.44",
|
|
4
|
+
"description": "Vala/GObject + Rust cdylib bridge to oxc's formatter (oxfmt) for GJS. Formats JavaScript/TypeScript/JSX under GJS without a Node runtime — the Node-free counterpart to the npm `oxfmt` native napi binary, backing `gjsify format` under GJS. Wraps oxc_formatter (Prettier-compatible) via a single-shot FFI; the embedded CSS/HTML/Markdown ExternalFormatter (Prettier-NAPI) is out of scope.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/esm/index.js",
|
|
7
|
+
"module": "lib/esm/index.js",
|
|
8
|
+
"types": "lib/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./lib/types/index.d.ts",
|
|
12
|
+
"default": "./lib/esm/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib",
|
|
17
|
+
"prebuilds",
|
|
18
|
+
"meson.build",
|
|
19
|
+
"src/rust",
|
|
20
|
+
"src/vala"
|
|
21
|
+
],
|
|
22
|
+
"gjsify": {
|
|
23
|
+
"prebuilds": "prebuilds",
|
|
24
|
+
"runtimes": {
|
|
25
|
+
"gjs": "polyfill",
|
|
26
|
+
"node": "none",
|
|
27
|
+
"browser": "none",
|
|
28
|
+
"nativescript": "none"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"clear": "rm -rf lib build tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo || exit 0",
|
|
33
|
+
"check": "gjsify tsc --noEmit",
|
|
34
|
+
"init:meson": "meson setup build .",
|
|
35
|
+
"init:meson:wipe": "gjsify run init:meson --wipe",
|
|
36
|
+
"build": "gjsify run build:gjsify && gjsify run build:types",
|
|
37
|
+
"build:gjsify": "gjsify build --library 'src/ts/**/*.{ts,js}'",
|
|
38
|
+
"build:meson": "gjsify run init:meson && meson compile -C build",
|
|
39
|
+
"build:types": "gjsify tsc",
|
|
40
|
+
"build:prebuilds": "gjsify run build:meson && mkdir -p prebuilds/linux-x86_64 && cp build/libgjsifyoxfmt.so build/libgjsify_oxfmt.so build/GjsifyOxfmt-1.0.gir build/GjsifyOxfmt-1.0.typelib prebuilds/linux-x86_64/"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"gjs",
|
|
44
|
+
"oxc",
|
|
45
|
+
"oxfmt",
|
|
46
|
+
"formatter",
|
|
47
|
+
"prettier",
|
|
48
|
+
"typescript",
|
|
49
|
+
"vala",
|
|
50
|
+
"rust",
|
|
51
|
+
"native"
|
|
52
|
+
],
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@girs/gjs": "4.0.4",
|
|
55
|
+
"@girs/glib-2.0": "2.88.0-4.0.4",
|
|
56
|
+
"@girs/gobject-2.0": "2.88.0-4.0.4"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@gjsify/cli": "workspace:^",
|
|
60
|
+
"@types/node": "^25.9.2",
|
|
61
|
+
"typescript": "^6.0.3"
|
|
62
|
+
},
|
|
63
|
+
"author": "Pascal Garber <pascal@artandcode.studio>",
|
|
64
|
+
"license": "MIT",
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/gjsify/gjsify.git",
|
|
68
|
+
"directory": "packages/infra/oxfmt-native"
|
|
69
|
+
},
|
|
70
|
+
"bugs": {
|
|
71
|
+
"url": "https://github.com/gjsify/gjsify/issues"
|
|
72
|
+
},
|
|
73
|
+
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/infra/oxfmt-native#readme"
|
|
74
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
<!-- GjsifyOxfmt-1.0.gir generated by valac 0.56.19, do not modify. -->
|
|
3
|
+
<repository version="1.2" xmlns="http://www.gtk.org/introspection/core/1.0" xmlns:c="http://www.gtk.org/introspection/c/1.0" xmlns:doc="http://www.gtk.org/introspection/doc/1.0" xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
|
|
4
|
+
<include name="GObject" version="2.0"/>
|
|
5
|
+
<include name="GLib" version="2.0"/>
|
|
6
|
+
<package name="gjsifyoxfmt"/>
|
|
7
|
+
<c:include name="gjsify-oxfmt-glue.h"/>
|
|
8
|
+
<c:include name="gjsifyoxfmt.h"/>
|
|
9
|
+
<doc:format name="unknown"/>
|
|
10
|
+
<namespace name="GjsifyOxfmt" version="1.0" shared-library="libgjsifyoxfmt.so" c:prefix="GjsifyOxfmt" c:identifier-prefixes="GjsifyOxfmt" c:symbol-prefixes="gjsify_oxfmt">
|
|
11
|
+
<class name="Formatter" c:type="GjsifyOxfmtFormatter" c:symbol-prefix="formatter" glib:type-name="GjsifyOxfmtFormatter" glib:get-type="gjsify_oxfmt_formatter_get_type" glib:type-struct="FormatterClass" parent="GObject.Object">
|
|
12
|
+
<field name="parent_instance" readable="0" private="1">
|
|
13
|
+
<type name="GObject.Object" c:type="GObject"/>
|
|
14
|
+
</field>
|
|
15
|
+
<field name="priv" readable="0" private="1">
|
|
16
|
+
<type name="FormatterPrivate" c:type="GjsifyOxfmtFormatterPrivate*"/>
|
|
17
|
+
</field>
|
|
18
|
+
<method name="format" c:identifier="gjsify_oxfmt_formatter_format" throws="1">
|
|
19
|
+
<return-value transfer-ownership="full">
|
|
20
|
+
<type name="GLib.Bytes" c:type="GBytes*"/>
|
|
21
|
+
</return-value>
|
|
22
|
+
<parameters>
|
|
23
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
24
|
+
<type name="GjsifyOxfmt.Formatter" c:type="GjsifyOxfmtFormatter*"/>
|
|
25
|
+
</instance-parameter>
|
|
26
|
+
<parameter name="filename" transfer-ownership="none" nullable="1">
|
|
27
|
+
<type name="utf8" c:type="const gchar*"/>
|
|
28
|
+
</parameter>
|
|
29
|
+
<parameter name="code" transfer-ownership="none">
|
|
30
|
+
<type name="GLib.Bytes" c:type="GBytes*"/>
|
|
31
|
+
</parameter>
|
|
32
|
+
</parameters>
|
|
33
|
+
</method>
|
|
34
|
+
<method name="run" c:identifier="gjsify_oxfmt_formatter_run">
|
|
35
|
+
<return-value transfer-ownership="full">
|
|
36
|
+
<type name="gint" c:type="gint"/>
|
|
37
|
+
</return-value>
|
|
38
|
+
<parameters>
|
|
39
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
40
|
+
<type name="GjsifyOxfmt.Formatter" c:type="GjsifyOxfmtFormatter*"/>
|
|
41
|
+
</instance-parameter>
|
|
42
|
+
<parameter name="args" transfer-ownership="none">
|
|
43
|
+
<array length="1" c:type="gchar**">
|
|
44
|
+
<type name="utf8" c:type="gchar*"/>
|
|
45
|
+
</array>
|
|
46
|
+
</parameter>
|
|
47
|
+
<parameter name="args_length1" transfer-ownership="none">
|
|
48
|
+
<type name="gint" c:type="gint"/>
|
|
49
|
+
</parameter>
|
|
50
|
+
</parameters>
|
|
51
|
+
</method>
|
|
52
|
+
<constructor name="new" c:identifier="gjsify_oxfmt_formatter_new">
|
|
53
|
+
<return-value transfer-ownership="full">
|
|
54
|
+
<type name="GjsifyOxfmt.Formatter" c:type="GjsifyOxfmtFormatter*"/>
|
|
55
|
+
</return-value>
|
|
56
|
+
</constructor>
|
|
57
|
+
</class>
|
|
58
|
+
<record name="FormatterClass" c:type="GjsifyOxfmtFormatterClass" glib:is-gtype-struct-for="Formatter">
|
|
59
|
+
<field name="parent_class" readable="0" private="1">
|
|
60
|
+
<type name="GObject.ObjectClass" c:type="GObjectClass"/>
|
|
61
|
+
</field>
|
|
62
|
+
</record>
|
|
63
|
+
<record name="FormatterPrivate" c:type="GjsifyOxfmtFormatterPrivate" disguised="1"/>
|
|
64
|
+
</namespace>
|
|
65
|
+
</repository>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|