# Automate Electron IPC

[![Node LTS](https://img.shields.io/node/v-lts/automate-electron-ipc?style=flat&label=node&color=%231B7EBC)](https://nodejs.org/en/download/prebuilt-installer/current)
[![NPM License](https://img.shields.io/npm/l/automate-electron-ipc)](https://github.com/aabmets/automate-electron-ipc/blob/main/LICENSE)
[![Code Coverage](https://codecov.io/gh/aabmets/automate-electron-ipc/graph/badge.svg?token=xg3PJRlo3o)](https://codecov.io/gh/aabmets/automate-electron-ipc)
[![NPM Downloads](https://img.shields.io/npm/dw/automate-electron-ipc)](https://www.npmjs.com/package/automate-electron-ipc)

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)<br/>
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=bugs)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=aabmets_automate-electron-ipc&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)

### Description

Node library for generating IPC components for Electron apps.


### Features

1) Declarative IPC schema using channel expressions
2) Generation of sender and listener callables for the main process
3) Generation of preload bindings for renderer processes
4) Generation of typehints for the renderer Window object
5) Automatic import of user-defined types for generated components
6) BrowserWindow event triggers for MainToRenderer Broadcast channels


### Installation

`bun add automate-electron-ipc --dev`

`pnpm add automate-electron-ipc --save-dev`

`yarn add automate-electron-ipc --dev`

`npm install automate-electron-ipc --save-dev`


### Optional Configuration

You can configure IPC automation in the `package.json` file using the following options. 
If no configuration is provided, IPC automation will use the default values as shown in the example below.

```json
{
   "config": {
      "autoipc": {
         "projectUsesNodeNext": false,
         "ipcDataDir": "src/autoipc",
         "codeIndent": 3
      }
   }
}
```

Config explanation:
 - `projectUsesNodeNext` - Must be set to true when `moduleResolution` in `tsconfig.json` is `nodenext`.
 - `ipcDataDir` - Relative path to a directory within the users project which will contain the IPC schema expressions and where the IPC bindings will be generated into.
 - `codeIndent` - How many spaces will one code indentation level have within the generated IPC bindings.


### Getting Started

IPC bindings are generated by calling the `ipcgen` command provided by this library from the command line. 
When you initially run this command, you will get a warning about IPC channels not being found. 
Do not let this warning dissuade you, as it's purpose is to guide you where to create the schema 
file or directory, which will contain the channel expressions that will be parsed by IPC automation. 

By default, IPC automation looks for a file named `schema.ts` in the IPC data directory. 
If you create a directory named `schema` into the IPC data directory, then IPC automation 
will recursively parse all files within it for Channel expressions, meaning it is possible 
to structure and segment channel expressions according to the needs of larger applications. 


### Channel Expressions

IPC automation uses its own Domain-Specific Language to generate IPC bindings. We call this language `CHEX`, 
which masquerades itself as regular JavaScript/TypeScript, but it's code is never executed by Node. Instead, 
this library uses the TypeScript library internally to parse the channel expressions from schema files to 
deduce the meanings behind their definitions.

Since this library is well-documented through its type definitions, the developer is encouraged to use an IDE 
which facilitates easy type inference and hints within its user interface. To that end, you should configure your 
`tsconfig.node.json` to include the generated `main.ts` and `preload.ts` files from within the IPC data directory.
For the renderer process, you should include the generated `window.d.ts` file into your `tsconfig.web.json` file.

_Note: IPC automation does not make a distinction between senders/listeners and invokers/handlers as they are 
defined in the IPC documentation of the Electron library. Whether an IPC component is generated as a sender/listener
or invoker/handler under the hood depends on the direction and the kind of the channel expression. The reason
behind this design choice was to allow the user to focus on IPC arguments and return types without having to
concern themselves with IPC internals._


### Simple Example

Schema file content at path `src/autoipc/schema.ts`:
```typescript
import { Channel, type } from "automate-electron-ipc";

Channel("EchoUserName").RendererToMain.Broadcast({
   signature: type as (userName: string) => void
});
```

After IPC bindings have been generated by running `ipcgen`, they can be used as described below.  
_Note: For brevity sake, other important code related to BrowserWindow has been omitted._

In main process source code file `src/main/index.ts`:
```typescript
import { app } from "electron";
import { ipcMain } from "../autoipc/main";

app.whenReady().then(() => {
   ipcMain.onEchoUserName((event, userName) => console.log(`Greetings, ${userName}!`));
});
```

Anywhere in renderer process source code:
```html
<button onClick={() => window.ipc.sendEchoUserName("Anonymous")}>
```

The example code provides only basic HTML, because this library is front-end-tech agnostic,
meaning you can use any front-end framework or library like React, Vue or Angular.


### Channel Directions and Kinds

Channels may be defined with three directions:

```typescript
Channel("Channel1").RendererToMain  // IPC call from a renderer process to the main process

Channel("Channel2").MainToRenderer  // IPC call from the main process to a renderer process

Channel("Channel3").RendererToRenderer  // Port binding between two renderer processes
```

Each direction supports specific kinds of transmissions:

```typescript
Channel("Channel1").RendererToMain.Broadcast()  // Message from one sender to one or multiple listeners without return data

Channel("Channel2").RendererToMain.Unicast()  // Message from one sender to one listener with return data

Channel("Channel3").MainToRenderer.Broadcast()  // Message from one sender to one or multiple listeners without return data

Channel("Channel4").RendererToRenderer.Port()  // Sender and listener on same port for each process
```
