2.0.0-alpha.3 • Published 11 months ago

@gi.ts/lib v2.0.0-alpha.3

Weekly downloads
10
License
MIT
Repository
-
Last release
11 months ago

@gi.ts/lib

This package contains the core of gi.ts' logic. It is written to only depend directly on @gi.ts/parser and contains no dependencies on a specific JavaScript environment. It is typically run on Node.js, but could be run directly on GJS or in a browser.

How It Works

@gi.ts/lib is split up into 6 distinct "stages" which convert a parsed XML GIR file into an output format (most commonly .d.ts TypeScript definitions).

  1. Loading: loads XML strings from a file source
  2. Parsing: converts XML strings into a traversable tree
  3. Injection: injects additional types from GJS into the GIR data
  4. Transformation: applies automated and manual changes like adding inferred generics
  5. Generation: converts the tree into a desired format (e.g. a .d.ts file)
  6. Formatting: optionally makes the output look pretty (.d.ts uses prettier)

Loading

Currently implemented by @gi.ts/node-loader for @gi.ts/cli. The loader simply loads relevant XML files from the filesystem.

Parsing (fromXML)

Parsing has two stages: literally parsing XML strings and then transforming those parsed strings into a traversable tree.

XML string parsing

This is currently implemented by @gi.ts/parser using fast-xml-parser.

Tree API

In the gir/ directory there are "parsers" for every GObject Introspection type. Each parser is prefixed with Gir (e.g. GirClass, GirEnum) and they all implement a static function, fromXML which takes a parsed XML file and constructs the relevant type.

The goal of this stage is to transform XML definitions into a tree of JavaScript objects which can be manipulated and traversed in the later stages.

Collectively, gir/ forms the tree API of gi.ts.

At the heart of all of this is GirNSRegistry. This class holds all the state for a single "tree" of libraries. GirNSRegistry is also where transformers, generators, injections, and other modifications are registered.

Injecting Overrides

Next, gi.ts "injects" definitions for GJS bindings which aren't included in the autogenerated GIR files. GJS typically calls these "overrides" but we also inject core GJS class' like ParamSpec.

There are two types of injections: injections/[library] and generators/[format]/[library]. The injections in injections/[library] are written using gi.ts' tree API and are exposed to all output formats (e.g. .d.ts, .json, .html). Some injections only make sense for specific formats, however, so they are implemented alongside the generator. Currently only .d.ts has generator-specific injections. Some of these are implemented as generator-specific injections because it would simply be too complicated to express the TypeScript constructions using gi.ts' tree API.

Calling registry.transform on a GirNSRegistry triggers the injections.

Transformation

While a GirNSRegistry tree is mutable, transformations are typically done immutably so a reproducible tree exists before and after.

Transformations are registered using registry.registerTransformation which accepts a visitor. The tree API frequently uses the visitor pattern, with some modifications.

Calling registry.transform on a GirNSRegistry registers the default transformations, which are applied to the tree prior to generation.

Generics

There are both manual and automatic generic transformations.

Automatic Generification

In generics/visitor.ts, an automatic transformation looks for functions similar to:

function do_something(input: string): GObject.Object;

And transforms them to...

function do_something<T extends GObject.Object = GObject.Object>(input: string): T;

This is because often GObject Introspected libraries express "generics" as the base class GObject.Object, this transformation allows users to correctly type these calls.

A great example of this is Gtk.Builder and get_object which returns GObject.Object.

const builder = new Gtk.Builder(...);
const button = builder.get_object<Gtk.Button>('my_button_id');
Manual Generics

In addition to the automated transformations, gi.ts also adds generics to common libraries like GTK, St, Clutter, Gio, and more to ease the use of common APIs.

These changes can be found in generics/[library].ts for each respective library.

Generation

To generate an output for a given namespace you must acquire the relevant generator from GirNSRegistry by calling registry.getGenerator(format). registry.getGenerator('dts') and registry.getGenerator('json') are built-in. If you specify a different format GirNSRegistry uses this resolution strategy:

  1. Look for a package with the name @gi.ts/generator-[format]
  2.             ...with the name `gi-ts-generator-[format]`
  3.             ...with the name `[format]`

It expects the given package to have a default CommonJS export = set to a subclass of FormatGenerator (see generators/generator.ts).

The generator for .d.ts is at generators/dts.ts and the generator for .json is found at generators/json.ts.

The generateNamespace function of a generator must return a string (it gets printed to a file), but the individual generate[Type] functions can return any format the generator desires. .json returns Json types, .d.ts returns strings, and .html returns React render functions.

Formatting

The final (and simplest) step is formatting. @gi.ts/lib comes bundled with a formatter for .json files based on JavaScript's JSON.stringify utility. Parsing for other outputs must be implemented in external packages to keep @gi.ts/lib from depending on Node-specific APIs. Parsing for .d.ts files is implemented by @gi.ts/cli using Prettier's API.

You can register a formatter by calling registry.registerFormatter on GirNSRegistry.

A formatter is not required, if a formatter is not found gi.ts simply outputs whatever the generator provides from generateNamespace.

2.0.0-alpha.3

11 months ago

2.0.0-alpha.0

11 months ago

2.0.0-alpha.1

11 months ago

2.0.0-alpha.2

11 months ago

1.5.10

2 years ago

1.5.12

2 years ago

1.5.11

2 years ago

1.5.13

2 years ago

1.5.9

3 years ago

1.5.8

3 years ago

1.5.6

3 years ago

1.5.3

3 years ago

1.5.0

3 years ago

1.4.1

3 years ago

1.4.0

3 years ago

1.3.0

3 years ago

1.2.2

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago