@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 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};
@@ -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>