Full Code of retejs/rete for AI

main 2aae19950180 cached
32 files
45.2 KB
12.9k tokens
96 symbols
1 requests
Download .txt
Repository: retejs/rete
Branch: main
Commit: 2aae19950180
Files: 32
Total size: 45.2 KB

Directory structure:
gitextract_whez86aj/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── build-push.yml
│       ├── ci.yml
│       ├── codeql.yml
│       ├── commit-linter.yml
│       ├── release.yml
│       ├── stale.yml
│       └── update-docs.yml
├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── eslint.config.mjs
├── package.json
├── postinstall.js
├── rete.config.ts
├── src/
│   ├── editor.ts
│   ├── index.ts
│   ├── presets/
│   │   └── classic.ts
│   ├── scope.ts
│   ├── types.ts
│   ├── utility-types.ts
│   └── utils.ts
├── test/
│   ├── index.perf.ts
│   ├── index.test.ts
│   ├── mocks/
│   │   └── crypto.ts
│   ├── presets/
│   │   └── classic.test.ts
│   ├── scope.test.ts
│   └── utils.test.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
patreon: ni55an
open_collective: rete


================================================
FILE: .github/workflows/build-push.yml
================================================
name: Build and Push
run-name: Build and Push to dist/${{ github.ref_name }}

on:
  workflow_dispatch:

jobs:
  push:
    uses: retejs/.github/.github/workflows/build-push.yml@main


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  workflow_dispatch:
  pull_request:
    branches: [ "main", "beta" ]

jobs:
  ci:
    uses: retejs/.github/.github/workflows/ci.yml@main
    secrets: inherit


================================================
FILE: .github/workflows/codeql.yml
================================================
name: CodeQL

on:
  workflow_dispatch:
  push:
    branches: [ "main", "beta" ]
  pull_request:
    branches: [ "main", "beta" ]

jobs:
  codeql:
    uses: retejs/.github/.github/workflows/codeql.yml@main


================================================
FILE: .github/workflows/commit-linter.yml
================================================
name: Commit linter

on:
  pull_request:
    branches: [ "main", "beta" ]

jobs:
  lint:
    uses: retejs/.github/.github/workflows/commit-linter.yml@main


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  workflow_dispatch:
  push:
    branches: [ "main", "beta" ]

jobs:
  release:
    uses: retejs/.github/.github/workflows/release.yml@main
    secrets: inherit


================================================
FILE: .github/workflows/stale.yml
================================================
name: Close stale issues and PRs

on:
  workflow_dispatch:
  schedule:
    - cron: '30 1 * * 0'

jobs:
  stale:
    uses: retejs/.github/.github/workflows/stale.yml@main
    secrets: inherit


================================================
FILE: .github/workflows/update-docs.yml
================================================
name: Update docs

on:
  workflow_dispatch:
  push:
    branches: [ "main" ]

jobs:
  pull:
    uses: retejs/.github/.github/workflows/update-docs.yml@main
    secrets: inherit
    with:
      filename: '1.rete'
      package: rete


================================================
FILE: .gitignore
================================================
node_modules
.idea/
.vscode/
.sonarlint
.scannerwork
.nyc_output
/coverage
npm-debug.log
/dist
docs
.rete-cli
.sonar


================================================
FILE: CHANGELOG.md
================================================
## [2.0.6](https://github.com/retejs/rete/compare/v2.0.5...v2.0.6) (2025-06-30)


### Bug Fixes

* improve concurrent behavior of removeNode and removeConnection ([4229f1f](https://github.com/retejs/rete/commit/4229f1f0772a581bce7174080fb05870109bdd62))
* optimize node and connection removal logic ([0696cba](https://github.com/retejs/rete/commit/0696cbaa1a1b3fd2a14cc6dd0312a783300d0fe7))

## [2.0.5](https://github.com/retejs/rete/compare/v2.0.4...v2.0.5) (2024-08-30)


### Bug Fixes

* build ([1f852d9](https://github.com/retejs/rete/commit/1f852d9e491522264d97de396a30d5f0faf2a681))

## [2.0.4](https://github.com/retejs/rete/compare/v2.0.3...v2.0.4) (2024-08-30)


### Bug Fixes

* update cli and fix linting errors ([d219f95](https://github.com/retejs/rete/commit/d219f95cb0d46f79e8d7f5d70e4afcd578f35455))

## [2.0.3](https://github.com/retejs/rete/compare/v2.0.2...v2.0.3) (2024-01-27)


### Bug Fixes

* **build:** source maps ([121775c](https://github.com/retejs/rete/commit/121775c90aac1db449b30284ba996eed1da1a03c))

## [2.0.2](https://github.com/retejs/rete/compare/v2.0.1...v2.0.2) (2023-07-24)


### Bug Fixes

* **editor:** return copy of array in getNodes/getConnections ([369e85e](https://github.com/retejs/rete/commit/369e85e5d661cca5e9de86326c2245c0e2f38d5b))

## v2.0.0-beta.8

Improve Scope typing: validate signals in `use` method, infer return type in `emit` method


================================================
FILE: CODE_OF_CONDUCT.md
================================================
Check out the [Code of Conduct](https://retejs.org/docs/code-of-conduct)


================================================
FILE: CONTRIBUTING.md
================================================
Check out the [Contribution guide](https://retejs.org/docs/contribution)


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2023 "Ni55aN" Vitaliy Stoliarov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
Rete.js
====
[![Made in Ukraine](https://img.shields.io/badge/made_in-ukraine-ffd700.svg?labelColor=0057b7)](https://stand-with-ukraine.pp.ua)
[![Discord](https://img.shields.io/discord/1081223198055604244?color=%237289da&label=Discord)](https://discord.gg/cxSFkPZdsV)

**JavaScript framework for visual programming**

![rete logo](https://raw.githubusercontent.com/retejs/rete/assets/preview.svg)

#StandWithUkraine 💙💛
----

#RussiaInvadedUkraine on 24 of February 2022, at 5.00 AM the armed forces of the Russian Federation  attacked Ukraine. Please, Stand with Ukraine, stay tuned for updates on Ukraine’s official sources and channels in English and support Ukraine in its fight for freedom and democracy in Europe.

Help to defend Ukraine — donate to [Ukraine’s main charity fund](https://savelife.in.ua/en/donate/)

Help to defend Ukraine — donate to the [fund of the National Bank of Ukraine](https://ukraine.ua/news/donate-to-the-nbu-fund/)


Introduction [🎥](https://youtu.be/xqPLa6P194A)
----

**Rete.js** is a framework for creating visual interfaces and workflows. It provides out-of-the-box solutions for visualization using various libraries and frameworks, as well as solutions for processing graphs based on dataflow and control flow approaches.


Getting started
----

Use [Rete Kit](https://retejs.org/docs/development/rete-kit) to quickly set up a Rete.js application. It lets you select a stack (React.js, Vue.js or Angular, Svelte) and the set of features

```bash
npx rete-kit app
```

Alternatively, you can follow the [complete guide](https://retejs.org/docs/getting-started/)

Documentation
----

- [Introduction](https://retejs.org/docs)
- [Guides](https://retejs.org/docs/guides/basic)
- [Examples](https://retejs.org/examples)

## Sponsors

Thank you to all our sponsors! [Become a sponsor](https://opencollective.com/rete#sponsor)

<a href="https://opencollective.com/rete#sponsors" target="_blank"><img src="https://opencollective.com/rete/sponsors.svg?width=890"></a>

## Backers

Thank you to all our backers! [Become a backer](https://opencollective.com/rete#backer)

<a href="https://opencollective.com/rete#backers" target="_blank"><img src="https://opencollective.com/rete/backers.svg?width=890"></a>


## Contributors

This project exists thanks to all the people who contribute. [Contribute](https://retejs.org/docs/contribution).

<a href="https://github.com/retejs/rete/graphs/contributors"><img src="https://opencollective.com/rete/contributors.svg?width=890" /></a>

## License

[MIT](https://github.com/retejs/rete/blob/main/LICENSE)


================================================
FILE: eslint.config.mjs
================================================
import tseslint from 'typescript-eslint';
import configs from 'rete-cli/configs/eslint.mjs';

export default tseslint.config(
  ...configs
)

================================================
FILE: package.json
================================================
{
  "name": "rete",
  "version": "2.0.6",
  "description": "JavaScript framework",
  "scripts": {
    "build": "rete build -c rete.config.ts",
    "postinstall": "node postinstall.js",
    "doc": "rete doc",
    "lint": "rete lint",
    "test": "rete test",
    "perf": "rete perf"
  },
  "author": "Vitaliy Stoliarov",
  "license": "MIT",
  "keywords": [
    "dataflow",
    "visual programming",
    "node editor",
    "rete",
    "Rete.js"
  ],
  "homepage": "https://retejs.org",
  "repository": {
    "type": "git",
    "url": "https://github.com/retejs/rete.git"
  },
  "bugs": {
    "url": "https://github.com/retejs/rete/issues"
  },
  "devDependencies": {
    "jest-environment-jsdom": "^29.1.2",
    "rete-cli": "^2.1.0"
  },
  "dependencies": {
    "@babel/runtime": "^7.21.0"
  }
}


================================================
FILE: postinstall.js
================================================
function getRectangle(width, height, color) {
  const line = new Array(width).fill(' ').join('')

  return new Array(height).fill(color(line)).join('\n')
}

function drawText(x, y, text) {
  const save = '\033[s'
  const restore = '\033[u'
  const up = n => '\033['+n+'A'
  const right = n => '\033['+n+'C'

  return `${save}${up(y)}${right(x)}${text}${restore}`
}

function black(text) {
  return '\x1b[30m' + text + '\x1b[0m'
}

function white(text) {
  return '\x1b[37m' + text + '\x1b[0m'
}

function bgBlue(text) {
  return '\x1b[44m' + text + '\x1b[0m'
}

function bgYellow(text) {
  return '\x1b[43m' + text + '\x1b[0m'
}

const topText = 'Stand with Ukraine'
const bottomText = 'Please check the Rete.js\'s README for details'

const top = getRectangle(50, 5, bgBlue)
const bottom = getRectangle(50, 5, bgYellow)

// eslint-disable-next-line max-len, no-console
console.log(`${top}\n${drawText(16, 3, white(bgBlue(topText)))}${bottom}\n${drawText(2, 3, black(bgYellow(bottomText)))}`)


================================================
FILE: rete.config.ts
================================================
import { ReteOptions } from 'rete-cli'
import copy from 'rollup-plugin-copy'

export default <ReteOptions>{
  input: 'src/index.ts',
  name: 'Rete',
  globals: {
    crypto: 'crypto'
  },
  plugins: [
    copy({
      targets: [
        { src: 'postinstall.js', dest: 'dist' }
      ]
    })
  ]
}


================================================
FILE: src/editor.ts
================================================
import { Scope } from './scope'
import { BaseSchemes } from './types'

/**
 * Signal types produced by NodeEditor instance
 * @typeParam Scheme - The scheme type
 * @priority 10
 * @group Primary
 */
export type Root<Scheme extends BaseSchemes> =
  | { type: 'nodecreate', data: Scheme['Node'] }
  | { type: 'nodecreated', data: Scheme['Node'] }
  | { type: 'noderemove', data: Scheme['Node'] }
  | { type: 'noderemoved', data: Scheme['Node'] }
  | { type: 'connectioncreate', data: Scheme['Connection'] }
  | { type: 'connectioncreated', data: Scheme['Connection'] }
  | { type: 'connectionremove', data: Scheme['Connection'] }
  | { type: 'connectionremoved', data: Scheme['Connection'] }
  | { type: 'clear' }
  | { type: 'clearcancelled' }
  | { type: 'cleared' }

/**
 * The NodeEditor class is the entry class. It is used to create and manage nodes and connections.
 * @typeParam Scheme - The scheme type
 * @priority 7
 * @group Primary
 */
export class NodeEditor<Scheme extends BaseSchemes> extends Scope<Root<Scheme>> {
  private nodes: Scheme['Node'][] = []
  private connections: Scheme['Connection'][] = []

  constructor() {
    super('NodeEditor')
  }

  /**
   * Get a node by id
   * @param id - The node id
   * @returns The node or undefined
   */
  public getNode(id: Scheme['Node']['id']) {
    return this.nodes.find(node => node.id === id)
  }

  /**
   * Get all nodes
   * @returns Copy of array with nodes
   */
  public getNodes() {
    return this.nodes.slice()
  }

  /**
   * Get all connections
   * @returns Copy of array with onnections
   */
  public getConnections() {
    return this.connections.slice()
  }

  /**
   * Get a connection by id
   * @param id - The connection id
   * @returns The connection or undefined
   */
  public getConnection(id: Scheme['Connection']['id']) {
    return this.connections.find(connection => connection.id === id)
  }

  /**
   * Add a node
   * @param data - The node data
   * @returns Whether the node was added
   * @throws If the node has already been added
   * @emits nodecreate
   * @emits nodecreated
   */
  async addNode(data: Scheme['Node']) {
    if (this.getNode(data.id)) throw new Error('node has already been added')

    if (!await this.emit({ type: 'nodecreate', data })) return false

    this.nodes.push(data)

    await this.emit({ type: 'nodecreated', data })
    return true
  }

  /**
   * Add a connection
   * @param data - The connection data
   * @returns Whether the connection was added
   * @throws If the connection has already been added
   * @emits connectioncreate
   * @emits connectioncreated
   */
  async addConnection(data: Scheme['Connection']) {
    if (this.getConnection(data.id)) throw new Error('connection has already been added')

    if (!await this.emit({ type: 'connectioncreate', data })) return false

    this.connections.push(data)

    await this.emit({ type: 'connectioncreated', data })
    return true
  }

  /**
   * Remove a node
   * @param id - The node id
   * @returns Whether the node was removed
   * @throws If the node cannot be found
   * @emits noderemove
   * @emits noderemoved
   */
  async removeNode(id: Scheme['Node']['id']) {
    const node = this.nodes.find(n => n.id === id)

    if (!node) throw new Error('cannot find node')

    if (!await this.emit({ type: 'noderemove', data: node })) return false

    const index = this.nodes.indexOf(node)

    this.nodes.splice(index, 1)

    await this.emit({ type: 'noderemoved', data: node })
    return true
  }

  /**
   * Remove a connection
   * @param id - The connection id
   * @returns Whether the connection was removed
   * @throws If the connection cannot be found
   * @emits connectionremove
   * @emits connectionremoved
   */
  async removeConnection(id: Scheme['Connection']['id']) {
    const connection = this.connections.find(c => c.id === id)

    if (!connection) throw new Error('cannot find connection')

    if (!await this.emit({ type: 'connectionremove', data: connection })) return false

    const index = this.connections.indexOf(connection)

    this.connections.splice(index, 1)

    await this.emit({ type: 'connectionremoved', data: connection })
    return true
  }

  /**
   * Clear all nodes and connections
   * @returns Whether the editor was cleared
   * @emits clear
   * @emits clearcancelled
   * @emits cleared
   */
  async clear() {
    if (!await this.emit({ type: 'clear' })) {
      await this.emit({ type: 'clearcancelled' })
      return false
    }

    for (const connection of this.connections.slice()) await this.removeConnection(connection.id)
    for (const node of this.nodes.slice()) await this.removeNode(node.id)

    await this.emit({ type: 'cleared' })
    return true
  }
}


================================================
FILE: src/index.ts
================================================
export * from './editor'
export * as ClassicPreset from './presets/classic'
export type { CanAssignSignal, NestedScope, Pipe, ScopeAsParameter } from './scope'
export { Scope, Signal } from './scope'
export * from './types'
export * from './utils'


================================================
FILE: src/presets/classic.ts
================================================
/**
 * Contains classes for classic scheme such as Node, Input, Output, Control, Socket, Connection
 * @module
 * @group Primary
 */

import { ConnectionBase, NodeBase } from '../types'
import { getUID } from '../utils'

type PortId = string

/**
 * The socket class
 * @priority 7
 */
export class Socket {
  /**
   * @constructor
   * @param name Name of the socket
   */
  constructor(public name: string) {

  }
}

/**
 * General port class
 */
export class Port<S extends Socket> {
  /**
   * Port id, unique string generated by `getUID` function
   */
  id: PortId
  /**
   * Port index, used for sorting ports. Default is `0`
   */
  index?: number

  /**
   * @constructor
   * @param socket Socket instance
   * @param label Label of the port
   * @param multipleConnections Whether the output port can have multiple connections
   */
  constructor(public socket: S, public label?: string, public multipleConnections?: boolean) {
    this.id = getUID()
  }
}

/**
 * The input port class
 * @priority 6
 */
export class Input<S extends Socket> extends Port<S> {
  /**
   * Control instance
   */
  control: Control | null = null
  /**
   * Whether the control is visible. Can be managed dynamically by extensions. Default is `true`
   */
  showControl = true

  /**
   * @constructor
   * @param socket Socket instance
   * @param label Label of the input port
   * @param multipleConnections Whether the output port can have multiple connections. Default is `false`
   */
  constructor(public socket: S, public label?: string, public multipleConnections?: boolean) {
    super(socket, label, multipleConnections)
  }

  /**
   * Add control to the input port
   * @param control Control instance
   */
  addControl(control: Control) {
    if (this.control) throw new Error('control already added for this input')
    this.control = control
  }

  /**
   * Remove control from the input port
   */
  removeControl() {
    this.control = null
  }
}

/**
 * The output port class
 * @priority 5
 */
export class Output<S extends Socket> extends Port<S> {
  /**
   * @constructor
   * @param socket Socket instance
   * @param label Label of the output port
   * @param multipleConnections Whether the output port can have multiple connections. Default is `true`
   */
  constructor(socket: S, label?: string, multipleConnections?: boolean) {
    super(socket, label, multipleConnections !== false)
  }
}

/**
 * General control class
 * @priority 5
 */
export class Control {
  /**
   * Control id, unique string generated by `getUID` function
   */
  id: string
  /**
   * Control index, used for sorting controls. Default is `0`
   */
  index?: number

  constructor() {
    this.id = getUID()
  }
}

/**
 * Input control options
 */
type InputControlOptions<N> = {
  /** Whether the control is readonly. Default is `false` */
  readonly?: boolean
  /** Initial value of the control */
  initial?: N
  /** Callback function that is called when the control value changes */
  change?: (value: N) => void
}
/**
 * The input control class
 * @example new InputControl('text', { readonly: true, initial: 'hello' })
 */
export class InputControl<T extends 'text' | 'number', N = T extends 'text' ? string : number> extends Control {
  value?: N
  readonly: boolean

  /**
   * @constructor
   * @param type Type of the control: `text` or `number`
   * @param options Control options
   */
  constructor(public type: T, public options?: InputControlOptions<N>) {
    super()
    this.id = getUID()
    this.readonly = options?.readonly ?? false

    if (typeof options?.initial !== 'undefined') this.value = options.initial
  }

  /**
   * Set control value
   * @param value Value to set
   */
  setValue(value?: N) {
    this.value = value
    if (this.options?.change) this.options.change(value!)
  }
}

/**
 * The node class
 * @priority 10
 * @example new Node('math')
 */
export class Node<
  Inputs extends { [key in string]?: Socket } = { [key in string]?: Socket },
  Outputs extends { [key in string]?: Socket } = { [key in string]?: Socket },
  Controls extends { [key in string]?: Control } = { [key in string]?: Control }
> implements NodeBase {
  /**
   * Node id, unique string generated by `getUID` function
   */
  id: NodeBase['id']
  /**
   * Node inputs
   */
  inputs: { [key in keyof Inputs]?: Input<Exclude<Inputs[key], undefined>> } = {}
  /**
   * Node outputs
   */
  outputs: { [key in keyof Outputs]?: Output<Exclude<Outputs[key], undefined>> } = {}
  /**
   * Node controls
   */
  controls: Controls = {} as Controls
  /**
   * Whether the node is selected. Default is `false`
   */
  selected?: boolean

  constructor(public label: string) {
    this.id = getUID()
  }

  hasInput<K extends keyof Inputs>(key: K) {
    return Object.prototype.hasOwnProperty.call(this.inputs, key)
  }

  addInput<K extends keyof Inputs>(key: K, input: Input<Exclude<Inputs[K], undefined>>) {
    if (this.hasInput(key)) throw new Error(`input with key '${String(key)}' already added`)

    Object.defineProperty(this.inputs, key, { value: input, enumerable: true, configurable: true })
  }

  removeInput(key: keyof Inputs) {
    delete this.inputs[key]
  }

  hasOutput<K extends keyof Outputs>(key: K) {
    return Object.prototype.hasOwnProperty.call(this.outputs, key)
  }

  addOutput<K extends keyof Outputs>(key: K, output: Output<Exclude<Outputs[K], undefined>>) {
    if (this.hasOutput(key)) throw new Error(`output with key '${String(key)}' already added`)

    Object.defineProperty(this.outputs, key, { value: output, enumerable: true, configurable: true })
  }

  removeOutput(key: keyof Outputs) {
    delete this.outputs[key]
  }

  hasControl<K extends keyof Controls>(key: K) {
    return Object.prototype.hasOwnProperty.call(this.controls, key)
  }

  addControl<K extends keyof Controls>(key: K, control: Controls[K]) {
    if (this.hasControl(key)) throw new Error(`control with key '${String(key)}' already added`)

    Object.defineProperty(this.controls, key, { value: control, enumerable: true, configurable: true })
  }

  removeControl(key: keyof Controls) {
    delete this.controls[key]
  }
}

/**
 * The connection class
 * @priority 9
 */
export class Connection<
  Source extends Node,
  Target extends Node
> implements ConnectionBase {
  /**
   * Connection id, unique string generated by `getUID` function
   */
  id: ConnectionBase['id']
  /**
   * Source node id
   */
  source: NodeBase['id']
  /**
   * Target node id
   */
  target: NodeBase['id']

  /**
   * @constructor
   * @param source Source node instance
   * @param sourceOutput Source node output key
   * @param target Target node instance
   * @param targetInput Target node input key
   */
  constructor(
    source: Source,
    public sourceOutput: keyof Source['outputs'],
    target: Target,
    public targetInput: keyof Target['inputs']
  ) {
    if (!source.outputs[sourceOutput as string]) {
      throw new Error(`source node doesn't have output with a key ${String(sourceOutput)}`)
    }
    if (!target.inputs[targetInput as string]) {
      throw new Error(`target node doesn't have input with a key ${String(targetInput)}`)
    }

    this.id = getUID()
    this.source = source.id
    this.target = target.id
  }
}


================================================
FILE: src/scope.ts
================================================
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/naming-convention */
import {
  AcceptPartialUnion, CanAssignSignal, GetAssignmentReferences, GetNonAssignableElements, Tail
} from './utility-types'

export type { CanAssignSignal }

/**
 * A middleware type that can modify the data
 * @typeParam T - The data type
 * @param data - The data to be modified
 * @returns The modified data or undefined
 * @example (data) => data + 1
 * @example (data) => undefined // will stop the execution
 * @internal
 */
export type Pipe<T> = (data: T) => Promise<undefined | T> | undefined | T

export type CanAssignEach<D extends any[], F extends any[]> = D extends [infer H1, ...infer Tail1]
  ? (
    F extends [infer H2, ...infer Tail2] ?
      [CanAssignSignal<H1, H2>, ...CanAssignEach<Tail1, Tail2>]
      : []
  ) : []

export type ScopeAsParameter<S extends Scope<any, any[]>, Current extends any[]> = (CanAssignEach<[S['__scope']['produces'], ...S['__scope']['parents']], Current>[number] extends true
  ? S
  : 'Argument Scope does not provide expected signals'
)

/**
 * Validate the Scope signals and replace the parameter type with an error message if they are not assignable
 * @internal
 */
export type NestedScope<S extends Scope<any, any[]>, Current extends any[]> = (CanAssignEach<Current, S['__scope']['parents']>[number] extends true
  ? S
  : 'Parent signals do not satisfy the connected scope. Please use `.debug($ => $) for detailed assignment error'
)

/**
 * Provides 'debug' method to check the detailed assignment error message
 * @example .debug($ => $)
 * @internal
 */
export function useHelper<S extends Scope<any, any[]>, Signals>() {
  type T1 = S['__scope']['parents'][number]
  return {
    debug<T extends GetNonAssignableElements<T1, Signals>>(_f: (p: GetAssignmentReferences<T, Signals>) => T) {
      /* placeholder */
    }
  }
}

/**
 * A signal is a middleware chain that can be used to modify the data
 * @typeParam T - The data type
 * @internal
 */
export class Signal<T> {
  pipes: Pipe<T>[] = []

  addPipe(pipe: Pipe<T>) {
    this.pipes.push(pipe)
  }

  async emit<Context extends T>(context: Context): Promise<Context | undefined> {
    let current: Context | undefined = context

    for (const pipe of this.pipes) {
      current = await pipe(current) as Context

      if (typeof current === 'undefined') return
    }
    return current
  }
}

type Type<T> = (new(...args: any[]) => T) | (abstract new (...args: any[]) => T)

/**
 * Base class for all plugins and the core. Provides a signals mechanism to modify the data
 */
export class Scope<Produces, Parents extends unknown[] = []> {
  signal = new Signal<AcceptPartialUnion<Produces | Parents[number]>>()
  parent?: any // Parents['length'] extends 0 ? undefined : Scope<Parents[0], Tail<Parents>>
  __scope!: {
    produces: Produces
    parents: Parents
  }

  constructor(public name: string) { }

  addPipe(middleware: Pipe<Produces | Parents[number]>) {
    this.signal.addPipe(middleware)
  }

  use<S extends Scope<any, any[]>>(scope: NestedScope<S, [Produces, ...Parents]>) {
    if (!(scope instanceof Scope)) throw new Error('cannot use non-Scope instance')

    scope.setParent(this)
    this.addPipe(context => {
      return scope.signal.emit(context)
    })

    return useHelper<S, Produces | Parents[number]>()
  }

  setParent(scope: Scope<Parents[0], Tail<Parents>>) {
    this.parent = scope
  }

  emit<C extends Produces>(context: C): Promise<Extract<Produces, C> | undefined> {
    return this.signal.emit(context) as Promise<Extract<Produces, C>>
  }

  hasParent(): boolean {
    return Boolean(this.parent)
  }

  parentScope<T extends Parents[0], P extends Tail<Parents>>(): Scope<T, P>
  parentScope<T>(type: Type<T>): T
  parentScope<T>(type?: Type<T>): T {
    if (!this.parent) throw new Error('cannot find parent')
    if (type && this.parent instanceof type) return this.parent
    if (type) throw new Error('actual parent is not instance of type')
    return this.parent
  }
}


================================================
FILE: src/types.ts
================================================
/**
 * Node id type
 */
export type NodeId = string
/**
 * Connection id type
 * @group Primary
 */
export type ConnectionId = string

/**
 * The base node type
 * @group Primary
 */
export type NodeBase = { id: NodeId }
/**
 * The base connection type
 * @group Primary
 */
export type ConnectionBase = { id: ConnectionId, source: NodeId, target: NodeId }

/**
 * Get the schemes
 * @example GetSchemes<Node & { myProp: number }, Connection>
 * @group Primary
 */
export type GetSchemes<NodeData extends NodeBase, ConnectionData extends ConnectionBase> = { Node: NodeData, Connection: ConnectionData }

/**
 * The base schemes
 * @group Primary
 */
export type BaseSchemes = GetSchemes<NodeBase, ConnectionBase>


================================================
FILE: src/utility-types.ts
================================================
/* eslint-disable @typescript-eslint/no-explicit-any */

// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
export type AcceptPartialUnion<T> = T | any

export type Tail<T extends any[]> = ((...args: T) => void) extends (head: any, ...tail: infer U) => any ? U : never

export type UnionToIntersection<U> = (
  U extends never ? never : (arg: U) => never
) extends (arg: infer I) => void
  ? I
  : never

type StrictExcludeInner<T, U> = 0 extends (
  U extends T ? [T] extends [U] ? 0 : never : never
) ? never : T
export type StrictExclude<T, U> = T extends unknown ? StrictExcludeInner<T, U> : never

export type UnionToTuple<T> = UnionToIntersection<
  T extends never ? never : (t: T) => T
> extends (_: never) => infer W
  ? [...UnionToTuple<StrictExclude<T, W>>, W]
  : []

export type FilterMatch<T extends any[], V> = T extends [infer Head, ...infer _Tail]
  ? ([Head] extends [V]
    ? [Head, ...FilterMatch<_Tail, V>]
    : FilterMatch<_Tail, V>
  ) : []

export type CanAssignToAnyOf<Provides, Requires> = FilterMatch<UnionToTuple<Provides>, Requires> extends [] ? false : true

export type CanAssignEachTupleElemmentToAnyOf<Provides, Requires extends any[]> = Requires extends [infer Head, ...infer _Tail]
  ? CanAssignToAnyOf<Provides, Head> extends true ?
    (_Tail extends []
      ? true
      : CanAssignEachTupleElemmentToAnyOf<Provides, _Tail>
    ) : false
  : false

export type CanAssignEachToAnyOf<Provides, Requires> = CanAssignEachTupleElemmentToAnyOf<Provides, UnionToTuple<Requires>>

export type CanAssignSignal<Provides, Requires> = CanAssignEachToAnyOf<Provides, Requires>

type ReplaceTupleTypes<T extends any[], U> = { [K in keyof T]: U }
export type FilterNever<T extends any[]> = T extends [infer Head, ...infer _Tail]
  ? ([Head] extends [never] ? FilterNever<_Tail> : [Head, ...FilterNever<_Tail>])
  : []

type KeepIfNonAssignable<T, Signals> = CanAssignToAnyOf<Signals, T> extends false ? T : never

export type GetAllNonValidElements<T extends any[], Signals> = T extends [infer Head, ...infer _Tail]
  ? ([KeepIfNonAssignable<Head, Signals>, ...GetAllNonValidElements<_Tail, Signals>])
  : []

export type GetNonAssignableElements<T, Signals>
  = FilterNever<GetAllNonValidElements<UnionToTuple<T>, Signals>>
export type GetAssignmentReferences<AssignableElements extends any[], Signals> = ReplaceTupleTypes<AssignableElements, Signals>


================================================
FILE: src/utils.ts
================================================
const crypto = globalThis.crypto as (typeof globalThis.crypto | typeof import('node:crypto'))

/**
 * @returns A unique id
 */
export function getUID(): string {
  if ('randomBytes' in crypto) {
    return crypto.randomBytes(8).toString('hex')
  }

  const bytes = crypto.getRandomValues(new Uint8Array(8))
  const array = Array.from(bytes)
  const hexPairs = array.map(b => b.toString(16).padStart(2, '0'))

  return hexPairs.join('')
}


================================================
FILE: test/index.perf.ts
================================================
import { describe, it } from '@jest/globals'

import { BaseSchemes } from '../src'
import { NodeEditor } from '../src/editor'

const iterations = 5

describe('NodeEditor', () => {
  for (let iteration = 0; iteration < iterations; iteration++) {
    describe(`remove nodes (${iteration})`, () => {
      // eslint-disable-next-line init-declarations
      let editor!: NodeEditor<BaseSchemes>

      const ids = new Array(5_000).fill(0)
        // eslint-disable-next-line @typescript-eslint/naming-convention
        .map((_, i) => i)
      const idsToRemove = [...ids].reverse()

      beforeEach(async () => {
        editor = new NodeEditor<BaseSchemes>()
        await Promise.all(ids.map(id => editor.addNode({ id: `s${id}` })))
      })

      it('basic', async () => {
        await Promise.all(idsToRemove.map(id => editor.removeNode(`s${id}`)))
      })
    })
  }

  for (let iteration = 0; iteration < iterations; iteration++) {
    describe(`remove connections (${iteration})`, () => {
      // eslint-disable-next-line init-declarations
      let editor!: NodeEditor<BaseSchemes>

      const ids = new Array(3_000).fill(0)
        // eslint-disable-next-line @typescript-eslint/naming-convention
        .map((_, i) => i)
      const idsToRemove = [...ids].reverse()

      beforeEach(async () => {
        editor = new NodeEditor<BaseSchemes>()
        await Promise.all(ids.map(id => editor.addNode({ id: `s${id}` })))
        await Promise.all(ids.map(id => editor.addNode({ id: `t${id}` })))
        await Promise.all(ids.map(id => editor.addConnection({ id: `c${id}`, source: `s${id}`, target: `t${id}` })))
      })

      it('basic', async () => {
        await Promise.all(idsToRemove.map(id => editor.removeConnection(`c${id}`)))
      })
    })
  }
})


================================================
FILE: test/index.test.ts
================================================
import { describe, expect, it } from '@jest/globals'

import { NodeEditor } from '../src/editor'

describe('NodeEditor', () => {
  it('NodeEditor is instantiable', () => {
    expect(new NodeEditor()).toBeInstanceOf(NodeEditor)
  })

  it('addNode should add a node', async () => {
    const editor = new NodeEditor()
    const nodeData = { id: '1', label: 'Node 1' }
    const result = await editor.addNode(nodeData)
    const nodes = editor.getNodes()

    expect(result).toBe(true)
    expect(nodes).toHaveLength(1)
    expect(nodes[0]).toEqual(nodeData)
  })

  it('addNode should not add a node with duplicate id', async () => {
    const editor = new NodeEditor()
    const nodeData = { id: '1', label: 'Node 1' }

    await editor.addNode(nodeData)

    await expect(() => editor.addNode(nodeData)).rejects.toThrowError()
  })

  it('addConnection should add a connection', async () => {
    const editor = new NodeEditor()
    const connectionData = { id: '1', source: '1', target: '2' }

    await editor.addNode({ id: '1' })
    await editor.addNode({ id: '2' })
    const result = await editor.addConnection(connectionData)
    const connections = editor.getConnections()

    expect(result).toBe(true)
    expect(connections).toHaveLength(1)
    expect(connections[0]).toEqual(connectionData)
  })

  it('addConnection should not add a connection with duplicate id', async () => {
    const editor = new NodeEditor()
    const connectionData = { id: '1', source: '1', target: '2' }

    await editor.addNode({ id: '1' })
    await editor.addNode({ id: '2' })
    await editor.addConnection(connectionData)

    await expect(() => editor.addConnection(connectionData)).rejects.toThrowError()
  })

  it('removeNode should remove a node', async () => {
    const editor = new NodeEditor()
    const nodeData = { id: '1', label: 'Node 1' }

    await editor.addNode(nodeData)
    await editor.removeNode('1')
    const nodes = editor.getNodes()

    expect(nodes).toHaveLength(0)
  })

  it('removeNode should remove specified nodes', async () => {
    const editor = new NodeEditor()

    const ids = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

    await Promise.all(ids.map(id => editor.addNode({ id: id })))

    const removeIds = ['1', '2', '3', '4', '5']

    await Promise.all(removeIds.map(id => editor.removeNode(id)))

    const remainIds = editor.getNodes().map(n => n.id)

    await editor.clear()

    expect(remainIds).toEqual(['6', '7', '8', '9', '10'])
  })

  it('removeConnection should remove a connection', async () => {
    const editor = new NodeEditor()
    const connectionData = { id: '1', source: '1', target: '2' }

    await editor.addNode({ id: '1' })
    await editor.addNode({ id: '2' })
    await editor.addConnection(connectionData)
    await editor.removeConnection('1')
    const connections = editor.getConnections()

    expect(connections).toHaveLength(0)
  })

  it('removeConnection should remove specified connections', async () => {
    const editor = new NodeEditor()

    const ids = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

    await Promise.all(ids.map(id => editor.addNode({ id: `s${id}` })))
    await Promise.all(ids.map(id => editor.addNode({ id: `t${id}` })))
    await Promise.all(ids.map(id => editor.addConnection({ id: id, source: `s${id}`, target: `t${id}` })))

    const removeIds = ['1', '2', '3', '4', '5']

    await Promise.all(removeIds.map(id => editor.removeConnection(id)))

    const remainIds = editor.getConnections().map(c => c.id)

    await editor.clear()

    expect(remainIds).toEqual(['6', '7', '8', '9', '10'])
  })

  it('should clear all nodes and connections', async () => {
    const editor = new NodeEditor()

    await editor.addNode({ id: '1' })
    await editor.addNode({ id: '2' })
    await editor.addConnection({ id: '1', source: '1', target: '2' })
    await editor.clear()
    const nodes = editor.getNodes()
    const connections = editor.getConnections()

    expect(nodes).toHaveLength(0)
    expect(connections).toHaveLength(0)
  })
})



================================================
FILE: test/mocks/crypto.ts
================================================
import { jest } from '@jest/globals'
import { Buffer } from 'buffer'

export function mockCrypto(object: Record<string, unknown>) {
  // eslint-disable-next-line no-undef
  Object.defineProperty(globalThis, 'crypto', {
    value: object,
    writable: true
  })
}

export function mockCryptoFromArray(array: Uint8Array) {
  mockCrypto({
    getRandomValues: jest.fn().mockReturnValue(array)
  })
}

export function mockCryptoFromBuffer(buffer: Buffer) {
  mockCrypto({
    randomBytes: jest.fn().mockReturnValue(buffer)
  })
}

export function resetCrypto() {
  // eslint-disable-next-line no-undef
  Object.defineProperty(globalThis, 'crypto', {
    // eslint-disable-next-line no-undefined
    value: undefined,
    writable: true
  })
}


================================================
FILE: test/presets/classic.test.ts
================================================
import { afterEach, beforeEach, describe, expect, it } from '@jest/globals'

import { mockCryptoFromArray, resetCrypto } from '../mocks/crypto'

describe('ClassicPreset', () => {
  // eslint-disable-next-line init-declarations
  let preset!: typeof import('../../src/presets/classic')

  beforeEach(async () => {
    mockCryptoFromArray(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))
    preset = await import('../../src/presets/classic')
  })

  afterEach(() => {
    resetCrypto()
  })

  describe('Node', () => {
    it('is instantiable', () => {
      expect(new preset.Node('A')).toBeInstanceOf(preset.Node)
    })

    it('should have an id', () => {
      const node = new preset.Node('A')

      expect(node.id).toBeDefined()
    })

    it('should have a label', () => {
      const node = new preset.Node('A')

      expect(node.label).toBe('A')
    })

    it('adds Input', () => {
      const node = new preset.Node('A')
      const input = new preset.Input(new preset.Socket('a'))

      node.addInput('a', input)

      expect(node.hasInput('a')).toBeTruthy()
      expect(node.inputs.a).toBe(input)
    })

    it('throws error if Input already exists', () => {
      const node = new preset.Node('A')

      node.addInput('a', new preset.Input(new preset.Socket('a')))

      expect(() => node.addInput('a', new preset.Input(new preset.Socket('a')))).toThrow()
    })

    it('removes Input', () => {
      const node = new preset.Node('A')

      node.addInput('a', new preset.Input(new preset.Socket('a')))
      node.removeInput('a')

      expect(node.hasInput('a')).toBeFalsy()
    })

    it('adds Output', () => {
      const node = new preset.Node('A')
      const output = new preset.Output(new preset.Socket('a'))

      node.addOutput('a', output)

      expect(node.hasOutput('a')).toBeTruthy()
      expect(node.outputs.a).toBe(output)
    })

    it('throws error if Output already exists', () => {
      const node = new preset.Node('A')

      node.addOutput('a', new preset.Output(new preset.Socket('a')))

      expect(() => node.addOutput('a', new preset.Output(new preset.Socket('a')))).toThrow()
    })

    it('removes Output', () => {
      const node = new preset.Node('A')

      node.addOutput('a', new preset.Output(new preset.Socket('a')))
      node.removeOutput('a')

      expect(node.hasOutput('a')).toBeFalsy()
    })
  })

  describe('Connection', () => {
    it('Connection throws error if input not found', () => {
      const a = new preset.Node('A')
      const b = new preset.Node('B')

      a.addOutput('a', new preset.Output(new preset.Socket('a')))

      expect(() => new preset.Connection(a, 'a', b, 'b')).toThrow()
    })

    it('Connection throws error if output not found', () => {
      const a = new preset.Node('A')
      const b = new preset.Node('B')

      b.addInput('b', new preset.Input(new preset.Socket('b')))

      expect(() => new preset.Connection(a, 'a', b, 'b')).toThrow()
    })

    it('Connection is instantiable', () => {
      const a = new preset.Node('A')
      const b = new preset.Node('B')
      const output = new preset.Output(new preset.Socket('b'))
      const input = new preset.Input(new preset.Socket('a'))

      a.addOutput('a', output)
      b.addInput('b', input)

      expect(new preset.Connection(a, 'a', b, 'b')).toBeInstanceOf(preset.Connection)
    })
  })

  describe('Control', () => {
    it('adds Control to Node', () => {
      const node = new preset.Node('A')

      node.addControl('ctrl', new preset.Control())

      expect(node.hasControl('ctrl')).toBeTruthy()
    })

    it('throws error if Control already exists', () => {
      const node = new preset.Node('A')

      node.addControl('ctrl', new preset.Control())

      expect(() => node.addControl('ctrl', new preset.Control())).toThrow()
    })

    it('removes Control from Node', () => {
      const node = new preset.Node('A')

      node.addControl('ctrl', new preset.Control())
      node.removeControl('ctrl')

      expect(node.hasControl('ctrl')).toBeFalsy()
    })

    it('adds Control to Input', () => {
      const input = new preset.Input(new preset.Socket('a'))

      input.addControl(new preset.Control())

      expect(input.control).toBeTruthy()
    })

    it('throws error if Control in Input already exists', () => {
      const input = new preset.Input(new preset.Socket('a'))

      input.addControl(new preset.Control())

      expect(() => input.addControl(new preset.Control())).toThrow()
    })

    it('removes Control from Input', () => {
      const input = new preset.Input(new preset.Socket('a'))

      input.addControl(new preset.Control())
      input.removeControl()

      expect(input.control).toBeFalsy()
    })
  })
})


================================================
FILE: test/scope.test.ts
================================================
import { describe, expect, it, jest } from '@jest/globals'

import { Scope } from '../src/scope'

type Parent = { parent: string }
type Child = { child: number }

describe('Scope', () => {
  it('should create a new Scope instance', () => {
    const scope = new Scope('test')

    expect(scope).toBeInstanceOf(Scope)
  })

  it('doesnt have a parent by default', () => {
    const scope = new Scope<Parent>('test')

    expect(scope.hasParent()).toBeFalsy()
  })

  describe('parent-child', () => {
    it('should set a parent scope', () => {
      const parent = new Scope<Parent>('parent')
      const child = new Scope<Child, [Parent]>('child')

      child.setParent(parent)

      expect(child.parentScope()).toBe(parent)
    })

    it('should use a nested scope', () => {
      const parent = new Scope<Parent>('parent')
      const child = new Scope<Child, [Parent]>('child')

      parent.use(child)
      expect(child.hasParent()).toBeTruthy()
      expect(child.parentScope()).toBe(parent)
    })

    it('should throw an error when using a non-Scope instance', () => {
      const parent = new Scope<Parent>('parent')
      const child = { signal: { emit: jest.fn() } }

      expect(() => parent.use(child as any)).toThrowError('cannot use non-Scope instance')
    })

    it('should throw an error when trying to access a parent without one', () => {
      const scope = new Scope<Parent>('test')

      expect(() => scope.parentScope()).toThrowError('cannot find parent')
    })

    it('should throw an error when trying to access a parent with the wrong type', () => {
      class WrongScope<T> extends Scope<T> { }
      const parent = new Scope<Parent>('parent')
      const child = new Scope<Child, [Parent]>('child')

      parent.use(child)

      expect(() => child.parentScope(WrongScope)).toThrowError('actual parent is not instance of type')
    })
  })

  describe('addPipe', () => {
    it('should emit a signal', async () => {
      const scope = new Scope<Parent>('test')
      const pipe = jest.fn<() => Parent>()

      scope.addPipe(pipe)
      await scope.emit({ parent: 'test' })

      expect(pipe).toHaveBeenCalledWith({ parent: 'test' })
    })

    it('should return a promise from emit', () => {
      const scope = new Scope<Parent>('test')
      const signal = jest.fn<() => Parent>()

      scope.addPipe(signal)
      const result = scope.emit({ parent: 'test' })

      expect(result).toBeInstanceOf(Promise)
    })

    it('should return the result of the signal', async () => {
      const scope = new Scope<Parent>('test')
      const signal = jest.fn<() => Parent>().mockReturnValue({ parent: 'test-result' })

      scope.addPipe(signal)
      const result = await scope.emit({ parent: 'test' })

      expect(result).toEqual({ parent: 'test-result' })
    })

    it('should return undefined if the signal returns undefined', async () => {
      const scope = new Scope('test')
      // eslint-disable-next-line no-undefined
      const signal = jest.fn().mockReturnValue(undefined)

      scope.addPipe(signal)
      const result = await scope.emit('test')

      expect(result).toBeUndefined()
    })

    it('should return the result of the signal with a parent', async () => {
      const parent = new Scope<Parent>('parent')
      const child = new Scope<Child, [Parent]>('child')
      const signal = jest.fn<() => Parent>().mockReturnValue({ parent: 'test-parent' })

      parent.addPipe(signal)
      parent.use(child)
      const result = await child.emit({ child: 1 })

      expect(result).toEqual({ child: 1 })
    })

    it('should return the result of the signal with a parent and child', async () => {
      const parent = new Scope<Parent>('parent')
      const child = new Scope<Child, [Parent]>('child')
      const signal = jest.fn<() => Child>().mockReturnValue({ child: 1 })

      parent.use(child)
      child.addPipe(signal)
      const result = await child.emit({ child: 2 })

      expect(result).toEqual({ child: 1 })
    })

    it('should transfer signals from parent to child', async () => {
      const parent = new Scope<Parent>('parent')
      const child = new Scope<Child, [Parent]>('child')
      const parentSignal = jest.fn<() => Parent>().mockReturnValue({ parent: 'test-parent' })
      const childSignal = jest.fn<() => Child>()

      parent.addPipe(parentSignal)
      child.addPipe(childSignal)
      parent.use(child)

      await parent.emit({ parent: 'test-parent' })

      expect(childSignal).toHaveBeenCalledWith({ parent: 'test-parent' })
    })

    it('should prevent execution of child signal if parent signal returns undefined', async () => {
      const parent = new Scope<Parent>('parent')
      const child = new Scope<Child, [Parent]>('child')
      // eslint-disable-next-line no-undefined
      const parentSignal = jest.fn<() => Parent | undefined>().mockReturnValue(undefined)
      const childSignal = jest.fn<() => Child>()

      parent.addPipe(parentSignal)
      child.addPipe(childSignal)
      parent.use(child)

      await parent.emit({ parent: 'test-parent' })

      expect(childSignal).not.toHaveBeenCalled()
    })
  })
})



================================================
FILE: test/utils.test.ts
================================================
import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals'
import { Buffer } from 'buffer'

import { mockCryptoFromArray, mockCryptoFromBuffer, resetCrypto } from './mocks/crypto'

describe('getUID', () => {
  beforeEach(() => {
    jest.resetModules()
  })

  afterEach(() => {
    resetCrypto()
  })

  it('should return a unique id based on crypto.getRandomValues', async () => {
    mockCryptoFromArray(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))

    const { getUID } = await import('../src/utils')
    const uid = getUID()

    expect(uid).toHaveLength(16)
  })

  it('should return a unique id based on crypto.randomBytes', async () => {
    mockCryptoFromBuffer(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]))

    const { getUID } = await import('../src/utils')
    const uid = getUID()

    expect(uid).toHaveLength(16)
  })
})


================================================
FILE: tsconfig.json
================================================
{
    "extends": "rete-cli/configs/tsconfig.json",
    "compilerOptions": {
        "target": "es5",
        "downlevelIteration": true,
	    "isolatedModules": false,
        "lib": []
    },
    "include": ["src", "test"]
}
Download .txt
gitextract_whez86aj/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── build-push.yml
│       ├── ci.yml
│       ├── codeql.yml
│       ├── commit-linter.yml
│       ├── release.yml
│       ├── stale.yml
│       └── update-docs.yml
├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── eslint.config.mjs
├── package.json
├── postinstall.js
├── rete.config.ts
├── src/
│   ├── editor.ts
│   ├── index.ts
│   ├── presets/
│   │   └── classic.ts
│   ├── scope.ts
│   ├── types.ts
│   ├── utility-types.ts
│   └── utils.ts
├── test/
│   ├── index.perf.ts
│   ├── index.test.ts
│   ├── mocks/
│   │   └── crypto.ts
│   ├── presets/
│   │   └── classic.test.ts
│   ├── scope.test.ts
│   └── utils.test.ts
└── tsconfig.json
Download .txt
SYMBOL INDEX (96 symbols across 9 files)

FILE: postinstall.js
  function getRectangle (line 1) | function getRectangle(width, height, color) {
  function drawText (line 7) | function drawText(x, y, text) {
  function black (line 16) | function black(text) {
  function white (line 20) | function white(text) {
  function bgBlue (line 24) | function bgBlue(text) {
  function bgYellow (line 28) | function bgYellow(text) {

FILE: src/editor.ts
  type Root (line 10) | type Root<Scheme extends BaseSchemes> =
  class NodeEditor (line 29) | class NodeEditor<Scheme extends BaseSchemes> extends Scope<Root<Scheme>> {
    method constructor (line 33) | constructor() {
    method getNode (line 42) | public getNode(id: Scheme['Node']['id']) {
    method getNodes (line 50) | public getNodes() {
    method getConnections (line 58) | public getConnections() {
    method getConnection (line 67) | public getConnection(id: Scheme['Connection']['id']) {
    method addNode (line 79) | async addNode(data: Scheme['Node']) {
    method addConnection (line 98) | async addConnection(data: Scheme['Connection']) {
    method removeNode (line 117) | async removeNode(id: Scheme['Node']['id']) {
    method removeConnection (line 140) | async removeConnection(id: Scheme['Connection']['id']) {
    method clear (line 162) | async clear() {

FILE: src/presets/classic.ts
  type PortId (line 10) | type PortId = string
  class Socket (line 16) | class Socket {
    method constructor (line 21) | constructor(public name: string) {
  class Port (line 29) | class Port<S extends Socket> {
    method constructor (line 45) | constructor(public socket: S, public label?: string, public multipleCo...
  class Input (line 54) | class Input<S extends Socket> extends Port<S> {
    method constructor (line 70) | constructor(public socket: S, public label?: string, public multipleCo...
    method addControl (line 78) | addControl(control: Control) {
    method removeControl (line 86) | removeControl() {
  class Output (line 95) | class Output<S extends Socket> extends Port<S> {
    method constructor (line 102) | constructor(socket: S, label?: string, multipleConnections?: boolean) {
  class Control (line 111) | class Control {
    method constructor (line 121) | constructor() {
  type InputControlOptions (line 129) | type InputControlOptions<N> = {
  class InputControl (line 141) | class InputControl<T extends 'text' | 'number', N = T extends 'text' ? s...
    method constructor (line 150) | constructor(public type: T, public options?: InputControlOptions<N>) {
    method setValue (line 162) | setValue(value?: N) {
  class Node (line 173) | class Node<
    method constructor (line 199) | constructor(public label: string) {
    method hasInput (line 203) | hasInput<K extends keyof Inputs>(key: K) {
    method addInput (line 207) | addInput<K extends keyof Inputs>(key: K, input: Input<Exclude<Inputs[K...
    method removeInput (line 213) | removeInput(key: keyof Inputs) {
    method hasOutput (line 217) | hasOutput<K extends keyof Outputs>(key: K) {
    method addOutput (line 221) | addOutput<K extends keyof Outputs>(key: K, output: Output<Exclude<Outp...
    method removeOutput (line 227) | removeOutput(key: keyof Outputs) {
    method hasControl (line 231) | hasControl<K extends keyof Controls>(key: K) {
    method addControl (line 235) | addControl<K extends keyof Controls>(key: K, control: Controls[K]) {
    method removeControl (line 241) | removeControl(key: keyof Controls) {
  class Connection (line 250) | class Connection<
    method constructor (line 274) | constructor(

FILE: src/scope.ts
  type Pipe (line 18) | type Pipe<T> = (data: T) => Promise<undefined | T> | undefined | T
  type CanAssignEach (line 20) | type CanAssignEach<D extends any[], F extends any[]> = D extends [infer ...
  type ScopeAsParameter (line 27) | type ScopeAsParameter<S extends Scope<any, any[]>, Current extends any[]...
  type NestedScope (line 36) | type NestedScope<S extends Scope<any, any[]>, Current extends any[]> = (...
  function useHelper (line 46) | function useHelper<S extends Scope<any, any[]>, Signals>() {
  class Signal (line 60) | class Signal<T> {
    method addPipe (line 63) | addPipe(pipe: Pipe<T>) {
    method emit (line 67) | async emit<Context extends T>(context: Context): Promise<Context | und...
  type Type (line 79) | type Type<T> = (new(...args: any[]) => T) | (abstract new (...args: any[...
  class Scope (line 84) | class Scope<Produces, Parents extends unknown[] = []> {
    method constructor (line 92) | constructor(public name: string) { }
    method addPipe (line 94) | addPipe(middleware: Pipe<Produces | Parents[number]>) {
    method use (line 98) | use<S extends Scope<any, any[]>>(scope: NestedScope<S, [Produces, ...P...
    method setParent (line 109) | setParent(scope: Scope<Parents[0], Tail<Parents>>) {
    method emit (line 113) | emit<C extends Produces>(context: C): Promise<Extract<Produces, C> | u...
    method hasParent (line 117) | hasParent(): boolean {
    method parentScope (line 123) | parentScope<T>(type?: Type<T>): T {

FILE: src/types.ts
  type NodeId (line 4) | type NodeId = string
  type ConnectionId (line 9) | type ConnectionId = string
  type NodeBase (line 15) | type NodeBase = { id: NodeId }
  type ConnectionBase (line 20) | type ConnectionBase = { id: ConnectionId, source: NodeId, target: NodeId }
  type GetSchemes (line 27) | type GetSchemes<NodeData extends NodeBase, ConnectionData extends Connec...
  type BaseSchemes (line 33) | type BaseSchemes = GetSchemes<NodeBase, ConnectionBase>

FILE: src/utility-types.ts
  type AcceptPartialUnion (line 4) | type AcceptPartialUnion<T> = T | any
  type Tail (line 6) | type Tail<T extends any[]> = ((...args: T) => void) extends (head: any, ...
  type UnionToIntersection (line 8) | type UnionToIntersection<U> = (
  type StrictExcludeInner (line 14) | type StrictExcludeInner<T, U> = 0 extends (
  type StrictExclude (line 17) | type StrictExclude<T, U> = T extends unknown ? StrictExcludeInner<T, U> ...
  type UnionToTuple (line 19) | type UnionToTuple<T> = UnionToIntersection<
  type FilterMatch (line 25) | type FilterMatch<T extends any[], V> = T extends [infer Head, ...infer _...
  type CanAssignToAnyOf (line 31) | type CanAssignToAnyOf<Provides, Requires> = FilterMatch<UnionToTuple<Pro...
  type CanAssignEachTupleElemmentToAnyOf (line 33) | type CanAssignEachTupleElemmentToAnyOf<Provides, Requires extends any[]>...
  type CanAssignEachToAnyOf (line 41) | type CanAssignEachToAnyOf<Provides, Requires> = CanAssignEachTupleElemme...
  type CanAssignSignal (line 43) | type CanAssignSignal<Provides, Requires> = CanAssignEachToAnyOf<Provides...
  type ReplaceTupleTypes (line 45) | type ReplaceTupleTypes<T extends any[], U> = { [K in keyof T]: U }
  type FilterNever (line 46) | type FilterNever<T extends any[]> = T extends [infer Head, ...infer _Tail]
  type KeepIfNonAssignable (line 50) | type KeepIfNonAssignable<T, Signals> = CanAssignToAnyOf<Signals, T> exte...
  type GetAllNonValidElements (line 52) | type GetAllNonValidElements<T extends any[], Signals> = T extends [infer...
  type GetNonAssignableElements (line 56) | type GetNonAssignableElements<T, Signals>
  type GetAssignmentReferences (line 58) | type GetAssignmentReferences<AssignableElements extends any[], Signals> ...

FILE: src/utils.ts
  function getUID (line 6) | function getUID(): string {

FILE: test/mocks/crypto.ts
  function mockCrypto (line 4) | function mockCrypto(object: Record<string, unknown>) {
  function mockCryptoFromArray (line 12) | function mockCryptoFromArray(array: Uint8Array) {
  function mockCryptoFromBuffer (line 18) | function mockCryptoFromBuffer(buffer: Buffer) {
  function resetCrypto (line 24) | function resetCrypto() {

FILE: test/scope.test.ts
  type Parent (line 5) | type Parent = { parent: string }
  type Child (line 6) | type Child = { child: number }
  class WrongScope (line 54) | class WrongScope<T> extends Scope<T> { }
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (50K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 38,
    "preview": "patreon: ni55an\nopen_collective: rete\n"
  },
  {
    "path": ".github/workflows/build-push.yml",
    "chars": 181,
    "preview": "name: Build and Push\nrun-name: Build and Push to dist/${{ github.ref_name }}\n\non:\n  workflow_dispatch:\n\njobs:\n  push:\n  "
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 173,
    "preview": "name: CI\n\non:\n  workflow_dispatch:\n  pull_request:\n    branches: [ \"main\", \"beta\" ]\n\njobs:\n  ci:\n    uses: retejs/.githu"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "chars": 205,
    "preview": "name: CodeQL\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ \"main\", \"beta\" ]\n  pull_request:\n    branches: [ \"main\", "
  },
  {
    "path": ".github/workflows/commit-linter.yml",
    "chars": 155,
    "preview": "name: Commit linter\n\non:\n  pull_request:\n    branches: [ \"main\", \"beta\" ]\n\njobs:\n  lint:\n    uses: retejs/.github/.githu"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 180,
    "preview": "name: Release\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ \"main\", \"beta\" ]\n\njobs:\n  release:\n    uses: retejs/.git"
  },
  {
    "path": ".github/workflows/stale.yml",
    "chars": 191,
    "preview": "name: Close stale issues and PRs\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '30 1 * * 0'\n\njobs:\n  stale:\n    uses"
  },
  {
    "path": ".github/workflows/update-docs.yml",
    "chars": 232,
    "preview": "name: Update docs\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ \"main\" ]\n\njobs:\n  pull:\n    uses: retejs/.github/.gi"
  },
  {
    "path": ".gitignore",
    "chars": 117,
    "preview": "node_modules\n.idea/\n.vscode/\n.sonarlint\n.scannerwork\n.nyc_output\n/coverage\nnpm-debug.log\n/dist\ndocs\n.rete-cli\n.sonar\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 1392,
    "preview": "## [2.0.6](https://github.com/retejs/rete/compare/v2.0.5...v2.0.6) (2025-06-30)\n\n\n### Bug Fixes\n\n* improve concurrent be"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 73,
    "preview": "Check out the [Code of Conduct](https://retejs.org/docs/code-of-conduct)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 73,
    "preview": "Check out the [Contribution guide](https://retejs.org/docs/contribution)\n"
  },
  {
    "path": "LICENSE",
    "chars": 1104,
    "preview": "MIT License\r\n\r\nCopyright (c) 2023 \"Ni55aN\" Vitaliy Stoliarov\r\n\r\nPermission is hereby granted, free of charge, to any per"
  },
  {
    "path": "README.md",
    "chars": 2577,
    "preview": "Rete.js\n====\n[![Made in Ukraine](https://img.shields.io/badge/made_in-ukraine-ffd700.svg?labelColor=0057b7)](https://sta"
  },
  {
    "path": "eslint.config.mjs",
    "chars": 140,
    "preview": "import tseslint from 'typescript-eslint';\nimport configs from 'rete-cli/configs/eslint.mjs';\n\nexport default tseslint.co"
  },
  {
    "path": "package.json",
    "chars": 794,
    "preview": "{\n  \"name\": \"rete\",\n  \"version\": \"2.0.6\",\n  \"description\": \"JavaScript framework\",\n  \"scripts\": {\n    \"build\": \"rete bui"
  },
  {
    "path": "postinstall.js",
    "chars": 993,
    "preview": "function getRectangle(width, height, color) {\n  const line = new Array(width).fill(' ').join('')\n\n  return new Array(hei"
  },
  {
    "path": "rete.config.ts",
    "chars": 298,
    "preview": "import { ReteOptions } from 'rete-cli'\nimport copy from 'rollup-plugin-copy'\n\nexport default <ReteOptions>{\n  input: 'sr"
  },
  {
    "path": "src/editor.ts",
    "chars": 4737,
    "preview": "import { Scope } from './scope'\nimport { BaseSchemes } from './types'\n\n/**\n * Signal types produced by NodeEditor instan"
  },
  {
    "path": "src/index.ts",
    "chars": 248,
    "preview": "export * from './editor'\nexport * as ClassicPreset from './presets/classic'\nexport type { CanAssignSignal, NestedScope, "
  },
  {
    "path": "src/presets/classic.ts",
    "chars": 7249,
    "preview": "/**\n * Contains classes for classic scheme such as Node, Input, Output, Control, Socket, Connection\n * @module\n * @group"
  },
  {
    "path": "src/scope.ts",
    "chars": 4051,
    "preview": "/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/naming-convention */\nimport"
  },
  {
    "path": "src/types.ts",
    "chars": 713,
    "preview": "/**\n * Node id type\n */\nexport type NodeId = string\n/**\n * Connection id type\n * @group Primary\n */\nexport type Connecti"
  },
  {
    "path": "src/utility-types.ts",
    "chars": 2405,
    "preview": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\n// eslint-disable-next-line @typescript-eslint/no-redundant-typ"
  },
  {
    "path": "src/utils.ts",
    "chars": 438,
    "preview": "const crypto = globalThis.crypto as (typeof globalThis.crypto | typeof import('node:crypto'))\n\n/**\n * @returns A unique "
  },
  {
    "path": "test/index.perf.ts",
    "chars": 1776,
    "preview": "import { describe, it } from '@jest/globals'\n\nimport { BaseSchemes } from '../src'\nimport { NodeEditor } from '../src/ed"
  },
  {
    "path": "test/index.test.ts",
    "chars": 4059,
    "preview": "import { describe, expect, it } from '@jest/globals'\n\nimport { NodeEditor } from '../src/editor'\n\ndescribe('NodeEditor',"
  },
  {
    "path": "test/mocks/crypto.ts",
    "chars": 740,
    "preview": "import { jest } from '@jest/globals'\nimport { Buffer } from 'buffer'\n\nexport function mockCrypto(object: Record<string, "
  },
  {
    "path": "test/presets/classic.test.ts",
    "chars": 4732,
    "preview": "import { afterEach, beforeEach, describe, expect, it } from '@jest/globals'\n\nimport { mockCryptoFromArray, resetCrypto }"
  },
  {
    "path": "test/scope.test.ts",
    "chars": 5153,
    "preview": "import { describe, expect, it, jest } from '@jest/globals'\n\nimport { Scope } from '../src/scope'\n\ntype Parent = { parent"
  },
  {
    "path": "test/utils.test.ts",
    "chars": 850,
    "preview": "import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals'\nimport { Buffer } from 'buffer'\n\nimpor"
  },
  {
    "path": "tsconfig.json",
    "chars": 226,
    "preview": "{\n    \"extends\": \"rete-cli/configs/tsconfig.json\",\n    \"compilerOptions\": {\n        \"target\": \"es5\",\n        \"downlevelI"
  }
]

About this extraction

This page contains the full source code of the retejs/rete GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (45.2 KB), approximately 12.9k tokens, and a symbol index with 96 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!