### Install TypeScript Kernel for Jupyter Source: https://github.com/hesprs/synthkernel/blob/main/README.md Register the TypeScript kernel for Jupyter Lab to execute the whitepaper notebook. ```bash pnpm install pnpm tslab install ``` -------------------------------- ### Add SynthKernel Agent Skill Source: https://github.com/hesprs/synthkernel/blob/main/README.md Install the SynthKernel agent skill using npx for enhanced agent navigation within SynthKernel repositories. ```bash npx skills add hesprs/synthkernel ``` -------------------------------- ### SynthKernel Loader Module Integration Source: https://github.com/hesprs/synthkernel/blob/main/skill/maintenance.md Example of how to integrate a new module into the SynthKernel loader by adding it to the modules array. ```TypeScript const allModules = [(...ExistingModules), YourNewModule]; ``` -------------------------------- ### SynthKernel Project Architecture Example Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md Illustrates the typical structure of a project using SynthKernel architecture, including a module loader and various modules. This structure emphasizes modularity and separation of concerns. ```markdown ## Project Architecture This project uses SynthKernel architecture, **you must use the `SynthKernel` skill when planning, refactoring or adding new functionalities**. Typical practice consists a module loader class and module classes: - The module loader class manages module lifecycles, orchestrates types, and behaves as an facade at of your app logic. **Do not implement any business logic in the module loader class, implement only in modules. **. - All module classes extend a `BaseModule` class, they define APIs, register lifecycle hooks, execute actual logic, augment the loader class and wire each other via dependency injection. - Types are resolved via generics orchestration. - Modules are composed to the loader to form an APP. **Structure**: ```text loader: description - module 1: description - module 2: description - (module as well as a loader) 3: description - module 1: description - module 2: description - module 4: description ``` ``` -------------------------------- ### TypeScript Base Orchestrations Interface Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md Define a base interface for module options, specifying loading behavior and the container element. This is an example and should be adapted to specific needs. ```TypeScript // #region Base Orchestrations // example only, define according to your needs export interface BaseOptions { load: 'lazy' | 'normal' | false; container: HTMLElement; } // #endregion ``` -------------------------------- ### TypeScript Compiler Options for SynthKernel Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md Ensure your tsconfig.json includes 'allowImportingTsExtensions' for SynthKernel development. ```json { "compilerOptions": { "allowImportingTsExtensions": true } } ``` -------------------------------- ### SynthKernel Module Template Source: https://github.com/hesprs/synthkernel/blob/main/skill/maintenance.md Template for creating a new module in a SynthKernel project. Includes DI, augmentation, lifecycle hooks, and orchestrations. ```TypeScript /** (module name): (what this module does) */ import { BaseModule, type BaseOptions } from './index.ts'; // all orchestrations needed by this module that has base fields, change the path to the actual path where the loader exists // import all modules that will be used by this module by DI import AnotherModule from './AnotherModule.ts'; // the types of orchestrations, must extend the base type if the orchestration has base fields, adjust accordingly interface Options extends BaseOptions { // all fields this module provides, adjust accordingly option1: string; option2?: boolean; } // the augmentation if the module needs, adjust the fields according to your needs interface Augmentation { method: () => void; property: boolean; } // change the module name to the intended one // pass type parameters in the correct order as defined in BaseModule // - if what you want to pass comes later, e.g., you only want to pass `Augmentation`, simply pass the base orchestration, like BaseModule export class Module extends BaseModule { constructor(...args: BaseArgs) { super(...args); // if you need augmentation, you must call `this.augment` in your constructor and pass everything defined in your `Augmentation` interface. this.augment({ method: this.method, property: this.property, }); // subscribe to lifecycle hooks if needed, adjust accordingly this.onStart(this.method); // use this.container.get() to inject a dependency const dep = this.container.get(AnotherModule); // ... freely implement your logic } // ... write your logic, the module is your playground method = () => {}; property = false; } ``` -------------------------------- ### TypeScript Loader Comments Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md Use this comment block to document the task of a loader, its modules, and configuration options like dependency injection, augmentation, lifecycle hooks, and orchestrations. ```TypeScript /** * (write down what is the task of this loader with all its modules) * Dependency injection enabled / not enabled (question 1) * Augmentation enabled / not enabled (question 4) * Lifecycle hooks: (question 3) * (hook name): (description) * Orchestrations: (question 2) * (orchestration name): (description) */ ``` -------------------------------- ### SynthKernel Core Types Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md Defines fundamental types for SynthKernel's type orchestration, enabling extraction and combination of types from input classes. These are essential for sharing across the SynthKernel tree. ```TypeScript // #region [DO NOT MODIFY] SynthKernel Core Types export type General = any; export type GeneralArray = ReadonlyArray; export type GeneralObject = object; export type GeneralConstructor = new (...args: General[]) => General; type UnionToIntersection = (U extends General ? (k: U) => void : never) extends ( k: infer I, ) => void ? I : never; type GeneralModuleInput = | ReadonlyArray | ReadonlyArray; export type ModuleInput = | ReadonlyArray | ReadonlyArray>; type Instances = T extends ReadonlyArray ? InstanceType : T[number]; export type Orchestratable< T extends GeneralModuleInput, K extends keyof Instances, > = UnionToIntersection[K]>; // #endregion ``` -------------------------------- ### Loader Class Implementation Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md This TypeScript code defines a `Loader` class responsible for initializing modules, managing a dependency injection container, and handling lifecycle hooks. It supports module augmentation for dynamic property and method reflection. ```TypeScript // adjust this to the real location of `BaseModule.ts` // imports should include: `BaseModule`, all orchestrations if needed (question 2), augmentation if needed (question 4) import type { GeneralModuleCtor, Options, Augmentation } from './BaseModule.ts'; import type { GeneralObject } from './types.ts'; // change this to the real path of `types.ts` import { makeHook } from './utilities.ts'; // change this to the real path of `utilities.ts` import { Container } from '@needle-di/core'; // change or delete this according to your DI container needs (question) // remember that we have defined the base orchestrations in step 6 export interface BaseOptions { container: HTMLElement; loading?: 'normal' | 'lazy' | 'none'; } // populate this once we have real modules const allModules = []; // let TypeScript infer the type to keep the exact type type AllModules = typeof allModules; // the final orchestration of types, should include: // - all orchestrations if you need (question 2) // - augmentation if you need (question 4) type AllOptions = Options; type AllAugmentation = Augmentation; // the loader class, change the class name freely // this is the target of augmentation, when an instance of the loader loads a module that augments it, new methods and properties will be reflected on both the loader's type and runtime property class Loader { // all your lifecycle hooks according to your needs (question 3), adjust according to your lifecycle needs private onDispose = makeHook(true); private onStart = makeHook(); private onRestart = makeHook(); // all your orchestrations according to your needs (question 2), this is the only case where you write some app logic in a loader. And all reason for it is type orchestration. Usually required by type-aware options or a event emitter whose event map is orchestrated options: AllOptions; // the DI container (question 1) container: Container; // constructor parameters you need, you probably want to use orchestrated types here, e.g. type for user configurable options defined by modules (question 2) constructor(options: AllOptions) { this.container = new Container(); // instantiate DI container when needed (question 1) this.options = options; // assign orchestrations according your need (question 2) // If you don't need DI, the following loading would be straightforward allModules.forEach((Module) => { new Class( // in the same order as the constructor parameters of the base module you defined in step 7, the exact parameters can vary between requirements this.container, this.options, this.onStart, this.onDispose, this.onRestart, this.augment, ), }); // the DI container binding, specific methods varies between different DI libraries, write following lines if you need to use a DI container const bind = (Class: GeneralModuleCtor) => { this.container.bind({ provide: Class, useFactory: () => new Class( // in the same order as the constructor parameters of the base module you defined in step 7, the exact parameters can vary between requirements this.container, this.options, this.onStart, this.onDispose, this.onRestart, this.augment, ), }); }; allModules.forEach(bind); // use non-assign container get to load all modules, if you need custom loading, it would be easy to implement yourself's allModules.forEach((Module: GeneralModuleCtor) => { this.container.get(Module); }); // ... implement your custom loading logic freely } // core component for augmentation which should be passed in modules' class constructors, add this if you need augmentation private augment = (aug: GeneralObject) => { const descriptors = Object.getOwnPropertyDescriptors(aug); Object.defineProperties(this, descriptors); }; // implement your lifecycle management methods freely dispose = () => { this.onDispose(); this.container.unbindAll(); }; } // If you are not using augmentation, simply export the loader, change the name if you like export default Loader; // If you are using augmentation, do the final type hack below type LoaderType = new (...args: ConstructorParameters) => Loader & AllAugmentation; export default Loader as LoaderType; ``` -------------------------------- ### Make Hook Utility Function Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md A utility function to create observable hooks that can be subscribed to and unsubscribed from. Useful for managing state or events across different parts of an application. Supports both synchronous and asynchronous operations, with an option to reverse execution order. ```TypeScript import type { GeneralArray } from './types.ts'; // change this to the actual path of `types.ts` type MatchingFunc = (...args: Args) => void | Promise; export type Hook = { (...args: Args): Async extends true ? Promise : void; subs: Set>; subscribe(callback: MatchingFunc): void; unsubscribe(callback: MatchingFunc): void; }; /** * A quick function to create a hook that can be subscribed to and unsubscribed from. * Pass your arguments as the type parameter * * @param reverse - Whether the hook should reverse the execution order or not * @param async - Whether the hook is async or not * @example const hook = makeHook(true); */ export function makeHook( reverse: boolean = false, async: Async = false as Async, ) { const result = (async ? async (...args: Args) => { if (reverse) { const items = Array.from(result.subs).reverse(); for (const callback of items) await callback(...args); } else for (const callback of result.subs) await callback(...args); } : (...args: Args) => { if (reverse) { const items = Array.from(result.subs).reverse(); for (const callback of items) void callback(...args); } else for (const callback of result.subs) void callback(...args); }) as Hook; result.subs = new Set(); result.subscribe = (callback: MatchingFunc) => { result.subs.add(callback); }; result.unsubscribe = (callback: MatchingFunc) => { result.subs.delete(callback); }; return result; } ``` -------------------------------- ### TypeScript BaseModule Class Definition Source: https://github.com/hesprs/synthkernel/blob/main/skill/start.md Defines a generic `BaseModule` class that supports dependency injection, lifecycle hooks, and augmentation. Adjust type parameters and imports based on project requirements. ```TypeScript import type { BaseOptions } from './index.ts'; // change or delete this to the path to `index.ts` (the loader) according to real base orchestration needs import type { General, GeneralObject, ModuleInput as MI, Orchestratable } from './types.ts'; // change this to the real path of `types.ts` import type { Hook } from './utilities.ts'; // change this to the real hook type you are using (question 5) import type { Container } from '@needle-di/core'; // change or delete this according to your DI container needs (question 1) type ModuleInput = MI; export type GeneralModuleCtor = typeof BaseModule; export type BaseArgs = ConstructorParameters; // change, add, or delete this according to your orchestration needs (question 2), align the second type parameter to the actual property name in the BaseModule export type Options = Orchestratable; // add this or not depends on whether you need augmentation or not (question 4) export type Augmentation = Orchestratable< M, '_Augmentation' >; // add, change or delete type parameters according to your type orchestration and augmentation needs (question 2, 4) // with base orchestrations: (Generics) extends (your base orchestration) = (your base orchestration) // without base orchestrations or augmentation: (Generics) extends GeneralObject = {} export class BaseModule< O extends BaseOptions = BaseOptions, A extends GeneralObject = {}, > { declare private static readonly _BaseModuleBrand: unique symbol; // nominal marker to ensure type safety // if you need augmentation (question 4) declare _Augmentation: A; // your orchestration fields (question 2) // orchestrated field needs runtime access: (field name): (Generics) // only type-level orchestration: declare (field name): (Generics) options: O; // your lifecycle hooks, add, modify or delete according to your needs (question 3) onStart: Hook['subscribe']; onRestart: Hook['subscribe']; onDispose: Hook['subscribe']; // constructor parameters, which should include: // - DI container if you need (question 1) // - all lifecycle hooks if you need (question 3) // - special augmentation function: `(aug: (Augmentation Generics)) => void` if you need (question 2) constructor( protected container: Container, options: GeneralObject, onStart: Hook, onDispose: Hook, onRestart: Hook, protected augment: (aug: A) => void, ) { // orchestration assignments (question 2) this.options = options as O; // lifecycle hooks assignments (question 3), adjust according to the real hook subscribe function according to your needs this.onStart = onStart.subscribe; this.onDispose = onDispose.subscribe; this.onRestart = onRestart.subscribe; } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.