GitRoot

Craft your forge, Build your project, Grow your community freely
  1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
  2//
  3// SPDX-License-Identifier: MIT
  4
  5import { JSON } from "json-as";
  6import { HttpRequest, HttpResponse } from "./server";
  7import { FS, FsBaseCache, FsBaseWebcontent, FsBaseWorktree } from "./src/fs";
  8import { HttpClient, needServer } from "./src/httpclient";
  9import {
 10  _call,
 11  _canCall,
 12  _commitAll,
 13  _commits,
 14  _diffWithParent,
 15  _exec,
 16  _forgeConf,
 17  _httpClient,
 18  _log,
 19  _logError,
 20  _merge,
 21  _report,
 22} from "./src/imports";
 23import { Call, CallRes } from "./src/model/call";
 24import { Commit } from "./src/model/commit";
 25import { Exec, ExecStatus } from "./src/model/exec";
 26import { ForgeConf } from "./src/model/forgeconf";
 27import { PluginRun } from "./src/model/pluginrun";
 28import { Report, ReportToGitroot } from "./src/model/report";
 29import { exportFuncCallback, Server } from "./src/model/server";
 30import { Plugin } from "./src/plugin";
 31
 32export * from "./src/index";
 33
 34export let __server: server | null = null;
 35
 36export function Register(
 37  run: Array<PluginRun>,
 38  p: (server: Server) => Plugin,
 39): void {
 40  const s = new server();
 41  s.plugin = p(s);
 42  s.run = run;
 43  __server = s;
 44}
 45
 46type ReporterCallback = (report: Report) => void;
 47
 48class PluginOption {
 49  constructor(public reporter: ReporterCallback) {}
 50}
 51
 52class server implements Server, needServer {
 53  private worktreeFS: FS = new FS(FsBaseWorktree);
 54  private webcontentFS: FS = new FS(FsBaseWebcontent);
 55  private cacheFS: FS = new FS(FsBaseCache);
 56  private exportedFuncs: Map<string, exportFuncCallback> = new Map<
 57    string,
 58    exportFuncCallback
 59  >();
 60
 61  plugin: Plugin | null = null;
 62  run: Array<PluginRun> = [];
 63  pluginOption: PluginOption | null = null;
 64
 65  addPluginOption(opt: PluginOption): void {
 66    this.pluginOption = opt;
 67  }
 68
 69  getExportedFuncs(name: string): exportFuncCallback {
 70    return this.exportedFuncs.get(name);
 71  }
 72
 73  forgeConf(): ForgeConf {
 74    const ptrSize = _forgeConf();
 75    const ptr = u32((ptrSize >> 32) & 0xffffffff);
 76    const size = u32(ptrSize & 0xffffffff);
 77    return JSON.parse<ForgeConf>(String.UTF8.decodeUnsafe(ptr, size));
 78  }
 79
 80  worktree(): FS {
 81    return this.worktreeFS;
 82  }
 83
 84  webcontent(): FS {
 85    return this.webcontentFS;
 86  }
 87
 88  cache(): FS {
 89    return this.cacheFS;
 90  }
 91
 92  commitAllIfNeeded(message: string): void {
 93    _commitAll(message);
 94  }
 95
 96  diffWithParent(
 97    hash: string,
 98    oldFilepath: string,
 99    newFilepath: string,
100  ): string {
101    const ptrSize = _diffWithParent(hash, oldFilepath, newFilepath);
102    const ptr = u32((ptrSize >> 32) & 0xffffffff);
103    const size = u32(ptrSize & 0xffffffff);
104    return String.UTF8.decodeUnsafe(ptr, size);
105  }
106
107  merge(from: string, to: string): void {
108    _merge(from, to);
109  }
110
111  log(message: string): void {
112    _log(message);
113  }
114
115  logError(message: string, error: string): void {
116    _logError(message, error);
117  }
118
119  commits(from: string, to: string): Array<Commit> {
120    const ptrSize = _commits(from, to);
121    const ptr = u32((ptrSize >> 32) & 0xffffffff);
122    const size = u32(ptrSize & 0xffffffff);
123    return JSON.parse<Array<Commit>>(String.UTF8.decodeUnsafe(ptr, size));
124  }
125
126  exec(exec: Exec): ExecStatus {
127    const execJson = JSON.stringify(exec);
128    const ptrSize = _exec(execJson);
129    const ptr = u32((ptrSize >> 32) & 0xffffffff);
130    const size = u32(ptrSize & 0xffffffff);
131    return JSON.parse<ExecStatus>(String.UTF8.decodeUnsafe(ptr, size));
132  }
133
134  report(level: string, content: Array<string>): void {
135    const reportMarshalled = JSON.stringify(
136      new ReportToGitroot(level, content),
137    );
138    _report(reportMarshalled);
139  }
140
141  reportToPlugin(report: Report): void {
142    if (this.pluginOption != null) {
143      this.pluginOption!.reporter(report);
144    }
145  }
146
147  exportFunc(name: string, callback: exportFuncCallback): void {
148    this.exportedFuncs.set(name, callback);
149  }
150
151  canCallFunc(plugin: string, name: string, args: Map<string, string>): bool {
152    const call = new Call(plugin, name, args);
153    const callJson = JSON.stringify(call);
154    return _canCall(callJson) != 0;
155  }
156
157  callFunc(plugin: string, name: string, args: Map<string, string>): CallRes {
158    const call = new Call(plugin, name, args);
159    const callJson = JSON.stringify(call);
160    const ptrSize = _call(callJson);
161    const ptrRes = u32(ptrSize >> 32);
162    const sizeRes = u32(ptrSize);
163    const res = String.UTF8.decodeUnsafe(ptrRes, sizeRes);
164    return JSON.parse<CallRes>(res);
165  }
166
167  httpClient(header: Map<string, Array<string>>): HttpClient {
168    return new HttpClient(this, header);
169  }
170
171  doRequest(request: HttpRequest): HttpResponse {
172    const requestJson = JSON.stringify(request);
173    const ptrSize = _httpClient(requestJson);
174    if (ptrSize === 0) {
175      return new HttpResponse(0, "unknown error");
176    }
177    const ptrRes = u32(ptrSize >> 32);
178    const sizeRes = u32(ptrSize);
179    const res = String.UTF8.decodeUnsafe(ptrRes, sizeRes);
180    return JSON.parse<HttpResponse>(res);
181  }
182}