Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fengari-lua/fengari-interop

Fengari <=> JS Interop
https://github.com/fengari-lua/fengari-interop

fengari javascript js lua

Last synced: 1 day ago
JSON representation

Fengari <=> JS Interop

Awesome Lists containing this project

README

        

[![Build Status](https://github.com/fengari-lua/fengari-interop/actions/workflows/ci.yaml/badge.svg)](https://github.com/fengari-lua/fengari-interop/actions/workflows/ci.yaml?query=event%3Apush)
[![npm](https://img.shields.io/npm/v/fengari-interop.svg)](https://npmjs.com/package/fengari-interop)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![#fengari on libera.chat](https://img.shields.io/badge/chat-%23fengari-brightgreen)](https://web.libera.chat/?channels=#fengari)

# JS library for Fengari

[Fengari](https://github.com/fengari-lua/fengari) is a lua VM written in Javascript.
Its implementation makes use of the JS garbage collector, which means it is fully capable of cross language interop.

## Features

- Call any JS function from Lua
- Give Lua tables/functions/userdata to Javascript

## `js` library

```lua
js = require "js"
```

### `null`

A userdata representing JavaScript [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null)

### `global`

A reference to the JavaScript global context. In the browser, this is usually equivalent to the `window` object. In node.js it's equal to [`global`](https://nodejs.org/api/globals.html#globals_global).

### `new(constructor, ...)`

Invokes the JavaScript [`new` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new) on `constructor` passing the arguments specified.

Returns the created object.

### `of(iterable)`

Returns a iterating function and an iterator state that behave like a JavaScript [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) loop.
Suitable for use as a lua iterator. e.g.

```lua
for f in js.of(js.global:Array(10,20,30)) do
print(f)
end
```

*Note: this function only exists if the JavaScript runtime supports [Symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)*

### `createproxy(x[, type])`

*Note: Only available if your JS environment has the `Proxy` constructor*

Creates a JavaScript [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) object. The proxy supports configuring traps by setting them as metamethods on your object.

`type` may be `"function"` (the default) `"arrow_function"` or `"object"`:

- `"function"`:
- `typeof p === "function"`
- Can be used as a constructor
- `"arrow_function"`:
- `typeof p === "function"`
- Can **not** be used as a constructor
- `"object"`:
- `typeof p === "object"`
- Can **not** be used as a constructor

Note that JavaScript coerces all types except Symbols to strings before using them as a key in an indexing operation.

### `tonumber(x)`

Coerces the value `x` to a number using JavaScript coercion rules.

### `tostring(x)`

Coerces the value `x` to a string using JavaScript coercion rules.

### `instanceof(x, y)`

Returns if the value `x` is an instance of the class `y` via use of the JavaScript [`instanceof` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof)

### `typeof(x)`

Returns what JavaScript sees as the type of `x`. Uses the JavaScript [`typeof` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof)

## JavaScript API

### `push(L, value)`

Pushes an arbitrary JavaScript object `value` as the most suitable lua type onto the lua stack `L`.
Performs deduplication so that the same JavaScript objects are pushed as the same lua objects.

### `pushjs(L, value)`

Pushes an arbitrary JavaScript object `value` as a userdata onto the lua stack `L`.
Rarely used; see `push(L, value)` instead.

### `checkjs(L, idx)`

If the value on the lua stack `L` at index `idx` is a JavaScript userdata object (as pushed by `push` or `pushjs`) then return it.
Otherwise throw an error.

### `testjs(L, idx)`

If the value on the lua stack `L` at index `idx` is a JavaScript userdata object (as pushed by `push` or `pushjs`) then return it.
Otherwise returns `undefined`.

### `tojs(L, idx)`

Returns the object on the lua stack `L` at index `idx` as the most suitable javascript type.

- `nil` is returned as `undefined`
- booleans are returned as booleans
- numbers are returned as numbers
- strings are returned as JavaScript strings
(Note: this *can* throw an error if the lua string is not represenable as a JavaScript string)
- JavaScript userdata object (as pushed by `push` or `pushjs`) returns the pushed JavaScript object
- Other objects are returned wrapped in a JavaScript function object with methods:
- `apply(this, [args...])`: calls the lua object. Returns only the first return value
- `invoke(this, [args...])`: calls the lua object. Returns results as an array
- `get(key)`: indexes the lua object
- `has(key)`: checks if indexing the lua object results in `nil`
- `set(key, value)`
- `delete(key)`: sets the key to `nil`
- `toString()`
JavaScript arguments to these methods are passed in via `push()` and results are returned via `tojs()`.
Calling the function is equivalent to calling the lua function wrapped.

### `luaopen_js`

The entrypoint for loading the [js library](#js-library) into a fengari `lua_State`.
Usually passed to `luaL_requiref`.

## Symbols

If the JavaScript environment supports [Symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), then some runtime-wide symbols can be used to customise behaviour:

### `__pairs`

The `__pairs` Symbol can be used to describe how to iterate over a JavaScript object. Use `Symbol.for("__pairs")` to get the symbol. It should be used as a key on your objects, where the value is a function returning an object with three properties: `"iter"`, `"state"` and `"first"`.

`"iter"` should be a function that follows the standard [Lua generic for protocol](http://www.lua.org/manual/5.3/manual.html#3.3.5), that is, it gets called with your *state* (as `this`) and the previous value produced; it should return an array of values or `undefined` if done.

e.g. to make `pairs` on a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) return entries in the map via the [iterator symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator):

```js
Map.prototype[Symbol.for("__pairs")] = function() {
return {
iter: function(last) {
var v = this.next();
if (v.done) return;
return v.value;
},
state: this[Symbol.iterator]()
};
};
```

If there is no `__pairs` Symbol attached to an object, an iterator over [`Object.keys`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) is returned.

### `__len`

The `__len` Symbol can be used to describe how to get the length (used by the lua `#` operator) of a JavaScript object.
Use `Symbol.for("__len")` to get the symbol. It should be used as a key on your objects, where the value is a function returning the length of your objects (passed as `this`).

e.g. to have the lua `#` operator applied to a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) return the [`size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) field:

```js
Map.prototype[Symbol.for("__len")] = function() {
return this.size;
};
```

If there is no `__len` Symbol attached to an object, the value of the `.length` property is returned.