diff --git a/.gitignore b/.gitignore
index a430c18..5844ea4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,10 @@
node_modules/
.yarn/cache
.yarn/install-state.gz
-examples/out
+examples/Typescript/out
+examples/CSharp/Generated
+examples/CSharp/Example/bin
+examples/CSharp/Example/obj
examples/definition.json
+templates/CSharp/bin
+templates/CSharp/obj
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..8ee6fc3
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,19 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ // "preLaunchTask": "build",
+ "program": "${workspaceFolder}/examples/CSharp_Example/bin/Debug/net6.0/CSharp_Example.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "console": "internalConsole",
+ "stopAtEntry": false
+ }
+ ]
+}
diff --git a/examples/CSharp/Example/CSharp_Example.csproj b/examples/CSharp/Example/CSharp_Example.csproj
new file mode 100644
index 0000000..bab5dbb
--- /dev/null
+++ b/examples/CSharp/Example/CSharp_Example.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/examples/CSharp/Example/Program.cs b/examples/CSharp/Example/Program.cs
new file mode 100644
index 0000000..96940a6
--- /dev/null
+++ b/examples/CSharp/Example/Program.cs
@@ -0,0 +1,94 @@
+// See https://aka.ms/new-console-template for more information
+using Example;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+
+class TestSrvimpl : Example.TestServiceServer {
+ public TestSrvimpl(): base() {}
+ public override async Task AddValuesSingleParam(AddValueRequest request, int ctx) {
+ var res = new Example.AddValueResponse();
+ res.value = 1;
+ return res;
+ }
+
+ public override async Task AddValuesMultipleParams(double value1,double value2,int ctx) {
+ return value1 + value2;
+ }
+
+ public override async Task ReturningVoid(double param1,int ctx) {
+
+ }
+
+ public override void OnEvent(string param1,int ctx) {
+ Console.WriteLine($"OnEvent {param1}");
+ }
+
+ public override async Task> FunctionWithArrayAsParamAndReturn(List values1,List values2, int ctx) {
+ var l = new List();
+ l.Append(1);
+ return l;
+ }
+
+ public override async Task ThrowingError(int ctx) {
+ throw new Exception("This is a remote error :)");
+ }
+
+}
+
+class CopyTransportS2 : Example.JRpcTransport {
+ CopyTransportS1 tr1;
+ public Queue backlog = new Queue();
+
+ public CopyTransportS2(CopyTransportS1 tr1) {
+ this.tr1 = tr1;
+ }
+
+ public override Task Write(string data) {
+ Console.WriteLine("--> " + data);
+ this.tr1.DevSendPacket(data);
+
+ return Task.CompletedTask;
+ }
+}
+
+class CopyTransportS1 : Example.JRpcTransport {
+ public Queue backlog = new Queue();
+
+ public CopyTransportS2 tr2;
+
+ public CopyTransportS1() {
+ this.tr2 = new CopyTransportS2(this);
+ }
+
+ public override Task Write(string data) {
+ Console.WriteLine("<-- " + data);
+ this.tr2.DevSendPacket(data);
+ return Task.CompletedTask;
+ }
+}
+
+class Program {
+ public static void Main() {
+ Program.Start().Wait();
+ }
+
+ public static async Task Start() {
+ var server = new Example.JRpcServer();
+ server.AddService("TestService", new TestSrvimpl());
+ var transport = new CopyTransportS1();
+
+ var sess = server.GetSession(transport, 0);
+ var client = new Example.JRpcClient(transport.tr2);
+ var testService = new Example.TestServiceClient(client);
+
+ var result = await testService.AddValuesMultipleParams(1,2);
+
+ Console.WriteLine($"Add 1 + 2 = {result}");
+
+ await testService.ThrowingError();
+ }
+}
+
+
+
diff --git a/examples/test.ts b/examples/Typescript/test.ts
similarity index 96%
rename from examples/test.ts
rename to examples/Typescript/test.ts
index e74bf58..5529293 100644
--- a/examples/test.ts
+++ b/examples/Typescript/test.ts
@@ -44,6 +44,10 @@ class TestService extends Server.TestService {
async FunctionWithArrayAsParamAndReturn(vals1, vals2) {
return [...vals1, ...vals2];
}
+
+ async ThrowingError(ctx: undefined): Promise {
+ throw new Error("Remote error!");
+ }
}
server.addService(new TestService());
diff --git a/examples/example.jrpc b/examples/example.jrpc
index 312a20f..723243c 100644
--- a/examples/example.jrpc
+++ b/examples/example.jrpc
@@ -1,5 +1,7 @@
import "./import";
+define CSharp_Namespace Example;
+
enum TestEnum {
VAL1,
VAL2,
@@ -44,6 +46,8 @@ service TestService {
@Param("param1", "Parameter with some string for event")
notification OnEvent(param1: string);
+ ThrowingError(): void;
+
FunctionWithArrayAsParamAndReturn(values1: number[], values2: number[]): number[];
}
diff --git a/lib/jrpc.js b/lib/jrpc.js
index c621cf6..a2cfbc3 100755
--- a/lib/jrpc.js
+++ b/lib/jrpc.js
@@ -1656,7 +1656,7 @@ var require_route = __commonJS({
}
module2.exports = function(fromModel) {
const graph = deriveBFS(fromModel);
- const conversion2 = {};
+ const conversion3 = {};
const models = Object.keys(graph);
for (let len = models.length, i = 0; i < len; i++) {
const toModel = models[i];
@@ -1664,9 +1664,9 @@ var require_route = __commonJS({
if (node.parent === null) {
continue;
}
- conversion2[toModel] = wrapConversion(toModel, graph);
+ conversion3[toModel] = wrapConversion(toModel, graph);
}
- return conversion2;
+ return conversion3;
};
}
});
@@ -2198,6 +2198,2577 @@ var require_source = __commonJS({
}
});
+// node_modules/universalify/index.js
+var require_universalify = __commonJS({
+ "node_modules/universalify/index.js"(exports) {
+ "use strict";
+ exports.fromCallback = function(fn) {
+ return Object.defineProperty(function(...args) {
+ if (typeof args[args.length - 1] === "function")
+ fn.apply(this, args);
+ else {
+ return new Promise((resolve6, reject) => {
+ fn.call(this, ...args, (err, res) => err != null ? reject(err) : resolve6(res));
+ });
+ }
+ }, "name", { value: fn.name });
+ };
+ exports.fromPromise = function(fn) {
+ return Object.defineProperty(function(...args) {
+ const cb = args[args.length - 1];
+ if (typeof cb !== "function")
+ return fn.apply(this, args);
+ else
+ fn.apply(this, args.slice(0, -1)).then((r) => cb(null, r), cb);
+ }, "name", { value: fn.name });
+ };
+ }
+});
+
+// node_modules/graceful-fs/polyfills.js
+var require_polyfills = __commonJS({
+ "node_modules/graceful-fs/polyfills.js"(exports, module2) {
+ var constants = require("constants");
+ var origCwd = process.cwd;
+ var cwd = null;
+ var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
+ process.cwd = function() {
+ if (!cwd)
+ cwd = origCwd.call(process);
+ return cwd;
+ };
+ try {
+ process.cwd();
+ } catch (er) {
+ }
+ if (typeof process.chdir === "function") {
+ chdir = process.chdir;
+ process.chdir = function(d) {
+ cwd = null;
+ chdir.call(process, d);
+ };
+ if (Object.setPrototypeOf)
+ Object.setPrototypeOf(process.chdir, chdir);
+ }
+ var chdir;
+ module2.exports = patch;
+ function patch(fs) {
+ if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
+ patchLchmod(fs);
+ }
+ if (!fs.lutimes) {
+ patchLutimes(fs);
+ }
+ fs.chown = chownFix(fs.chown);
+ fs.fchown = chownFix(fs.fchown);
+ fs.lchown = chownFix(fs.lchown);
+ fs.chmod = chmodFix(fs.chmod);
+ fs.fchmod = chmodFix(fs.fchmod);
+ fs.lchmod = chmodFix(fs.lchmod);
+ fs.chownSync = chownFixSync(fs.chownSync);
+ fs.fchownSync = chownFixSync(fs.fchownSync);
+ fs.lchownSync = chownFixSync(fs.lchownSync);
+ fs.chmodSync = chmodFixSync(fs.chmodSync);
+ fs.fchmodSync = chmodFixSync(fs.fchmodSync);
+ fs.lchmodSync = chmodFixSync(fs.lchmodSync);
+ fs.stat = statFix(fs.stat);
+ fs.fstat = statFix(fs.fstat);
+ fs.lstat = statFix(fs.lstat);
+ fs.statSync = statFixSync(fs.statSync);
+ fs.fstatSync = statFixSync(fs.fstatSync);
+ fs.lstatSync = statFixSync(fs.lstatSync);
+ if (!fs.lchmod) {
+ fs.lchmod = function(path, mode, cb) {
+ if (cb)
+ process.nextTick(cb);
+ };
+ fs.lchmodSync = function() {
+ };
+ }
+ if (!fs.lchown) {
+ fs.lchown = function(path, uid, gid, cb) {
+ if (cb)
+ process.nextTick(cb);
+ };
+ fs.lchownSync = function() {
+ };
+ }
+ if (platform === "win32") {
+ fs.rename = function(fs$rename) {
+ return function(from, to, cb) {
+ var start = Date.now();
+ var backoff = 0;
+ fs$rename(from, to, function CB(er) {
+ if (er && (er.code === "EACCES" || er.code === "EPERM") && Date.now() - start < 6e4) {
+ setTimeout(function() {
+ fs.stat(to, function(stater, st) {
+ if (stater && stater.code === "ENOENT")
+ fs$rename(from, to, CB);
+ else
+ cb(er);
+ });
+ }, backoff);
+ if (backoff < 100)
+ backoff += 10;
+ return;
+ }
+ if (cb)
+ cb(er);
+ });
+ };
+ }(fs.rename);
+ }
+ fs.read = function(fs$read) {
+ function read(fd, buffer, offset, length, position, callback_) {
+ var callback;
+ if (callback_ && typeof callback_ === "function") {
+ var eagCounter = 0;
+ callback = function(er, _, __) {
+ if (er && er.code === "EAGAIN" && eagCounter < 10) {
+ eagCounter++;
+ return fs$read.call(fs, fd, buffer, offset, length, position, callback);
+ }
+ callback_.apply(this, arguments);
+ };
+ }
+ return fs$read.call(fs, fd, buffer, offset, length, position, callback);
+ }
+ if (Object.setPrototypeOf)
+ Object.setPrototypeOf(read, fs$read);
+ return read;
+ }(fs.read);
+ fs.readSync = function(fs$readSync) {
+ return function(fd, buffer, offset, length, position) {
+ var eagCounter = 0;
+ while (true) {
+ try {
+ return fs$readSync.call(fs, fd, buffer, offset, length, position);
+ } catch (er) {
+ if (er.code === "EAGAIN" && eagCounter < 10) {
+ eagCounter++;
+ continue;
+ }
+ throw er;
+ }
+ }
+ };
+ }(fs.readSync);
+ function patchLchmod(fs2) {
+ fs2.lchmod = function(path, mode, callback) {
+ fs2.open(path, constants.O_WRONLY | constants.O_SYMLINK, mode, function(err, fd) {
+ if (err) {
+ if (callback)
+ callback(err);
+ return;
+ }
+ fs2.fchmod(fd, mode, function(err2) {
+ fs2.close(fd, function(err22) {
+ if (callback)
+ callback(err2 || err22);
+ });
+ });
+ });
+ };
+ fs2.lchmodSync = function(path, mode) {
+ var fd = fs2.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode);
+ var threw = true;
+ var ret;
+ try {
+ ret = fs2.fchmodSync(fd, mode);
+ threw = false;
+ } finally {
+ if (threw) {
+ try {
+ fs2.closeSync(fd);
+ } catch (er) {
+ }
+ } else {
+ fs2.closeSync(fd);
+ }
+ }
+ return ret;
+ };
+ }
+ function patchLutimes(fs2) {
+ if (constants.hasOwnProperty("O_SYMLINK")) {
+ fs2.lutimes = function(path, at, mt, cb) {
+ fs2.open(path, constants.O_SYMLINK, function(er, fd) {
+ if (er) {
+ if (cb)
+ cb(er);
+ return;
+ }
+ fs2.futimes(fd, at, mt, function(er2) {
+ fs2.close(fd, function(er22) {
+ if (cb)
+ cb(er2 || er22);
+ });
+ });
+ });
+ };
+ fs2.lutimesSync = function(path, at, mt) {
+ var fd = fs2.openSync(path, constants.O_SYMLINK);
+ var ret;
+ var threw = true;
+ try {
+ ret = fs2.futimesSync(fd, at, mt);
+ threw = false;
+ } finally {
+ if (threw) {
+ try {
+ fs2.closeSync(fd);
+ } catch (er) {
+ }
+ } else {
+ fs2.closeSync(fd);
+ }
+ }
+ return ret;
+ };
+ } else {
+ fs2.lutimes = function(_a, _b, _c, cb) {
+ if (cb)
+ process.nextTick(cb);
+ };
+ fs2.lutimesSync = function() {
+ };
+ }
+ }
+ function chmodFix(orig) {
+ if (!orig)
+ return orig;
+ return function(target, mode, cb) {
+ return orig.call(fs, target, mode, function(er) {
+ if (chownErOk(er))
+ er = null;
+ if (cb)
+ cb.apply(this, arguments);
+ });
+ };
+ }
+ function chmodFixSync(orig) {
+ if (!orig)
+ return orig;
+ return function(target, mode) {
+ try {
+ return orig.call(fs, target, mode);
+ } catch (er) {
+ if (!chownErOk(er))
+ throw er;
+ }
+ };
+ }
+ function chownFix(orig) {
+ if (!orig)
+ return orig;
+ return function(target, uid, gid, cb) {
+ return orig.call(fs, target, uid, gid, function(er) {
+ if (chownErOk(er))
+ er = null;
+ if (cb)
+ cb.apply(this, arguments);
+ });
+ };
+ }
+ function chownFixSync(orig) {
+ if (!orig)
+ return orig;
+ return function(target, uid, gid) {
+ try {
+ return orig.call(fs, target, uid, gid);
+ } catch (er) {
+ if (!chownErOk(er))
+ throw er;
+ }
+ };
+ }
+ function statFix(orig) {
+ if (!orig)
+ return orig;
+ return function(target, options, cb) {
+ if (typeof options === "function") {
+ cb = options;
+ options = null;
+ }
+ function callback(er, stats) {
+ if (stats) {
+ if (stats.uid < 0)
+ stats.uid += 4294967296;
+ if (stats.gid < 0)
+ stats.gid += 4294967296;
+ }
+ if (cb)
+ cb.apply(this, arguments);
+ }
+ return options ? orig.call(fs, target, options, callback) : orig.call(fs, target, callback);
+ };
+ }
+ function statFixSync(orig) {
+ if (!orig)
+ return orig;
+ return function(target, options) {
+ var stats = options ? orig.call(fs, target, options) : orig.call(fs, target);
+ if (stats) {
+ if (stats.uid < 0)
+ stats.uid += 4294967296;
+ if (stats.gid < 0)
+ stats.gid += 4294967296;
+ }
+ return stats;
+ };
+ }
+ function chownErOk(er) {
+ if (!er)
+ return true;
+ if (er.code === "ENOSYS")
+ return true;
+ var nonroot = !process.getuid || process.getuid() !== 0;
+ if (nonroot) {
+ if (er.code === "EINVAL" || er.code === "EPERM")
+ return true;
+ }
+ return false;
+ }
+ }
+ }
+});
+
+// node_modules/graceful-fs/legacy-streams.js
+var require_legacy_streams = __commonJS({
+ "node_modules/graceful-fs/legacy-streams.js"(exports, module2) {
+ var Stream = require("stream").Stream;
+ module2.exports = legacy;
+ function legacy(fs) {
+ return {
+ ReadStream,
+ WriteStream
+ };
+ function ReadStream(path, options) {
+ if (!(this instanceof ReadStream))
+ return new ReadStream(path, options);
+ Stream.call(this);
+ var self = this;
+ this.path = path;
+ this.fd = null;
+ this.readable = true;
+ this.paused = false;
+ this.flags = "r";
+ this.mode = 438;
+ this.bufferSize = 64 * 1024;
+ options = options || {};
+ var keys = Object.keys(options);
+ for (var index = 0, length = keys.length; index < length; index++) {
+ var key = keys[index];
+ this[key] = options[key];
+ }
+ if (this.encoding)
+ this.setEncoding(this.encoding);
+ if (this.start !== void 0) {
+ if (typeof this.start !== "number") {
+ throw TypeError("start must be a Number");
+ }
+ if (this.end === void 0) {
+ this.end = Infinity;
+ } else if (typeof this.end !== "number") {
+ throw TypeError("end must be a Number");
+ }
+ if (this.start > this.end) {
+ throw new Error("start must be <= end");
+ }
+ this.pos = this.start;
+ }
+ if (this.fd !== null) {
+ process.nextTick(function() {
+ self._read();
+ });
+ return;
+ }
+ fs.open(this.path, this.flags, this.mode, function(err, fd) {
+ if (err) {
+ self.emit("error", err);
+ self.readable = false;
+ return;
+ }
+ self.fd = fd;
+ self.emit("open", fd);
+ self._read();
+ });
+ }
+ function WriteStream(path, options) {
+ if (!(this instanceof WriteStream))
+ return new WriteStream(path, options);
+ Stream.call(this);
+ this.path = path;
+ this.fd = null;
+ this.writable = true;
+ this.flags = "w";
+ this.encoding = "binary";
+ this.mode = 438;
+ this.bytesWritten = 0;
+ options = options || {};
+ var keys = Object.keys(options);
+ for (var index = 0, length = keys.length; index < length; index++) {
+ var key = keys[index];
+ this[key] = options[key];
+ }
+ if (this.start !== void 0) {
+ if (typeof this.start !== "number") {
+ throw TypeError("start must be a Number");
+ }
+ if (this.start < 0) {
+ throw new Error("start must be >= zero");
+ }
+ this.pos = this.start;
+ }
+ this.busy = false;
+ this._queue = [];
+ if (this.fd === null) {
+ this._open = fs.open;
+ this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
+ this.flush();
+ }
+ }
+ }
+ }
+});
+
+// node_modules/graceful-fs/clone.js
+var require_clone = __commonJS({
+ "node_modules/graceful-fs/clone.js"(exports, module2) {
+ "use strict";
+ module2.exports = clone;
+ var getPrototypeOf = Object.getPrototypeOf || function(obj) {
+ return obj.__proto__;
+ };
+ function clone(obj) {
+ if (obj === null || typeof obj !== "object")
+ return obj;
+ if (obj instanceof Object)
+ var copy = { __proto__: getPrototypeOf(obj) };
+ else
+ var copy = /* @__PURE__ */ Object.create(null);
+ Object.getOwnPropertyNames(obj).forEach(function(key) {
+ Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key));
+ });
+ return copy;
+ }
+ }
+});
+
+// node_modules/graceful-fs/graceful-fs.js
+var require_graceful_fs = __commonJS({
+ "node_modules/graceful-fs/graceful-fs.js"(exports, module2) {
+ var fs = require("fs");
+ var polyfills = require_polyfills();
+ var legacy = require_legacy_streams();
+ var clone = require_clone();
+ var util = require("util");
+ var gracefulQueue;
+ var previousSymbol;
+ if (typeof Symbol === "function" && typeof Symbol.for === "function") {
+ gracefulQueue = Symbol.for("graceful-fs.queue");
+ previousSymbol = Symbol.for("graceful-fs.previous");
+ } else {
+ gracefulQueue = "___graceful-fs.queue";
+ previousSymbol = "___graceful-fs.previous";
+ }
+ function noop() {
+ }
+ function publishQueue(context, queue2) {
+ Object.defineProperty(context, gracefulQueue, {
+ get: function() {
+ return queue2;
+ }
+ });
+ }
+ var debug = noop;
+ if (util.debuglog)
+ debug = util.debuglog("gfs4");
+ else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ""))
+ debug = function() {
+ var m = util.format.apply(util, arguments);
+ m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
+ console.error(m);
+ };
+ if (!fs[gracefulQueue]) {
+ queue = global[gracefulQueue] || [];
+ publishQueue(fs, queue);
+ fs.close = function(fs$close) {
+ function close(fd, cb) {
+ return fs$close.call(fs, fd, function(err) {
+ if (!err) {
+ resetQueue();
+ }
+ if (typeof cb === "function")
+ cb.apply(this, arguments);
+ });
+ }
+ Object.defineProperty(close, previousSymbol, {
+ value: fs$close
+ });
+ return close;
+ }(fs.close);
+ fs.closeSync = function(fs$closeSync) {
+ function closeSync(fd) {
+ fs$closeSync.apply(fs, arguments);
+ resetQueue();
+ }
+ Object.defineProperty(closeSync, previousSymbol, {
+ value: fs$closeSync
+ });
+ return closeSync;
+ }(fs.closeSync);
+ if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
+ process.on("exit", function() {
+ debug(fs[gracefulQueue]);
+ require("assert").equal(fs[gracefulQueue].length, 0);
+ });
+ }
+ }
+ var queue;
+ if (!global[gracefulQueue]) {
+ publishQueue(global, fs[gracefulQueue]);
+ }
+ module2.exports = patch(clone(fs));
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
+ module2.exports = patch(fs);
+ fs.__patched = true;
+ }
+ function patch(fs2) {
+ polyfills(fs2);
+ fs2.gracefulify = patch;
+ fs2.createReadStream = createReadStream;
+ fs2.createWriteStream = createWriteStream;
+ var fs$readFile = fs2.readFile;
+ fs2.readFile = readFile;
+ function readFile(path, options, cb) {
+ if (typeof options === "function")
+ cb = options, options = null;
+ return go$readFile(path, options, cb);
+ function go$readFile(path2, options2, cb2, startTime) {
+ return fs$readFile(path2, options2, function(err) {
+ if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
+ enqueue([go$readFile, [path2, options2, cb2], err, startTime || Date.now(), Date.now()]);
+ else {
+ if (typeof cb2 === "function")
+ cb2.apply(this, arguments);
+ }
+ });
+ }
+ }
+ var fs$writeFile = fs2.writeFile;
+ fs2.writeFile = writeFile2;
+ function writeFile2(path, data, options, cb) {
+ if (typeof options === "function")
+ cb = options, options = null;
+ return go$writeFile(path, data, options, cb);
+ function go$writeFile(path2, data2, options2, cb2, startTime) {
+ return fs$writeFile(path2, data2, options2, function(err) {
+ if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
+ enqueue([go$writeFile, [path2, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
+ else {
+ if (typeof cb2 === "function")
+ cb2.apply(this, arguments);
+ }
+ });
+ }
+ }
+ var fs$appendFile = fs2.appendFile;
+ if (fs$appendFile)
+ fs2.appendFile = appendFile;
+ function appendFile(path, data, options, cb) {
+ if (typeof options === "function")
+ cb = options, options = null;
+ return go$appendFile(path, data, options, cb);
+ function go$appendFile(path2, data2, options2, cb2, startTime) {
+ return fs$appendFile(path2, data2, options2, function(err) {
+ if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
+ enqueue([go$appendFile, [path2, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
+ else {
+ if (typeof cb2 === "function")
+ cb2.apply(this, arguments);
+ }
+ });
+ }
+ }
+ var fs$copyFile = fs2.copyFile;
+ if (fs$copyFile)
+ fs2.copyFile = copyFile;
+ function copyFile(src, dest, flags, cb) {
+ if (typeof flags === "function") {
+ cb = flags;
+ flags = 0;
+ }
+ return go$copyFile(src, dest, flags, cb);
+ function go$copyFile(src2, dest2, flags2, cb2, startTime) {
+ return fs$copyFile(src2, dest2, flags2, function(err) {
+ if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
+ enqueue([go$copyFile, [src2, dest2, flags2, cb2], err, startTime || Date.now(), Date.now()]);
+ else {
+ if (typeof cb2 === "function")
+ cb2.apply(this, arguments);
+ }
+ });
+ }
+ }
+ var fs$readdir = fs2.readdir;
+ fs2.readdir = readdir;
+ function readdir(path, options, cb) {
+ if (typeof options === "function")
+ cb = options, options = null;
+ return go$readdir(path, options, cb);
+ function go$readdir(path2, options2, cb2, startTime) {
+ return fs$readdir(path2, options2, function(err, files) {
+ if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
+ enqueue([go$readdir, [path2, options2, cb2], err, startTime || Date.now(), Date.now()]);
+ else {
+ if (files && files.sort)
+ files.sort();
+ if (typeof cb2 === "function")
+ cb2.call(this, err, files);
+ }
+ });
+ }
+ }
+ if (process.version.substr(0, 4) === "v0.8") {
+ var legStreams = legacy(fs2);
+ ReadStream = legStreams.ReadStream;
+ WriteStream = legStreams.WriteStream;
+ }
+ var fs$ReadStream = fs2.ReadStream;
+ if (fs$ReadStream) {
+ ReadStream.prototype = Object.create(fs$ReadStream.prototype);
+ ReadStream.prototype.open = ReadStream$open;
+ }
+ var fs$WriteStream = fs2.WriteStream;
+ if (fs$WriteStream) {
+ WriteStream.prototype = Object.create(fs$WriteStream.prototype);
+ WriteStream.prototype.open = WriteStream$open;
+ }
+ Object.defineProperty(fs2, "ReadStream", {
+ get: function() {
+ return ReadStream;
+ },
+ set: function(val) {
+ ReadStream = val;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(fs2, "WriteStream", {
+ get: function() {
+ return WriteStream;
+ },
+ set: function(val) {
+ WriteStream = val;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ var FileReadStream = ReadStream;
+ Object.defineProperty(fs2, "FileReadStream", {
+ get: function() {
+ return FileReadStream;
+ },
+ set: function(val) {
+ FileReadStream = val;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ var FileWriteStream = WriteStream;
+ Object.defineProperty(fs2, "FileWriteStream", {
+ get: function() {
+ return FileWriteStream;
+ },
+ set: function(val) {
+ FileWriteStream = val;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ function ReadStream(path, options) {
+ if (this instanceof ReadStream)
+ return fs$ReadStream.apply(this, arguments), this;
+ else
+ return ReadStream.apply(Object.create(ReadStream.prototype), arguments);
+ }
+ function ReadStream$open() {
+ var that = this;
+ open(that.path, that.flags, that.mode, function(err, fd) {
+ if (err) {
+ if (that.autoClose)
+ that.destroy();
+ that.emit("error", err);
+ } else {
+ that.fd = fd;
+ that.emit("open", fd);
+ that.read();
+ }
+ });
+ }
+ function WriteStream(path, options) {
+ if (this instanceof WriteStream)
+ return fs$WriteStream.apply(this, arguments), this;
+ else
+ return WriteStream.apply(Object.create(WriteStream.prototype), arguments);
+ }
+ function WriteStream$open() {
+ var that = this;
+ open(that.path, that.flags, that.mode, function(err, fd) {
+ if (err) {
+ that.destroy();
+ that.emit("error", err);
+ } else {
+ that.fd = fd;
+ that.emit("open", fd);
+ }
+ });
+ }
+ function createReadStream(path, options) {
+ return new fs2.ReadStream(path, options);
+ }
+ function createWriteStream(path, options) {
+ return new fs2.WriteStream(path, options);
+ }
+ var fs$open = fs2.open;
+ fs2.open = open;
+ function open(path, flags, mode, cb) {
+ if (typeof mode === "function")
+ cb = mode, mode = null;
+ return go$open(path, flags, mode, cb);
+ function go$open(path2, flags2, mode2, cb2, startTime) {
+ return fs$open(path2, flags2, mode2, function(err, fd) {
+ if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
+ enqueue([go$open, [path2, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
+ else {
+ if (typeof cb2 === "function")
+ cb2.apply(this, arguments);
+ }
+ });
+ }
+ }
+ return fs2;
+ }
+ function enqueue(elem) {
+ debug("ENQUEUE", elem[0].name, elem[1]);
+ fs[gracefulQueue].push(elem);
+ retry();
+ }
+ var retryTimer;
+ function resetQueue() {
+ var now = Date.now();
+ for (var i = 0; i < fs[gracefulQueue].length; ++i) {
+ if (fs[gracefulQueue][i].length > 2) {
+ fs[gracefulQueue][i][3] = now;
+ fs[gracefulQueue][i][4] = now;
+ }
+ }
+ retry();
+ }
+ function retry() {
+ clearTimeout(retryTimer);
+ retryTimer = void 0;
+ if (fs[gracefulQueue].length === 0)
+ return;
+ var elem = fs[gracefulQueue].shift();
+ var fn = elem[0];
+ var args = elem[1];
+ var err = elem[2];
+ var startTime = elem[3];
+ var lastTime = elem[4];
+ if (startTime === void 0) {
+ debug("RETRY", fn.name, args);
+ fn.apply(null, args);
+ } else if (Date.now() - startTime >= 6e4) {
+ debug("TIMEOUT", fn.name, args);
+ var cb = args.pop();
+ if (typeof cb === "function")
+ cb.call(null, err);
+ } else {
+ var sinceAttempt = Date.now() - lastTime;
+ var sinceStart = Math.max(lastTime - startTime, 1);
+ var desiredDelay = Math.min(sinceStart * 1.2, 100);
+ if (sinceAttempt >= desiredDelay) {
+ debug("RETRY", fn.name, args);
+ fn.apply(null, args.concat([startTime]));
+ } else {
+ fs[gracefulQueue].push(elem);
+ }
+ }
+ if (retryTimer === void 0) {
+ retryTimer = setTimeout(retry, 0);
+ }
+ }
+ }
+});
+
+// node_modules/fs-extra/lib/fs/index.js
+var require_fs = __commonJS({
+ "node_modules/fs-extra/lib/fs/index.js"(exports) {
+ "use strict";
+ var u = require_universalify().fromCallback;
+ var fs = require_graceful_fs();
+ var api = [
+ "access",
+ "appendFile",
+ "chmod",
+ "chown",
+ "close",
+ "copyFile",
+ "fchmod",
+ "fchown",
+ "fdatasync",
+ "fstat",
+ "fsync",
+ "ftruncate",
+ "futimes",
+ "lchmod",
+ "lchown",
+ "link",
+ "lstat",
+ "mkdir",
+ "mkdtemp",
+ "open",
+ "opendir",
+ "readdir",
+ "readFile",
+ "readlink",
+ "realpath",
+ "rename",
+ "rm",
+ "rmdir",
+ "stat",
+ "symlink",
+ "truncate",
+ "unlink",
+ "utimes",
+ "writeFile"
+ ].filter((key) => {
+ return typeof fs[key] === "function";
+ });
+ Object.assign(exports, fs);
+ api.forEach((method) => {
+ exports[method] = u(fs[method]);
+ });
+ exports.realpath.native = u(fs.realpath.native);
+ exports.exists = function(filename, callback) {
+ if (typeof callback === "function") {
+ return fs.exists(filename, callback);
+ }
+ return new Promise((resolve6) => {
+ return fs.exists(filename, resolve6);
+ });
+ };
+ exports.read = function(fd, buffer, offset, length, position, callback) {
+ if (typeof callback === "function") {
+ return fs.read(fd, buffer, offset, length, position, callback);
+ }
+ return new Promise((resolve6, reject) => {
+ fs.read(fd, buffer, offset, length, position, (err, bytesRead, buffer2) => {
+ if (err)
+ return reject(err);
+ resolve6({ bytesRead, buffer: buffer2 });
+ });
+ });
+ };
+ exports.write = function(fd, buffer, ...args) {
+ if (typeof args[args.length - 1] === "function") {
+ return fs.write(fd, buffer, ...args);
+ }
+ return new Promise((resolve6, reject) => {
+ fs.write(fd, buffer, ...args, (err, bytesWritten, buffer2) => {
+ if (err)
+ return reject(err);
+ resolve6({ bytesWritten, buffer: buffer2 });
+ });
+ });
+ };
+ if (typeof fs.writev === "function") {
+ exports.writev = function(fd, buffers, ...args) {
+ if (typeof args[args.length - 1] === "function") {
+ return fs.writev(fd, buffers, ...args);
+ }
+ return new Promise((resolve6, reject) => {
+ fs.writev(fd, buffers, ...args, (err, bytesWritten, buffers2) => {
+ if (err)
+ return reject(err);
+ resolve6({ bytesWritten, buffers: buffers2 });
+ });
+ });
+ };
+ }
+ }
+});
+
+// node_modules/fs-extra/lib/mkdirs/utils.js
+var require_utils = __commonJS({
+ "node_modules/fs-extra/lib/mkdirs/utils.js"(exports, module2) {
+ "use strict";
+ var path = require("path");
+ module2.exports.checkPath = function checkPath(pth) {
+ if (process.platform === "win32") {
+ const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, ""));
+ if (pathHasInvalidWinCharacters) {
+ const error = new Error(`Path contains invalid characters: ${pth}`);
+ error.code = "EINVAL";
+ throw error;
+ }
+ }
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/mkdirs/make-dir.js
+var require_make_dir = __commonJS({
+ "node_modules/fs-extra/lib/mkdirs/make-dir.js"(exports, module2) {
+ "use strict";
+ var fs = require_fs();
+ var { checkPath } = require_utils();
+ var getMode = (options) => {
+ const defaults = { mode: 511 };
+ if (typeof options === "number")
+ return options;
+ return __spreadValues(__spreadValues({}, defaults), options).mode;
+ };
+ module2.exports.makeDir = async (dir, options) => {
+ checkPath(dir);
+ return fs.mkdir(dir, {
+ mode: getMode(options),
+ recursive: true
+ });
+ };
+ module2.exports.makeDirSync = (dir, options) => {
+ checkPath(dir);
+ return fs.mkdirSync(dir, {
+ mode: getMode(options),
+ recursive: true
+ });
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/mkdirs/index.js
+var require_mkdirs = __commonJS({
+ "node_modules/fs-extra/lib/mkdirs/index.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromPromise;
+ var { makeDir: _makeDir, makeDirSync } = require_make_dir();
+ var makeDir = u(_makeDir);
+ module2.exports = {
+ mkdirs: makeDir,
+ mkdirsSync: makeDirSync,
+ mkdirp: makeDir,
+ mkdirpSync: makeDirSync,
+ ensureDir: makeDir,
+ ensureDirSync: makeDirSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/util/utimes.js
+var require_utimes = __commonJS({
+ "node_modules/fs-extra/lib/util/utimes.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ function utimesMillis(path, atime, mtime, callback) {
+ fs.open(path, "r+", (err, fd) => {
+ if (err)
+ return callback(err);
+ fs.futimes(fd, atime, mtime, (futimesErr) => {
+ fs.close(fd, (closeErr) => {
+ if (callback)
+ callback(futimesErr || closeErr);
+ });
+ });
+ });
+ }
+ function utimesMillisSync(path, atime, mtime) {
+ const fd = fs.openSync(path, "r+");
+ fs.futimesSync(fd, atime, mtime);
+ return fs.closeSync(fd);
+ }
+ module2.exports = {
+ utimesMillis,
+ utimesMillisSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/util/stat.js
+var require_stat = __commonJS({
+ "node_modules/fs-extra/lib/util/stat.js"(exports, module2) {
+ "use strict";
+ var fs = require_fs();
+ var path = require("path");
+ var util = require("util");
+ function getStats(src, dest, opts) {
+ const statFunc = opts.dereference ? (file) => fs.stat(file, { bigint: true }) : (file) => fs.lstat(file, { bigint: true });
+ return Promise.all([
+ statFunc(src),
+ statFunc(dest).catch((err) => {
+ if (err.code === "ENOENT")
+ return null;
+ throw err;
+ })
+ ]).then(([srcStat, destStat]) => ({ srcStat, destStat }));
+ }
+ function getStatsSync(src, dest, opts) {
+ let destStat;
+ const statFunc = opts.dereference ? (file) => fs.statSync(file, { bigint: true }) : (file) => fs.lstatSync(file, { bigint: true });
+ const srcStat = statFunc(src);
+ try {
+ destStat = statFunc(dest);
+ } catch (err) {
+ if (err.code === "ENOENT")
+ return { srcStat, destStat: null };
+ throw err;
+ }
+ return { srcStat, destStat };
+ }
+ function checkPaths(src, dest, funcName, opts, cb) {
+ util.callbackify(getStats)(src, dest, opts, (err, stats) => {
+ if (err)
+ return cb(err);
+ const { srcStat, destStat } = stats;
+ if (destStat) {
+ if (areIdentical(srcStat, destStat)) {
+ const srcBaseName = path.basename(src);
+ const destBaseName = path.basename(dest);
+ if (funcName === "move" && srcBaseName !== destBaseName && srcBaseName.toLowerCase() === destBaseName.toLowerCase()) {
+ return cb(null, { srcStat, destStat, isChangingCase: true });
+ }
+ return cb(new Error("Source and destination must not be the same."));
+ }
+ if (srcStat.isDirectory() && !destStat.isDirectory()) {
+ return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`));
+ }
+ if (!srcStat.isDirectory() && destStat.isDirectory()) {
+ return cb(new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`));
+ }
+ }
+ if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
+ return cb(new Error(errMsg(src, dest, funcName)));
+ }
+ return cb(null, { srcStat, destStat });
+ });
+ }
+ function checkPathsSync(src, dest, funcName, opts) {
+ const { srcStat, destStat } = getStatsSync(src, dest, opts);
+ if (destStat) {
+ if (areIdentical(srcStat, destStat)) {
+ const srcBaseName = path.basename(src);
+ const destBaseName = path.basename(dest);
+ if (funcName === "move" && srcBaseName !== destBaseName && srcBaseName.toLowerCase() === destBaseName.toLowerCase()) {
+ return { srcStat, destStat, isChangingCase: true };
+ }
+ throw new Error("Source and destination must not be the same.");
+ }
+ if (srcStat.isDirectory() && !destStat.isDirectory()) {
+ throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`);
+ }
+ if (!srcStat.isDirectory() && destStat.isDirectory()) {
+ throw new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`);
+ }
+ }
+ if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
+ throw new Error(errMsg(src, dest, funcName));
+ }
+ return { srcStat, destStat };
+ }
+ function checkParentPaths(src, srcStat, dest, funcName, cb) {
+ const srcParent = path.resolve(path.dirname(src));
+ const destParent = path.resolve(path.dirname(dest));
+ if (destParent === srcParent || destParent === path.parse(destParent).root)
+ return cb();
+ fs.stat(destParent, { bigint: true }, (err, destStat) => {
+ if (err) {
+ if (err.code === "ENOENT")
+ return cb();
+ return cb(err);
+ }
+ if (areIdentical(srcStat, destStat)) {
+ return cb(new Error(errMsg(src, dest, funcName)));
+ }
+ return checkParentPaths(src, srcStat, destParent, funcName, cb);
+ });
+ }
+ function checkParentPathsSync(src, srcStat, dest, funcName) {
+ const srcParent = path.resolve(path.dirname(src));
+ const destParent = path.resolve(path.dirname(dest));
+ if (destParent === srcParent || destParent === path.parse(destParent).root)
+ return;
+ let destStat;
+ try {
+ destStat = fs.statSync(destParent, { bigint: true });
+ } catch (err) {
+ if (err.code === "ENOENT")
+ return;
+ throw err;
+ }
+ if (areIdentical(srcStat, destStat)) {
+ throw new Error(errMsg(src, dest, funcName));
+ }
+ return checkParentPathsSync(src, srcStat, destParent, funcName);
+ }
+ function areIdentical(srcStat, destStat) {
+ return destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev;
+ }
+ function isSrcSubdir(src, dest) {
+ const srcArr = path.resolve(src).split(path.sep).filter((i) => i);
+ const destArr = path.resolve(dest).split(path.sep).filter((i) => i);
+ return srcArr.reduce((acc, cur, i) => acc && destArr[i] === cur, true);
+ }
+ function errMsg(src, dest, funcName) {
+ return `Cannot ${funcName} '${src}' to a subdirectory of itself, '${dest}'.`;
+ }
+ module2.exports = {
+ checkPaths,
+ checkPathsSync,
+ checkParentPaths,
+ checkParentPathsSync,
+ isSrcSubdir,
+ areIdentical
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/copy-sync/copy-sync.js
+var require_copy_sync = __commonJS({
+ "node_modules/fs-extra/lib/copy-sync/copy-sync.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ var path = require("path");
+ var mkdirsSync = require_mkdirs().mkdirsSync;
+ var utimesMillisSync = require_utimes().utimesMillisSync;
+ var stat = require_stat();
+ function copySync2(src, dest, opts) {
+ if (typeof opts === "function") {
+ opts = { filter: opts };
+ }
+ opts = opts || {};
+ opts.clobber = "clobber" in opts ? !!opts.clobber : true;
+ opts.overwrite = "overwrite" in opts ? !!opts.overwrite : opts.clobber;
+ if (opts.preserveTimestamps && process.arch === "ia32") {
+ console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;
+
+ see https://github.com/jprichardson/node-fs-extra/issues/269`);
+ }
+ const { srcStat, destStat } = stat.checkPathsSync(src, dest, "copy", opts);
+ stat.checkParentPathsSync(src, srcStat, dest, "copy");
+ return handleFilterAndCopy(destStat, src, dest, opts);
+ }
+ function handleFilterAndCopy(destStat, src, dest, opts) {
+ if (opts.filter && !opts.filter(src, dest))
+ return;
+ const destParent = path.dirname(dest);
+ if (!fs.existsSync(destParent))
+ mkdirsSync(destParent);
+ return getStats(destStat, src, dest, opts);
+ }
+ function startCopy(destStat, src, dest, opts) {
+ if (opts.filter && !opts.filter(src, dest))
+ return;
+ return getStats(destStat, src, dest, opts);
+ }
+ function getStats(destStat, src, dest, opts) {
+ const statSync3 = opts.dereference ? fs.statSync : fs.lstatSync;
+ const srcStat = statSync3(src);
+ if (srcStat.isDirectory())
+ return onDir(srcStat, destStat, src, dest, opts);
+ else if (srcStat.isFile() || srcStat.isCharacterDevice() || srcStat.isBlockDevice())
+ return onFile(srcStat, destStat, src, dest, opts);
+ else if (srcStat.isSymbolicLink())
+ return onLink(destStat, src, dest, opts);
+ else if (srcStat.isSocket())
+ throw new Error(`Cannot copy a socket file: ${src}`);
+ else if (srcStat.isFIFO())
+ throw new Error(`Cannot copy a FIFO pipe: ${src}`);
+ throw new Error(`Unknown file: ${src}`);
+ }
+ function onFile(srcStat, destStat, src, dest, opts) {
+ if (!destStat)
+ return copyFile(srcStat, src, dest, opts);
+ return mayCopyFile(srcStat, src, dest, opts);
+ }
+ function mayCopyFile(srcStat, src, dest, opts) {
+ if (opts.overwrite) {
+ fs.unlinkSync(dest);
+ return copyFile(srcStat, src, dest, opts);
+ } else if (opts.errorOnExist) {
+ throw new Error(`'${dest}' already exists`);
+ }
+ }
+ function copyFile(srcStat, src, dest, opts) {
+ fs.copyFileSync(src, dest);
+ if (opts.preserveTimestamps)
+ handleTimestamps(srcStat.mode, src, dest);
+ return setDestMode(dest, srcStat.mode);
+ }
+ function handleTimestamps(srcMode, src, dest) {
+ if (fileIsNotWritable(srcMode))
+ makeFileWritable(dest, srcMode);
+ return setDestTimestamps(src, dest);
+ }
+ function fileIsNotWritable(srcMode) {
+ return (srcMode & 128) === 0;
+ }
+ function makeFileWritable(dest, srcMode) {
+ return setDestMode(dest, srcMode | 128);
+ }
+ function setDestMode(dest, srcMode) {
+ return fs.chmodSync(dest, srcMode);
+ }
+ function setDestTimestamps(src, dest) {
+ const updatedSrcStat = fs.statSync(src);
+ return utimesMillisSync(dest, updatedSrcStat.atime, updatedSrcStat.mtime);
+ }
+ function onDir(srcStat, destStat, src, dest, opts) {
+ if (!destStat)
+ return mkDirAndCopy(srcStat.mode, src, dest, opts);
+ return copyDir(src, dest, opts);
+ }
+ function mkDirAndCopy(srcMode, src, dest, opts) {
+ fs.mkdirSync(dest);
+ copyDir(src, dest, opts);
+ return setDestMode(dest, srcMode);
+ }
+ function copyDir(src, dest, opts) {
+ fs.readdirSync(src).forEach((item) => copyDirItem(item, src, dest, opts));
+ }
+ function copyDirItem(item, src, dest, opts) {
+ const srcItem = path.join(src, item);
+ const destItem = path.join(dest, item);
+ const { destStat } = stat.checkPathsSync(srcItem, destItem, "copy", opts);
+ return startCopy(destStat, srcItem, destItem, opts);
+ }
+ function onLink(destStat, src, dest, opts) {
+ let resolvedSrc = fs.readlinkSync(src);
+ if (opts.dereference) {
+ resolvedSrc = path.resolve(process.cwd(), resolvedSrc);
+ }
+ if (!destStat) {
+ return fs.symlinkSync(resolvedSrc, dest);
+ } else {
+ let resolvedDest;
+ try {
+ resolvedDest = fs.readlinkSync(dest);
+ } catch (err) {
+ if (err.code === "EINVAL" || err.code === "UNKNOWN")
+ return fs.symlinkSync(resolvedSrc, dest);
+ throw err;
+ }
+ if (opts.dereference) {
+ resolvedDest = path.resolve(process.cwd(), resolvedDest);
+ }
+ if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
+ throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`);
+ }
+ if (fs.statSync(dest).isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
+ throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`);
+ }
+ return copyLink(resolvedSrc, dest);
+ }
+ }
+ function copyLink(resolvedSrc, dest) {
+ fs.unlinkSync(dest);
+ return fs.symlinkSync(resolvedSrc, dest);
+ }
+ module2.exports = copySync2;
+ }
+});
+
+// node_modules/fs-extra/lib/copy-sync/index.js
+var require_copy_sync2 = __commonJS({
+ "node_modules/fs-extra/lib/copy-sync/index.js"(exports, module2) {
+ "use strict";
+ module2.exports = {
+ copySync: require_copy_sync()
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/path-exists/index.js
+var require_path_exists = __commonJS({
+ "node_modules/fs-extra/lib/path-exists/index.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromPromise;
+ var fs = require_fs();
+ function pathExists(path) {
+ return fs.access(path).then(() => true).catch(() => false);
+ }
+ module2.exports = {
+ pathExists: u(pathExists),
+ pathExistsSync: fs.existsSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/copy/copy.js
+var require_copy = __commonJS({
+ "node_modules/fs-extra/lib/copy/copy.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ var path = require("path");
+ var mkdirs = require_mkdirs().mkdirs;
+ var pathExists = require_path_exists().pathExists;
+ var utimesMillis = require_utimes().utimesMillis;
+ var stat = require_stat();
+ function copy(src, dest, opts, cb) {
+ if (typeof opts === "function" && !cb) {
+ cb = opts;
+ opts = {};
+ } else if (typeof opts === "function") {
+ opts = { filter: opts };
+ }
+ cb = cb || function() {
+ };
+ opts = opts || {};
+ opts.clobber = "clobber" in opts ? !!opts.clobber : true;
+ opts.overwrite = "overwrite" in opts ? !!opts.overwrite : opts.clobber;
+ if (opts.preserveTimestamps && process.arch === "ia32") {
+ console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;
+
+ see https://github.com/jprichardson/node-fs-extra/issues/269`);
+ }
+ stat.checkPaths(src, dest, "copy", opts, (err, stats) => {
+ if (err)
+ return cb(err);
+ const { srcStat, destStat } = stats;
+ stat.checkParentPaths(src, srcStat, dest, "copy", (err2) => {
+ if (err2)
+ return cb(err2);
+ if (opts.filter)
+ return handleFilter(checkParentDir, destStat, src, dest, opts, cb);
+ return checkParentDir(destStat, src, dest, opts, cb);
+ });
+ });
+ }
+ function checkParentDir(destStat, src, dest, opts, cb) {
+ const destParent = path.dirname(dest);
+ pathExists(destParent, (err, dirExists) => {
+ if (err)
+ return cb(err);
+ if (dirExists)
+ return getStats(destStat, src, dest, opts, cb);
+ mkdirs(destParent, (err2) => {
+ if (err2)
+ return cb(err2);
+ return getStats(destStat, src, dest, opts, cb);
+ });
+ });
+ }
+ function handleFilter(onInclude, destStat, src, dest, opts, cb) {
+ Promise.resolve(opts.filter(src, dest)).then((include) => {
+ if (include)
+ return onInclude(destStat, src, dest, opts, cb);
+ return cb();
+ }, (error) => cb(error));
+ }
+ function startCopy(destStat, src, dest, opts, cb) {
+ if (opts.filter)
+ return handleFilter(getStats, destStat, src, dest, opts, cb);
+ return getStats(destStat, src, dest, opts, cb);
+ }
+ function getStats(destStat, src, dest, opts, cb) {
+ const stat2 = opts.dereference ? fs.stat : fs.lstat;
+ stat2(src, (err, srcStat) => {
+ if (err)
+ return cb(err);
+ if (srcStat.isDirectory())
+ return onDir(srcStat, destStat, src, dest, opts, cb);
+ else if (srcStat.isFile() || srcStat.isCharacterDevice() || srcStat.isBlockDevice())
+ return onFile(srcStat, destStat, src, dest, opts, cb);
+ else if (srcStat.isSymbolicLink())
+ return onLink(destStat, src, dest, opts, cb);
+ else if (srcStat.isSocket())
+ return cb(new Error(`Cannot copy a socket file: ${src}`));
+ else if (srcStat.isFIFO())
+ return cb(new Error(`Cannot copy a FIFO pipe: ${src}`));
+ return cb(new Error(`Unknown file: ${src}`));
+ });
+ }
+ function onFile(srcStat, destStat, src, dest, opts, cb) {
+ if (!destStat)
+ return copyFile(srcStat, src, dest, opts, cb);
+ return mayCopyFile(srcStat, src, dest, opts, cb);
+ }
+ function mayCopyFile(srcStat, src, dest, opts, cb) {
+ if (opts.overwrite) {
+ fs.unlink(dest, (err) => {
+ if (err)
+ return cb(err);
+ return copyFile(srcStat, src, dest, opts, cb);
+ });
+ } else if (opts.errorOnExist) {
+ return cb(new Error(`'${dest}' already exists`));
+ } else
+ return cb();
+ }
+ function copyFile(srcStat, src, dest, opts, cb) {
+ fs.copyFile(src, dest, (err) => {
+ if (err)
+ return cb(err);
+ if (opts.preserveTimestamps)
+ return handleTimestampsAndMode(srcStat.mode, src, dest, cb);
+ return setDestMode(dest, srcStat.mode, cb);
+ });
+ }
+ function handleTimestampsAndMode(srcMode, src, dest, cb) {
+ if (fileIsNotWritable(srcMode)) {
+ return makeFileWritable(dest, srcMode, (err) => {
+ if (err)
+ return cb(err);
+ return setDestTimestampsAndMode(srcMode, src, dest, cb);
+ });
+ }
+ return setDestTimestampsAndMode(srcMode, src, dest, cb);
+ }
+ function fileIsNotWritable(srcMode) {
+ return (srcMode & 128) === 0;
+ }
+ function makeFileWritable(dest, srcMode, cb) {
+ return setDestMode(dest, srcMode | 128, cb);
+ }
+ function setDestTimestampsAndMode(srcMode, src, dest, cb) {
+ setDestTimestamps(src, dest, (err) => {
+ if (err)
+ return cb(err);
+ return setDestMode(dest, srcMode, cb);
+ });
+ }
+ function setDestMode(dest, srcMode, cb) {
+ return fs.chmod(dest, srcMode, cb);
+ }
+ function setDestTimestamps(src, dest, cb) {
+ fs.stat(src, (err, updatedSrcStat) => {
+ if (err)
+ return cb(err);
+ return utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime, cb);
+ });
+ }
+ function onDir(srcStat, destStat, src, dest, opts, cb) {
+ if (!destStat)
+ return mkDirAndCopy(srcStat.mode, src, dest, opts, cb);
+ return copyDir(src, dest, opts, cb);
+ }
+ function mkDirAndCopy(srcMode, src, dest, opts, cb) {
+ fs.mkdir(dest, (err) => {
+ if (err)
+ return cb(err);
+ copyDir(src, dest, opts, (err2) => {
+ if (err2)
+ return cb(err2);
+ return setDestMode(dest, srcMode, cb);
+ });
+ });
+ }
+ function copyDir(src, dest, opts, cb) {
+ fs.readdir(src, (err, items) => {
+ if (err)
+ return cb(err);
+ return copyDirItems(items, src, dest, opts, cb);
+ });
+ }
+ function copyDirItems(items, src, dest, opts, cb) {
+ const item = items.pop();
+ if (!item)
+ return cb();
+ return copyDirItem(items, item, src, dest, opts, cb);
+ }
+ function copyDirItem(items, item, src, dest, opts, cb) {
+ const srcItem = path.join(src, item);
+ const destItem = path.join(dest, item);
+ stat.checkPaths(srcItem, destItem, "copy", opts, (err, stats) => {
+ if (err)
+ return cb(err);
+ const { destStat } = stats;
+ startCopy(destStat, srcItem, destItem, opts, (err2) => {
+ if (err2)
+ return cb(err2);
+ return copyDirItems(items, src, dest, opts, cb);
+ });
+ });
+ }
+ function onLink(destStat, src, dest, opts, cb) {
+ fs.readlink(src, (err, resolvedSrc) => {
+ if (err)
+ return cb(err);
+ if (opts.dereference) {
+ resolvedSrc = path.resolve(process.cwd(), resolvedSrc);
+ }
+ if (!destStat) {
+ return fs.symlink(resolvedSrc, dest, cb);
+ } else {
+ fs.readlink(dest, (err2, resolvedDest) => {
+ if (err2) {
+ if (err2.code === "EINVAL" || err2.code === "UNKNOWN")
+ return fs.symlink(resolvedSrc, dest, cb);
+ return cb(err2);
+ }
+ if (opts.dereference) {
+ resolvedDest = path.resolve(process.cwd(), resolvedDest);
+ }
+ if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
+ return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`));
+ }
+ if (destStat.isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
+ return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`));
+ }
+ return copyLink(resolvedSrc, dest, cb);
+ });
+ }
+ });
+ }
+ function copyLink(resolvedSrc, dest, cb) {
+ fs.unlink(dest, (err) => {
+ if (err)
+ return cb(err);
+ return fs.symlink(resolvedSrc, dest, cb);
+ });
+ }
+ module2.exports = copy;
+ }
+});
+
+// node_modules/fs-extra/lib/copy/index.js
+var require_copy2 = __commonJS({
+ "node_modules/fs-extra/lib/copy/index.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromCallback;
+ module2.exports = {
+ copy: u(require_copy())
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/remove/rimraf.js
+var require_rimraf = __commonJS({
+ "node_modules/fs-extra/lib/remove/rimraf.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ var path = require("path");
+ var assert = require("assert");
+ var isWindows = process.platform === "win32";
+ function defaults(options) {
+ const methods = [
+ "unlink",
+ "chmod",
+ "stat",
+ "lstat",
+ "rmdir",
+ "readdir"
+ ];
+ methods.forEach((m) => {
+ options[m] = options[m] || fs[m];
+ m = m + "Sync";
+ options[m] = options[m] || fs[m];
+ });
+ options.maxBusyTries = options.maxBusyTries || 3;
+ }
+ function rimraf(p, options, cb) {
+ let busyTries = 0;
+ if (typeof options === "function") {
+ cb = options;
+ options = {};
+ }
+ assert(p, "rimraf: missing path");
+ assert.strictEqual(typeof p, "string", "rimraf: path should be a string");
+ assert.strictEqual(typeof cb, "function", "rimraf: callback function required");
+ assert(options, "rimraf: invalid options argument provided");
+ assert.strictEqual(typeof options, "object", "rimraf: options should be object");
+ defaults(options);
+ rimraf_(p, options, function CB(er) {
+ if (er) {
+ if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && busyTries < options.maxBusyTries) {
+ busyTries++;
+ const time = busyTries * 100;
+ return setTimeout(() => rimraf_(p, options, CB), time);
+ }
+ if (er.code === "ENOENT")
+ er = null;
+ }
+ cb(er);
+ });
+ }
+ function rimraf_(p, options, cb) {
+ assert(p);
+ assert(options);
+ assert(typeof cb === "function");
+ options.lstat(p, (er, st) => {
+ if (er && er.code === "ENOENT") {
+ return cb(null);
+ }
+ if (er && er.code === "EPERM" && isWindows) {
+ return fixWinEPERM(p, options, er, cb);
+ }
+ if (st && st.isDirectory()) {
+ return rmdir(p, options, er, cb);
+ }
+ options.unlink(p, (er2) => {
+ if (er2) {
+ if (er2.code === "ENOENT") {
+ return cb(null);
+ }
+ if (er2.code === "EPERM") {
+ return isWindows ? fixWinEPERM(p, options, er2, cb) : rmdir(p, options, er2, cb);
+ }
+ if (er2.code === "EISDIR") {
+ return rmdir(p, options, er2, cb);
+ }
+ }
+ return cb(er2);
+ });
+ });
+ }
+ function fixWinEPERM(p, options, er, cb) {
+ assert(p);
+ assert(options);
+ assert(typeof cb === "function");
+ options.chmod(p, 438, (er2) => {
+ if (er2) {
+ cb(er2.code === "ENOENT" ? null : er);
+ } else {
+ options.stat(p, (er3, stats) => {
+ if (er3) {
+ cb(er3.code === "ENOENT" ? null : er);
+ } else if (stats.isDirectory()) {
+ rmdir(p, options, er, cb);
+ } else {
+ options.unlink(p, cb);
+ }
+ });
+ }
+ });
+ }
+ function fixWinEPERMSync(p, options, er) {
+ let stats;
+ assert(p);
+ assert(options);
+ try {
+ options.chmodSync(p, 438);
+ } catch (er2) {
+ if (er2.code === "ENOENT") {
+ return;
+ } else {
+ throw er;
+ }
+ }
+ try {
+ stats = options.statSync(p);
+ } catch (er3) {
+ if (er3.code === "ENOENT") {
+ return;
+ } else {
+ throw er;
+ }
+ }
+ if (stats.isDirectory()) {
+ rmdirSync(p, options, er);
+ } else {
+ options.unlinkSync(p);
+ }
+ }
+ function rmdir(p, options, originalEr, cb) {
+ assert(p);
+ assert(options);
+ assert(typeof cb === "function");
+ options.rmdir(p, (er) => {
+ if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) {
+ rmkids(p, options, cb);
+ } else if (er && er.code === "ENOTDIR") {
+ cb(originalEr);
+ } else {
+ cb(er);
+ }
+ });
+ }
+ function rmkids(p, options, cb) {
+ assert(p);
+ assert(options);
+ assert(typeof cb === "function");
+ options.readdir(p, (er, files) => {
+ if (er)
+ return cb(er);
+ let n = files.length;
+ let errState;
+ if (n === 0)
+ return options.rmdir(p, cb);
+ files.forEach((f) => {
+ rimraf(path.join(p, f), options, (er2) => {
+ if (errState) {
+ return;
+ }
+ if (er2)
+ return cb(errState = er2);
+ if (--n === 0) {
+ options.rmdir(p, cb);
+ }
+ });
+ });
+ });
+ }
+ function rimrafSync(p, options) {
+ let st;
+ options = options || {};
+ defaults(options);
+ assert(p, "rimraf: missing path");
+ assert.strictEqual(typeof p, "string", "rimraf: path should be a string");
+ assert(options, "rimraf: missing options");
+ assert.strictEqual(typeof options, "object", "rimraf: options should be object");
+ try {
+ st = options.lstatSync(p);
+ } catch (er) {
+ if (er.code === "ENOENT") {
+ return;
+ }
+ if (er.code === "EPERM" && isWindows) {
+ fixWinEPERMSync(p, options, er);
+ }
+ }
+ try {
+ if (st && st.isDirectory()) {
+ rmdirSync(p, options, null);
+ } else {
+ options.unlinkSync(p);
+ }
+ } catch (er) {
+ if (er.code === "ENOENT") {
+ return;
+ } else if (er.code === "EPERM") {
+ return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er);
+ } else if (er.code !== "EISDIR") {
+ throw er;
+ }
+ rmdirSync(p, options, er);
+ }
+ }
+ function rmdirSync(p, options, originalEr) {
+ assert(p);
+ assert(options);
+ try {
+ options.rmdirSync(p);
+ } catch (er) {
+ if (er.code === "ENOTDIR") {
+ throw originalEr;
+ } else if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") {
+ rmkidsSync(p, options);
+ } else if (er.code !== "ENOENT") {
+ throw er;
+ }
+ }
+ }
+ function rmkidsSync(p, options) {
+ assert(p);
+ assert(options);
+ options.readdirSync(p).forEach((f) => rimrafSync(path.join(p, f), options));
+ if (isWindows) {
+ const startTime = Date.now();
+ do {
+ try {
+ const ret = options.rmdirSync(p, options);
+ return ret;
+ } catch {
+ }
+ } while (Date.now() - startTime < 500);
+ } else {
+ const ret = options.rmdirSync(p, options);
+ return ret;
+ }
+ }
+ module2.exports = rimraf;
+ rimraf.sync = rimrafSync;
+ }
+});
+
+// node_modules/fs-extra/lib/remove/index.js
+var require_remove = __commonJS({
+ "node_modules/fs-extra/lib/remove/index.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ var u = require_universalify().fromCallback;
+ var rimraf = require_rimraf();
+ function remove(path, callback) {
+ if (fs.rm)
+ return fs.rm(path, { recursive: true, force: true }, callback);
+ rimraf(path, callback);
+ }
+ function removeSync(path) {
+ if (fs.rmSync)
+ return fs.rmSync(path, { recursive: true, force: true });
+ rimraf.sync(path);
+ }
+ module2.exports = {
+ remove: u(remove),
+ removeSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/empty/index.js
+var require_empty = __commonJS({
+ "node_modules/fs-extra/lib/empty/index.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromPromise;
+ var fs = require_fs();
+ var path = require("path");
+ var mkdir = require_mkdirs();
+ var remove = require_remove();
+ var emptyDir = u(async function emptyDir2(dir) {
+ let items;
+ try {
+ items = await fs.readdir(dir);
+ } catch {
+ return mkdir.mkdirs(dir);
+ }
+ return Promise.all(items.map((item) => remove.remove(path.join(dir, item))));
+ });
+ function emptyDirSync(dir) {
+ let items;
+ try {
+ items = fs.readdirSync(dir);
+ } catch {
+ return mkdir.mkdirsSync(dir);
+ }
+ items.forEach((item) => {
+ item = path.join(dir, item);
+ remove.removeSync(item);
+ });
+ }
+ module2.exports = {
+ emptyDirSync,
+ emptydirSync: emptyDirSync,
+ emptyDir,
+ emptydir: emptyDir
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/ensure/file.js
+var require_file = __commonJS({
+ "node_modules/fs-extra/lib/ensure/file.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromCallback;
+ var path = require("path");
+ var fs = require_graceful_fs();
+ var mkdir = require_mkdirs();
+ function createFile(file, callback) {
+ function makeFile() {
+ fs.writeFile(file, "", (err) => {
+ if (err)
+ return callback(err);
+ callback();
+ });
+ }
+ fs.stat(file, (err, stats) => {
+ if (!err && stats.isFile())
+ return callback();
+ const dir = path.dirname(file);
+ fs.stat(dir, (err2, stats2) => {
+ if (err2) {
+ if (err2.code === "ENOENT") {
+ return mkdir.mkdirs(dir, (err3) => {
+ if (err3)
+ return callback(err3);
+ makeFile();
+ });
+ }
+ return callback(err2);
+ }
+ if (stats2.isDirectory())
+ makeFile();
+ else {
+ fs.readdir(dir, (err3) => {
+ if (err3)
+ return callback(err3);
+ });
+ }
+ });
+ });
+ }
+ function createFileSync(file) {
+ let stats;
+ try {
+ stats = fs.statSync(file);
+ } catch {
+ }
+ if (stats && stats.isFile())
+ return;
+ const dir = path.dirname(file);
+ try {
+ if (!fs.statSync(dir).isDirectory()) {
+ fs.readdirSync(dir);
+ }
+ } catch (err) {
+ if (err && err.code === "ENOENT")
+ mkdir.mkdirsSync(dir);
+ else
+ throw err;
+ }
+ fs.writeFileSync(file, "");
+ }
+ module2.exports = {
+ createFile: u(createFile),
+ createFileSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/ensure/link.js
+var require_link = __commonJS({
+ "node_modules/fs-extra/lib/ensure/link.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromCallback;
+ var path = require("path");
+ var fs = require_graceful_fs();
+ var mkdir = require_mkdirs();
+ var pathExists = require_path_exists().pathExists;
+ var { areIdentical } = require_stat();
+ function createLink(srcpath, dstpath, callback) {
+ function makeLink(srcpath2, dstpath2) {
+ fs.link(srcpath2, dstpath2, (err) => {
+ if (err)
+ return callback(err);
+ callback(null);
+ });
+ }
+ fs.lstat(dstpath, (_, dstStat) => {
+ fs.lstat(srcpath, (err, srcStat) => {
+ if (err) {
+ err.message = err.message.replace("lstat", "ensureLink");
+ return callback(err);
+ }
+ if (dstStat && areIdentical(srcStat, dstStat))
+ return callback(null);
+ const dir = path.dirname(dstpath);
+ pathExists(dir, (err2, dirExists) => {
+ if (err2)
+ return callback(err2);
+ if (dirExists)
+ return makeLink(srcpath, dstpath);
+ mkdir.mkdirs(dir, (err3) => {
+ if (err3)
+ return callback(err3);
+ makeLink(srcpath, dstpath);
+ });
+ });
+ });
+ });
+ }
+ function createLinkSync(srcpath, dstpath) {
+ let dstStat;
+ try {
+ dstStat = fs.lstatSync(dstpath);
+ } catch {
+ }
+ try {
+ const srcStat = fs.lstatSync(srcpath);
+ if (dstStat && areIdentical(srcStat, dstStat))
+ return;
+ } catch (err) {
+ err.message = err.message.replace("lstat", "ensureLink");
+ throw err;
+ }
+ const dir = path.dirname(dstpath);
+ const dirExists = fs.existsSync(dir);
+ if (dirExists)
+ return fs.linkSync(srcpath, dstpath);
+ mkdir.mkdirsSync(dir);
+ return fs.linkSync(srcpath, dstpath);
+ }
+ module2.exports = {
+ createLink: u(createLink),
+ createLinkSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/ensure/symlink-paths.js
+var require_symlink_paths = __commonJS({
+ "node_modules/fs-extra/lib/ensure/symlink-paths.js"(exports, module2) {
+ "use strict";
+ var path = require("path");
+ var fs = require_graceful_fs();
+ var pathExists = require_path_exists().pathExists;
+ function symlinkPaths(srcpath, dstpath, callback) {
+ if (path.isAbsolute(srcpath)) {
+ return fs.lstat(srcpath, (err) => {
+ if (err) {
+ err.message = err.message.replace("lstat", "ensureSymlink");
+ return callback(err);
+ }
+ return callback(null, {
+ toCwd: srcpath,
+ toDst: srcpath
+ });
+ });
+ } else {
+ const dstdir = path.dirname(dstpath);
+ const relativeToDst = path.join(dstdir, srcpath);
+ return pathExists(relativeToDst, (err, exists) => {
+ if (err)
+ return callback(err);
+ if (exists) {
+ return callback(null, {
+ toCwd: relativeToDst,
+ toDst: srcpath
+ });
+ } else {
+ return fs.lstat(srcpath, (err2) => {
+ if (err2) {
+ err2.message = err2.message.replace("lstat", "ensureSymlink");
+ return callback(err2);
+ }
+ return callback(null, {
+ toCwd: srcpath,
+ toDst: path.relative(dstdir, srcpath)
+ });
+ });
+ }
+ });
+ }
+ }
+ function symlinkPathsSync(srcpath, dstpath) {
+ let exists;
+ if (path.isAbsolute(srcpath)) {
+ exists = fs.existsSync(srcpath);
+ if (!exists)
+ throw new Error("absolute srcpath does not exist");
+ return {
+ toCwd: srcpath,
+ toDst: srcpath
+ };
+ } else {
+ const dstdir = path.dirname(dstpath);
+ const relativeToDst = path.join(dstdir, srcpath);
+ exists = fs.existsSync(relativeToDst);
+ if (exists) {
+ return {
+ toCwd: relativeToDst,
+ toDst: srcpath
+ };
+ } else {
+ exists = fs.existsSync(srcpath);
+ if (!exists)
+ throw new Error("relative srcpath does not exist");
+ return {
+ toCwd: srcpath,
+ toDst: path.relative(dstdir, srcpath)
+ };
+ }
+ }
+ }
+ module2.exports = {
+ symlinkPaths,
+ symlinkPathsSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/ensure/symlink-type.js
+var require_symlink_type = __commonJS({
+ "node_modules/fs-extra/lib/ensure/symlink-type.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ function symlinkType(srcpath, type, callback) {
+ callback = typeof type === "function" ? type : callback;
+ type = typeof type === "function" ? false : type;
+ if (type)
+ return callback(null, type);
+ fs.lstat(srcpath, (err, stats) => {
+ if (err)
+ return callback(null, "file");
+ type = stats && stats.isDirectory() ? "dir" : "file";
+ callback(null, type);
+ });
+ }
+ function symlinkTypeSync(srcpath, type) {
+ let stats;
+ if (type)
+ return type;
+ try {
+ stats = fs.lstatSync(srcpath);
+ } catch {
+ return "file";
+ }
+ return stats && stats.isDirectory() ? "dir" : "file";
+ }
+ module2.exports = {
+ symlinkType,
+ symlinkTypeSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/ensure/symlink.js
+var require_symlink = __commonJS({
+ "node_modules/fs-extra/lib/ensure/symlink.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromCallback;
+ var path = require("path");
+ var fs = require_fs();
+ var _mkdirs = require_mkdirs();
+ var mkdirs = _mkdirs.mkdirs;
+ var mkdirsSync = _mkdirs.mkdirsSync;
+ var _symlinkPaths = require_symlink_paths();
+ var symlinkPaths = _symlinkPaths.symlinkPaths;
+ var symlinkPathsSync = _symlinkPaths.symlinkPathsSync;
+ var _symlinkType = require_symlink_type();
+ var symlinkType = _symlinkType.symlinkType;
+ var symlinkTypeSync = _symlinkType.symlinkTypeSync;
+ var pathExists = require_path_exists().pathExists;
+ var { areIdentical } = require_stat();
+ function createSymlink(srcpath, dstpath, type, callback) {
+ callback = typeof type === "function" ? type : callback;
+ type = typeof type === "function" ? false : type;
+ fs.lstat(dstpath, (err, stats) => {
+ if (!err && stats.isSymbolicLink()) {
+ Promise.all([
+ fs.stat(srcpath),
+ fs.stat(dstpath)
+ ]).then(([srcStat, dstStat]) => {
+ if (areIdentical(srcStat, dstStat))
+ return callback(null);
+ _createSymlink(srcpath, dstpath, type, callback);
+ });
+ } else
+ _createSymlink(srcpath, dstpath, type, callback);
+ });
+ }
+ function _createSymlink(srcpath, dstpath, type, callback) {
+ symlinkPaths(srcpath, dstpath, (err, relative2) => {
+ if (err)
+ return callback(err);
+ srcpath = relative2.toDst;
+ symlinkType(relative2.toCwd, type, (err2, type2) => {
+ if (err2)
+ return callback(err2);
+ const dir = path.dirname(dstpath);
+ pathExists(dir, (err3, dirExists) => {
+ if (err3)
+ return callback(err3);
+ if (dirExists)
+ return fs.symlink(srcpath, dstpath, type2, callback);
+ mkdirs(dir, (err4) => {
+ if (err4)
+ return callback(err4);
+ fs.symlink(srcpath, dstpath, type2, callback);
+ });
+ });
+ });
+ });
+ }
+ function createSymlinkSync(srcpath, dstpath, type) {
+ let stats;
+ try {
+ stats = fs.lstatSync(dstpath);
+ } catch {
+ }
+ if (stats && stats.isSymbolicLink()) {
+ const srcStat = fs.statSync(srcpath);
+ const dstStat = fs.statSync(dstpath);
+ if (areIdentical(srcStat, dstStat))
+ return;
+ }
+ const relative2 = symlinkPathsSync(srcpath, dstpath);
+ srcpath = relative2.toDst;
+ type = symlinkTypeSync(relative2.toCwd, type);
+ const dir = path.dirname(dstpath);
+ const exists = fs.existsSync(dir);
+ if (exists)
+ return fs.symlinkSync(srcpath, dstpath, type);
+ mkdirsSync(dir);
+ return fs.symlinkSync(srcpath, dstpath, type);
+ }
+ module2.exports = {
+ createSymlink: u(createSymlink),
+ createSymlinkSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/ensure/index.js
+var require_ensure = __commonJS({
+ "node_modules/fs-extra/lib/ensure/index.js"(exports, module2) {
+ "use strict";
+ var file = require_file();
+ var link = require_link();
+ var symlink = require_symlink();
+ module2.exports = {
+ createFile: file.createFile,
+ createFileSync: file.createFileSync,
+ ensureFile: file.createFile,
+ ensureFileSync: file.createFileSync,
+ createLink: link.createLink,
+ createLinkSync: link.createLinkSync,
+ ensureLink: link.createLink,
+ ensureLinkSync: link.createLinkSync,
+ createSymlink: symlink.createSymlink,
+ createSymlinkSync: symlink.createSymlinkSync,
+ ensureSymlink: symlink.createSymlink,
+ ensureSymlinkSync: symlink.createSymlinkSync
+ };
+ }
+});
+
+// node_modules/jsonfile/utils.js
+var require_utils2 = __commonJS({
+ "node_modules/jsonfile/utils.js"(exports, module2) {
+ function stringify(obj, { EOL = "\n", finalEOL = true, replacer = null, spaces } = {}) {
+ const EOF = finalEOL ? EOL : "";
+ const str = JSON.stringify(obj, replacer, spaces);
+ return str.replace(/\n/g, EOL) + EOF;
+ }
+ function stripBom(content) {
+ if (Buffer.isBuffer(content))
+ content = content.toString("utf8");
+ return content.replace(/^\uFEFF/, "");
+ }
+ module2.exports = { stringify, stripBom };
+ }
+});
+
+// node_modules/jsonfile/index.js
+var require_jsonfile = __commonJS({
+ "node_modules/jsonfile/index.js"(exports, module2) {
+ var _fs;
+ try {
+ _fs = require_graceful_fs();
+ } catch (_) {
+ _fs = require("fs");
+ }
+ var universalify = require_universalify();
+ var { stringify, stripBom } = require_utils2();
+ async function _readFile(file, options = {}) {
+ if (typeof options === "string") {
+ options = { encoding: options };
+ }
+ const fs = options.fs || _fs;
+ const shouldThrow = "throws" in options ? options.throws : true;
+ let data = await universalify.fromCallback(fs.readFile)(file, options);
+ data = stripBom(data);
+ let obj;
+ try {
+ obj = JSON.parse(data, options ? options.reviver : null);
+ } catch (err) {
+ if (shouldThrow) {
+ err.message = `${file}: ${err.message}`;
+ throw err;
+ } else {
+ return null;
+ }
+ }
+ return obj;
+ }
+ var readFile = universalify.fromPromise(_readFile);
+ function readFileSync6(file, options = {}) {
+ if (typeof options === "string") {
+ options = { encoding: options };
+ }
+ const fs = options.fs || _fs;
+ const shouldThrow = "throws" in options ? options.throws : true;
+ try {
+ let content = fs.readFileSync(file, options);
+ content = stripBom(content);
+ return JSON.parse(content, options.reviver);
+ } catch (err) {
+ if (shouldThrow) {
+ err.message = `${file}: ${err.message}`;
+ throw err;
+ } else {
+ return null;
+ }
+ }
+ }
+ async function _writeFile(file, obj, options = {}) {
+ const fs = options.fs || _fs;
+ const str = stringify(obj, options);
+ await universalify.fromCallback(fs.writeFile)(file, str, options);
+ }
+ var writeFile2 = universalify.fromPromise(_writeFile);
+ function writeFileSync3(file, obj, options = {}) {
+ const fs = options.fs || _fs;
+ const str = stringify(obj, options);
+ return fs.writeFileSync(file, str, options);
+ }
+ var jsonfile = {
+ readFile,
+ readFileSync: readFileSync6,
+ writeFile: writeFile2,
+ writeFileSync: writeFileSync3
+ };
+ module2.exports = jsonfile;
+ }
+});
+
+// node_modules/fs-extra/lib/json/jsonfile.js
+var require_jsonfile2 = __commonJS({
+ "node_modules/fs-extra/lib/json/jsonfile.js"(exports, module2) {
+ "use strict";
+ var jsonFile = require_jsonfile();
+ module2.exports = {
+ readJson: jsonFile.readFile,
+ readJsonSync: jsonFile.readFileSync,
+ writeJson: jsonFile.writeFile,
+ writeJsonSync: jsonFile.writeFileSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/output/index.js
+var require_output = __commonJS({
+ "node_modules/fs-extra/lib/output/index.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromCallback;
+ var fs = require_graceful_fs();
+ var path = require("path");
+ var mkdir = require_mkdirs();
+ var pathExists = require_path_exists().pathExists;
+ function outputFile(file, data, encoding, callback) {
+ if (typeof encoding === "function") {
+ callback = encoding;
+ encoding = "utf8";
+ }
+ const dir = path.dirname(file);
+ pathExists(dir, (err, itDoes) => {
+ if (err)
+ return callback(err);
+ if (itDoes)
+ return fs.writeFile(file, data, encoding, callback);
+ mkdir.mkdirs(dir, (err2) => {
+ if (err2)
+ return callback(err2);
+ fs.writeFile(file, data, encoding, callback);
+ });
+ });
+ }
+ function outputFileSync(file, ...args) {
+ const dir = path.dirname(file);
+ if (fs.existsSync(dir)) {
+ return fs.writeFileSync(file, ...args);
+ }
+ mkdir.mkdirsSync(dir);
+ fs.writeFileSync(file, ...args);
+ }
+ module2.exports = {
+ outputFile: u(outputFile),
+ outputFileSync
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/json/output-json.js
+var require_output_json = __commonJS({
+ "node_modules/fs-extra/lib/json/output-json.js"(exports, module2) {
+ "use strict";
+ var { stringify } = require_utils2();
+ var { outputFile } = require_output();
+ async function outputJson(file, data, options = {}) {
+ const str = stringify(data, options);
+ await outputFile(file, str, options);
+ }
+ module2.exports = outputJson;
+ }
+});
+
+// node_modules/fs-extra/lib/json/output-json-sync.js
+var require_output_json_sync = __commonJS({
+ "node_modules/fs-extra/lib/json/output-json-sync.js"(exports, module2) {
+ "use strict";
+ var { stringify } = require_utils2();
+ var { outputFileSync } = require_output();
+ function outputJsonSync(file, data, options) {
+ const str = stringify(data, options);
+ outputFileSync(file, str, options);
+ }
+ module2.exports = outputJsonSync;
+ }
+});
+
+// node_modules/fs-extra/lib/json/index.js
+var require_json = __commonJS({
+ "node_modules/fs-extra/lib/json/index.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromPromise;
+ var jsonFile = require_jsonfile2();
+ jsonFile.outputJson = u(require_output_json());
+ jsonFile.outputJsonSync = require_output_json_sync();
+ jsonFile.outputJSON = jsonFile.outputJson;
+ jsonFile.outputJSONSync = jsonFile.outputJsonSync;
+ jsonFile.writeJSON = jsonFile.writeJson;
+ jsonFile.writeJSONSync = jsonFile.writeJsonSync;
+ jsonFile.readJSON = jsonFile.readJson;
+ jsonFile.readJSONSync = jsonFile.readJsonSync;
+ module2.exports = jsonFile;
+ }
+});
+
+// node_modules/fs-extra/lib/move-sync/move-sync.js
+var require_move_sync = __commonJS({
+ "node_modules/fs-extra/lib/move-sync/move-sync.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ var path = require("path");
+ var copySync2 = require_copy_sync2().copySync;
+ var removeSync = require_remove().removeSync;
+ var mkdirpSync = require_mkdirs().mkdirpSync;
+ var stat = require_stat();
+ function moveSync(src, dest, opts) {
+ opts = opts || {};
+ const overwrite = opts.overwrite || opts.clobber || false;
+ const { srcStat, isChangingCase = false } = stat.checkPathsSync(src, dest, "move", opts);
+ stat.checkParentPathsSync(src, srcStat, dest, "move");
+ if (!isParentRoot(dest))
+ mkdirpSync(path.dirname(dest));
+ return doRename(src, dest, overwrite, isChangingCase);
+ }
+ function isParentRoot(dest) {
+ const parent = path.dirname(dest);
+ const parsedPath = path.parse(parent);
+ return parsedPath.root === parent;
+ }
+ function doRename(src, dest, overwrite, isChangingCase) {
+ if (isChangingCase)
+ return rename(src, dest, overwrite);
+ if (overwrite) {
+ removeSync(dest);
+ return rename(src, dest, overwrite);
+ }
+ if (fs.existsSync(dest))
+ throw new Error("dest already exists.");
+ return rename(src, dest, overwrite);
+ }
+ function rename(src, dest, overwrite) {
+ try {
+ fs.renameSync(src, dest);
+ } catch (err) {
+ if (err.code !== "EXDEV")
+ throw err;
+ return moveAcrossDevice(src, dest, overwrite);
+ }
+ }
+ function moveAcrossDevice(src, dest, overwrite) {
+ const opts = {
+ overwrite,
+ errorOnExist: true
+ };
+ copySync2(src, dest, opts);
+ return removeSync(src);
+ }
+ module2.exports = moveSync;
+ }
+});
+
+// node_modules/fs-extra/lib/move-sync/index.js
+var require_move_sync2 = __commonJS({
+ "node_modules/fs-extra/lib/move-sync/index.js"(exports, module2) {
+ "use strict";
+ module2.exports = {
+ moveSync: require_move_sync()
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/move/move.js
+var require_move = __commonJS({
+ "node_modules/fs-extra/lib/move/move.js"(exports, module2) {
+ "use strict";
+ var fs = require_graceful_fs();
+ var path = require("path");
+ var copy = require_copy2().copy;
+ var remove = require_remove().remove;
+ var mkdirp = require_mkdirs().mkdirp;
+ var pathExists = require_path_exists().pathExists;
+ var stat = require_stat();
+ function move(src, dest, opts, cb) {
+ if (typeof opts === "function") {
+ cb = opts;
+ opts = {};
+ }
+ const overwrite = opts.overwrite || opts.clobber || false;
+ stat.checkPaths(src, dest, "move", opts, (err, stats) => {
+ if (err)
+ return cb(err);
+ const { srcStat, isChangingCase = false } = stats;
+ stat.checkParentPaths(src, srcStat, dest, "move", (err2) => {
+ if (err2)
+ return cb(err2);
+ if (isParentRoot(dest))
+ return doRename(src, dest, overwrite, isChangingCase, cb);
+ mkdirp(path.dirname(dest), (err3) => {
+ if (err3)
+ return cb(err3);
+ return doRename(src, dest, overwrite, isChangingCase, cb);
+ });
+ });
+ });
+ }
+ function isParentRoot(dest) {
+ const parent = path.dirname(dest);
+ const parsedPath = path.parse(parent);
+ return parsedPath.root === parent;
+ }
+ function doRename(src, dest, overwrite, isChangingCase, cb) {
+ if (isChangingCase)
+ return rename(src, dest, overwrite, cb);
+ if (overwrite) {
+ return remove(dest, (err) => {
+ if (err)
+ return cb(err);
+ return rename(src, dest, overwrite, cb);
+ });
+ }
+ pathExists(dest, (err, destExists) => {
+ if (err)
+ return cb(err);
+ if (destExists)
+ return cb(new Error("dest already exists."));
+ return rename(src, dest, overwrite, cb);
+ });
+ }
+ function rename(src, dest, overwrite, cb) {
+ fs.rename(src, dest, (err) => {
+ if (!err)
+ return cb();
+ if (err.code !== "EXDEV")
+ return cb(err);
+ return moveAcrossDevice(src, dest, overwrite, cb);
+ });
+ }
+ function moveAcrossDevice(src, dest, overwrite, cb) {
+ const opts = {
+ overwrite,
+ errorOnExist: true
+ };
+ copy(src, dest, opts, (err) => {
+ if (err)
+ return cb(err);
+ return remove(src, cb);
+ });
+ }
+ module2.exports = move;
+ }
+});
+
+// node_modules/fs-extra/lib/move/index.js
+var require_move2 = __commonJS({
+ "node_modules/fs-extra/lib/move/index.js"(exports, module2) {
+ "use strict";
+ var u = require_universalify().fromCallback;
+ module2.exports = {
+ move: u(require_move())
+ };
+ }
+});
+
+// node_modules/fs-extra/lib/index.js
+var require_lib = __commonJS({
+ "node_modules/fs-extra/lib/index.js"(exports, module2) {
+ "use strict";
+ module2.exports = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, require_fs()), require_copy_sync2()), require_copy2()), require_empty()), require_ensure()), require_json()), require_mkdirs()), require_move_sync2()), require_move2()), require_output()), require_path_exists()), require_remove());
+ }
+});
+
// node_modules/yargs/lib/platform-shims/esm.mjs
var import_assert = require("assert");
@@ -3882,8 +6453,8 @@ var GlobalMiddleware = class {
this.frozens = [];
this.yargs = yargs;
}
- addMiddleware(callback, applyBeforeValidation, global = true, mutates = false) {
- argsert(" [boolean] [boolean] [boolean]", [callback, applyBeforeValidation, global], arguments.length);
+ addMiddleware(callback, applyBeforeValidation, global2 = true, mutates = false) {
+ argsert(" [boolean] [boolean] [boolean]", [callback, applyBeforeValidation, global2], arguments.length);
if (Array.isArray(callback)) {
for (let i = 0; i < callback.length; i++) {
if (typeof callback[i] !== "function") {
@@ -3891,13 +6462,13 @@ var GlobalMiddleware = class {
}
const m = callback[i];
m.applyBeforeValidation = applyBeforeValidation;
- m.global = global;
+ m.global = global2;
}
Array.prototype.push.apply(this.globalMiddleware, callback);
} else if (typeof callback === "function") {
const m = callback;
m.applyBeforeValidation = applyBeforeValidation;
- m.global = global;
+ m.global = global2;
m.mutates = mutates;
this.globalMiddleware.push(callback);
}
@@ -5673,8 +8244,8 @@ var YargsInstance = class {
this[kTrackManuallySetKeys](keys);
return this;
}
- check(f, global) {
- argsert(" [boolean]", [f, global], arguments.length);
+ check(f, global2) {
+ argsert(" [boolean]", [f, global2], arguments.length);
this.middleware((argv, _yargs) => {
return maybeAsyncResult(() => {
return f(argv, _yargs.getOptions());
@@ -5689,7 +8260,7 @@ var YargsInstance = class {
__classPrivateFieldGet(this, _YargsInstance_usage, "f").fail(err.message ? err.message : err.toString(), err);
return argv;
});
- }, false, global);
+ }, false, global2);
return this;
}
choices(key, value) {
@@ -5990,10 +8561,10 @@ var YargsInstance = class {
getStrictOptions() {
return __classPrivateFieldGet(this, _YargsInstance_strictOptions, "f");
}
- global(globals, global) {
- argsert(" [boolean]", [globals, global], arguments.length);
+ global(globals, global2) {
+ argsert(" [boolean]", [globals, global2], arguments.length);
globals = [].concat(globals);
- if (global !== false) {
+ if (global2 !== false) {
__classPrivateFieldGet(this, _YargsInstance_options, "f").local = __classPrivateFieldGet(this, _YargsInstance_options, "f").local.filter((l) => globals.indexOf(l) === -1);
} else {
globals.forEach((g) => {
@@ -6037,8 +8608,8 @@ var YargsInstance = class {
__classPrivateFieldGet(this, _YargsInstance_shim, "f").y18n.setLocale(locale);
return this;
}
- middleware(callback, applyBeforeValidation, global) {
- return __classPrivateFieldGet(this, _YargsInstance_globalMiddleware, "f").addMiddleware(callback, !!applyBeforeValidation, global);
+ middleware(callback, applyBeforeValidation, global2) {
+ return __classPrivateFieldGet(this, _YargsInstance_globalMiddleware, "f").addMiddleware(callback, !!applyBeforeValidation, global2);
}
nargs(key, value) {
argsert(" [number]", [key, value], arguments.length);
@@ -6987,7 +9558,7 @@ var matcher = [
regexMatcher(/^\/\/.+/, "comment"),
regexMatcher(/^#.+/, "comment"),
regexMatcher(/^".*?"/, "string"),
- regexMatcher(/^(type|enum|import|service)\b/, "keyword"),
+ regexMatcher(/^(type|enum|import|service|define)\b/, "keyword"),
regexMatcher(/^\@/, "at"),
regexMatcher(/^\:/, "colon"),
regexMatcher(/^\;/, "semicolon"),
@@ -7257,6 +9828,18 @@ function parse(tokens, file) {
location: { file, idx }
};
};
+ const parseDefine = () => {
+ const idx = eatToken("define");
+ let [key] = eatText();
+ let [value] = eatText();
+ eatToken(";");
+ return {
+ type: "define",
+ location: { file, idx },
+ key,
+ value
+ };
+ };
const parseStatement = () => {
if (currentToken.type === "keyword") {
switch (currentToken.value) {
@@ -7268,6 +9851,8 @@ function parse(tokens, file) {
return parseEnumStatement();
case "service":
return parseServiceStatement();
+ case "define":
+ return parseDefine();
default:
throw new ParserError(`Unknown keyword ${currentToken.value}`, currentToken);
}
@@ -7298,6 +9883,7 @@ function get_ir(parsed) {
let types = [];
let enums = [];
let steps = [];
+ let options = {};
parsed.forEach((statement) => {
log("Working on statement of type %s", statement.type);
if (statement.type == "import")
@@ -7451,19 +10037,26 @@ function get_ir(parsed) {
functions
}
]);
+ } else if (statement.type == "define") {
+ options[statement.key] = statement.value;
} else {
throw new IRError(statement, "Invalid statement!");
}
});
- return steps;
+ return {
+ options,
+ steps
+ };
}
// src/compile.ts
var FS = __toESM(require("fs"));
+var FSE = __toESM(require_lib());
var Path = __toESM(require("path"));
var CompileTarget = class {
- constructor(outputFolder) {
+ constructor(outputFolder, options) {
this.outputFolder = outputFolder;
+ this.options = options;
if (!FS.existsSync(outputFolder)) {
FS.mkdirSync(outputFolder, {
recursive: true
@@ -7494,10 +10087,14 @@ var CompileTarget = class {
}
return res.join("\n");
}
+ loadTemplateFolder(name) {
+ let root = Path.join(__dirname, "../templates/", name);
+ FSE.copySync(root, this.outputFolder, {});
+ }
};
function compile(ir, target) {
target.start();
- ir.forEach((step) => {
+ ir.steps.forEach((step) => {
const [type, def] = step;
if (type == "type")
target.generateType(def);
@@ -7507,7 +10104,7 @@ function compile(ir, target) {
target.generateService(def);
});
if (target.finalize)
- target.finalize(ir);
+ target.finalize(ir.steps);
}
// src/targets/typescript.ts
@@ -7580,7 +10177,7 @@ var TypescriptTarget = class extends CompileTarget {
a(0, `export function apply_${def.name}(data: ${def.name}): ${def.name} {`);
{
a(1, `if(typeof data !== "object") throw new VerificationError("${def.name}", undefined, data);`);
- a(1, `let res = {} as any;`);
+ a(1, `let res = new ${def.name}() as any;`);
def.fields.forEach((field) => {
a(1, `if(data["${field.name}"] !== null && data["${field.name}"] !== undefined) {`);
if (field.array) {
@@ -7652,6 +10249,7 @@ var TypescriptTarget = class extends CompileTarget {
const params = fnc.inputs.map((e) => `${e.name}: ${toJSType(e.type) + (e.array ? "[]" : "")}`).join(", ");
if (!fnc.return) {
a(1, `${fnc.name}(${params}): void {`);
+ 1;
a(2, `this._provider.sendMessage({`);
a(3, `jsonrpc: "2.0",`);
a(3, `method: "${def.name}.${fnc.name}",`);
@@ -7672,11 +10270,11 @@ var TypescriptTarget = class extends CompileTarget {
a(3, `});`);
a(2, `}).then(result => {`);
if (fnc.return.array) {
- a(2, `for(const elm of result) {`);
- a(3, `apply_${fnc.return.type}(elm);`);
- a(2, `}`);
+ a(3, `for(let i = 0; i < result.length; i++) {`);
+ a(4, `result[i] = apply_${fnc.return.type}(result[i]);`);
+ a(3, `}`);
} else {
- a(3, `apply_${fnc.return.type}(result);`);
+ a(3, `result = apply_${fnc.return.type}(result);`);
}
a(3, `return result;`);
a(2, `});`);
@@ -7826,6 +10424,225 @@ var NodeJSTypescriptTarget = class extends TypescriptTarget {
flavour = "node";
};
+// src/targets/csharp.ts
+var conversion2 = {
+ boolean: "bool",
+ number: "double",
+ string: "string",
+ void: "void"
+};
+function toCSharpType(type) {
+ return conversion2[type] || type;
+}
+var CSharpTarget = class extends CompileTarget {
+ name = "c#";
+ get namespace() {
+ return this.options.CSharp_Namespace || "JRPC";
+ }
+ start() {
+ this.writeFile(this.namespace + ".csproj", this.getTemplate("CSharp/CSharp.csproj"));
+ const fixNS = (input) => input.replace("__NAMESPACE__", this.namespace);
+ const copyClass = (name) => this.writeFile(name + ".cs", fixNS(this.getTemplate(`CSharp/${name}.cs`)));
+ copyClass("JRpcClient");
+ copyClass("JRpcServer");
+ copyClass("JRpcTransport");
+ }
+ generateType(definition) {
+ let lines = [];
+ const a = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, `using System.Collections.Generic;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(0, `public class ${definition.name} {`);
+ for (const field of definition.fields) {
+ if (field.array) {
+ a(1, `public IList<${toCSharpType(field.type)}>? ${field.name} { get; set; }`);
+ } else if (field.map) {
+ a(1, `public Dictionary<${toCSharpType(field.map)}, ${toCSharpType(field.type)}>? ${field.name} { get; set; }`);
+ } else {
+ a(1, `public ${toCSharpType(field.type)}? ${field.name} { get; set; }`);
+ }
+ }
+ a(0, `}`);
+ this.writeFile(`${definition.name}.cs`, lines.join("\n"));
+ }
+ generateEnum(definition) {
+ let lines = [];
+ const a = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(0, `public enum ${definition.name} {`);
+ for (const field of definition.values) {
+ a(1, `${field.name} = ${field.value},`);
+ }
+ a(0, `}`);
+ this.writeFile(`${definition.name}.cs`, lines.join("\n"));
+ }
+ generateServiceClient(definition) {
+ let lines = [];
+ const a = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, `using System.Text.Json.Nodes;`);
+ a(0, `using System.Threading.Tasks;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(0, `public class ${definition.name}Client {`);
+ a(0, ``);
+ a(1, `private JRpcClient Client;`);
+ a(0, ``);
+ a(1, `public ${definition.name}Client(JRpcClient client) {`);
+ a(2, `this.Client = client;`);
+ a(1, `}`);
+ a(0, ``);
+ for (const fnc of definition.functions) {
+ let params = fnc.inputs.map((inp) => {
+ if (inp.array) {
+ return `List<${toCSharpType(inp.type)}> ${inp.name}`;
+ } else {
+ return `${toCSharpType(inp.type)} ${inp.name}`;
+ }
+ }).join(",");
+ const genParam = () => a(2, `var param = new JsonArray(${fnc.inputs.map((e) => `JsonSerializer.SerializeToNode(${e.name})`).join(",")});`);
+ if (fnc.return) {
+ if (fnc.return.type == "void") {
+ a(1, `public async Task ${fnc.name}(${params}) {`);
+ genParam();
+ a(2, `await this.Client.SendRequestRaw("${definition.name}.${fnc.name}", param);`);
+ a(1, `}`);
+ } else {
+ let ret = fnc.return ? fnc.return.array ? `IList<${toCSharpType(fnc.return.type)}>` : toCSharpType(fnc.return.type) : void 0;
+ a(1, `public async Task<${ret}> ${fnc.name}(${params}) {`);
+ genParam();
+ a(2, `return await this.Client.SendRequest<${ret}>("${definition.name}.${fnc.name}", param);`);
+ a(1, `}`);
+ }
+ } else {
+ a(1, `public void ${fnc.name}(${params}) {`);
+ genParam();
+ a(2, `this.Client.SendNotification("${definition.name}.${fnc.name}", param);`);
+ a(1, `}`);
+ }
+ a(1, ``);
+ }
+ a(0, `}`);
+ this.writeFile(`${definition.name}Client.cs`, lines.join("\n"));
+ }
+ generateServiceServer(definition) {
+ let lines = [];
+ const a = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, `using System.Text.Json.Nodes;`);
+ a(0, `using System.Threading.Tasks;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(0, `public abstract class ${definition.name}Server : JRpcService {`);
+ a(0, ``);
+ a(1, `public ${definition.name}Server(JRpcClient client) {`);
+ for (const fnc of definition.functions) {
+ a(2, `this.RegisterFunction("${fnc.name}");`);
+ }
+ a(1, `}`);
+ a(0, ``);
+ for (const fnc of definition.functions) {
+ let params = [
+ fnc.inputs.map((inp) => {
+ if (inp.array) {
+ return `List<${toCSharpType(inp.type)}> ${inp.name}`;
+ } else {
+ return `${toCSharpType(inp.type)} ${inp.name}`;
+ }
+ }),
+ "TContext ctx"
+ ].join(",");
+ if (fnc.return) {
+ if (fnc.return.type == "void") {
+ a(1, `public abstract Task ${fnc.name}(${params});`);
+ } else {
+ let ret = fnc.return ? fnc.return.array ? `IList<${toCSharpType(fnc.return.type)}>` : toCSharpType(fnc.return.type) : void 0;
+ a(1, `public abstract Task<${ret}> ${fnc.name}(${params});`);
+ }
+ } else {
+ a(1, `public abstract void ${fnc.name}(${params});`);
+ }
+ }
+ a(0, ``);
+ a(1, `public async override Task HandleRequest(string func, JsonNode param, TContext context) {`);
+ a(2, `switch(func) {`);
+ for (const fnc of definition.functions) {
+ a(3, `case "${fnc.name}": {`);
+ a(4, `if(param is JsonObject) {`);
+ a(5, `var ja = new JsonArray(${fnc.inputs.map((inp) => {
+ return `param["${inp.name}"]`;
+ }).join(", ")});`);
+ a(5, `param = ja;`);
+ a(4, `}`);
+ let pref = "";
+ if (fnc.return) {
+ if (fnc.return.type != "void")
+ pref = "var result = await ";
+ else
+ pref = "await ";
+ }
+ a(4, pref + `this.${fnc.name}(${[
+ ...fnc.inputs.map((inp, idx) => {
+ let type = inp.array ? `List<${toCSharpType(inp.type)}>` : `${toCSharpType(inp.type)}`;
+ return `param[${idx}]!.Deserialize<${type}>()`;
+ }),
+ "context"
+ ].join(", ")});`);
+ if (fnc.return && fnc.return.type != "void") {
+ a(4, `return JsonSerializer.SerializeToNode(result);`);
+ } else {
+ a(4, `return null;`);
+ }
+ a(3, `}`);
+ a(0, ``);
+ }
+ a(3, `default:`);
+ a(4, `throw new Exception("Invalid Method!");`);
+ a(2, `}`);
+ a(1, `}`);
+ a(0, `}`);
+ this.writeFile(`${definition.name}Server.cs`, lines.join("\n"));
+ }
+ generateService(definition) {
+ this.generateServiceClient(definition);
+ this.generateServiceServer(definition);
+ }
+ finalize(steps) {
+ }
+};
+
// src/process.ts
var CatchedError = class extends Error {
};
@@ -7833,6 +10650,7 @@ var log2 = (0, import_debug2.default)("app");
var Targets = /* @__PURE__ */ new Map();
Targets.set("ts-esm", ESMTypescriptTarget);
Targets.set("ts-node", NodeJSTypescriptTarget);
+Targets.set("c#", CSharpTarget);
function indexToLineAndCol(src, index) {
let line = 1;
let col = 1;
@@ -7952,7 +10770,7 @@ function startCompile(options) {
console.log(import_chalk.default.red("ERROR:"), "Target not supported!");
return;
}
- compile(ir, new tg(target.output));
+ compile(ir, new tg(target.output, ir.options));
});
}
diff --git a/package.json b/package.json
index b77968e..c613765 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,10 @@
"packageManager": "yarn@3.1.1",
"scripts": {
"start": "ts-node src/index.ts",
- "test": "npm run start -- compile examples/example.jrpc --definition=examples/definition.json -o=ts-node:examples/out && ts-node examples/test.ts",
+ "test-start": "npm run start -- compile examples/example.jrpc --definition=examples/definition.json -o=ts-node:examples/Typescript/out -o=c#:examples/CSharp/Generated",
+ "test-csharp": "cd examples/CSharp/Example/ && dotnet run",
+ "test-typescript": "ts-node examples/test.ts",
+ "test": "npm run test-start && npm run test-csharp && npm run test-typescript",
"build": "esbuild src/index.ts --bundle --platform=node --target=node14 --outfile=lib/jrpc.js",
"prepublishOnly": "npm run build"
},
@@ -22,6 +25,7 @@
],
"devDependencies": {
"@types/debug": "^4.1.7",
+ "@types/fs-extra": "^9.0.13",
"@types/node": "^17.0.5",
"@types/prettier": "^2.4.2",
"@types/yargs": "^17.0.8",
@@ -32,5 +36,8 @@
"ts-node": "^10.4.0",
"typescript": "^4.5.4",
"yargs": "^17.3.1"
+ },
+ "dependencies": {
+ "fs-extra": "^10.0.0"
}
}
diff --git a/src/compile.ts b/src/compile.ts
index 51ff9a0..2014e53 100644
--- a/src/compile.ts
+++ b/src/compile.ts
@@ -1,4 +1,5 @@
import * as FS from "fs";
+import * as FSE from "fs-extra"
import * as Path from "path";
import {
EnumDefinition,
@@ -8,9 +9,9 @@ import {
TypeDefinition,
} from "./ir";
-export abstract class CompileTarget {
+export abstract class CompileTarget {
abstract name: string;
- constructor(private outputFolder: string) {
+ constructor(private outputFolder: string, protected options: T) {
if (!FS.existsSync(outputFolder)) {
FS.mkdirSync(outputFolder, {
recursive: true,
@@ -57,6 +58,14 @@ export abstract class CompileTarget {
return res.join("\n");
}
+
+ protected loadTemplateFolder(name:string) {
+ let root = Path.join(__dirname, "../templates/", name);
+
+ FSE.copySync(root, this.outputFolder, {
+
+ });
+ }
}
export default function compile(ir: IR, target: CompileTarget) {
@@ -64,12 +73,12 @@ export default function compile(ir: IR, target: CompileTarget) {
// setState("Building for target: " + target.name);
target.start();
- ir.forEach((step) => {
+ ir.steps.forEach((step) => {
const [type, def] = step;
if (type == "type") target.generateType(def as TypeDefinition);
else if (type == "enum") target.generateEnum(def as EnumDefinition);
else if (type == "service")
target.generateService(def as ServiceDefinition);
});
- if (target.finalize) target.finalize(ir);
+ if (target.finalize) target.finalize(ir.steps);
}
diff --git a/src/ir.ts b/src/ir.ts
index 6a635b4..dc2d810 100644
--- a/src/ir.ts
+++ b/src/ir.ts
@@ -61,7 +61,10 @@ export type Step = [
TypeDefinition | EnumDefinition | ServiceDefinition
];
-export type IR = Step[];
+export type IR = {
+ options: { [key:string]: string},
+ steps: Step[]
+};
export default function get_ir(parsed: Parsed): IR {
log("Generatie IR from parse output");
@@ -72,6 +75,7 @@ export default function get_ir(parsed: Parsed): IR {
// Verifiy and generating steps
let steps: Step[] = [];
+ let options = {} as any;
parsed.forEach((statement) => {
log("Working on statement of type %s", statement.type);
@@ -276,10 +280,15 @@ export default function get_ir(parsed: Parsed): IR {
functions,
} as ServiceDefinition,
]);
+ } else if(statement.type == "define") {
+ options[statement.key] = statement.value;
} else {
throw new IRError(statement, "Invalid statement!");
}
});
- return steps;
+ return {
+ options,
+ steps
+ };
}
diff --git a/src/parser.ts b/src/parser.ts
index aed7546..618de89 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -67,11 +67,19 @@ export interface ServiceStatement extends DefinitionNode {
functions: ServiceFunctionStatement[];
}
+export interface DefineStatement extends DefinitionNode {
+ type: "define";
+ key: string;
+ value: string;
+}
+
export type RootStatementNode =
| ImportStatement
| TypeStatement
| ServiceStatement
- | EnumStatement;
+ | EnumStatement
+ | DefineStatement;
+
export type StatementNode =
| RootStatementNode
| TypeFieldStatement
@@ -414,6 +422,22 @@ export default function parse(tokens: Token[], file: string): Parsed {
};
};
+ const parseDefine = (): DefineStatement => {
+ const idx = eatToken("define");
+
+ let [key] = eatText()
+ let [value] = eatText()
+
+ eatToken(";");
+
+ return {
+ type :"define",
+ location: {file, idx},
+ key,
+ value
+ }
+ }
+
const parseStatement = () => {
if (currentToken.type === "keyword") {
switch (currentToken.value) {
@@ -427,6 +451,8 @@ export default function parse(tokens: Token[], file: string): Parsed {
return parseEnumStatement();
case "service":
return parseServiceStatement();
+ case "define":
+ return parseDefine();
default:
throw new ParserError(
`Unknown keyword ${currentToken.value}`,
diff --git a/src/process.ts b/src/process.ts
index ba2f25d..cfa9661 100644
--- a/src/process.ts
+++ b/src/process.ts
@@ -6,18 +6,21 @@ import tokenize, { TokenizerError } from "./tokenizer";
import parse, { Parsed, ParserError } from "./parser";
import get_ir, { IR, IRError } from "./ir";
import compile, { CompileTarget } from "./compile";
-import { ESMTypescriptTarget, NodeJSTypescriptTarget } from "./targets/typescript";
+import {
+ ESMTypescriptTarget,
+ NodeJSTypescriptTarget,
+} from "./targets/typescript";
+import { CSharpTarget } from "./targets/csharp";
class CatchedError extends Error {}
const log = dbg("app");
+const Targets = new Map();
-const Targets = new Map();
-
-Targets.set("ts-esm", ESMTypescriptTarget)
-Targets.set("ts-node", NodeJSTypescriptTarget)
-
+Targets.set("ts-esm", ESMTypescriptTarget);
+Targets.set("ts-node", NodeJSTypescriptTarget);
+Targets.set("c#", CSharpTarget as typeof CompileTarget);
function indexToLineAndCol(src: string, index: number) {
let line = 1;
@@ -77,7 +80,11 @@ type ProcessContext = {
processedFiles: Set;
};
-function processFile(ctx: ProcessContext, file: string, root = false): Parsed | null {
+function processFile(
+ ctx: ProcessContext,
+ file: string,
+ root = false
+): Parsed | null {
file = Path.resolve(file);
if (ctx.processedFiles.has(file)) {
log("Skipping file %s since it has already be processed", file);
@@ -99,7 +106,9 @@ function processFile(ctx: ProcessContext, file: string, root = false): Parsed |
.map((statement) => {
if (statement.type == "import") {
const base = Path.dirname(file);
- const resolved = Path.resolve(Path.join(base, statement.path + ".jrpc"));
+ const resolved = Path.resolve(
+ Path.join(base, statement.path + ".jrpc")
+ );
return processFile(ctx, resolved);
} else {
return statement;
@@ -111,16 +120,14 @@ function processFile(ctx: ProcessContext, file: string, root = false): Parsed |
} catch (err) {
if (err instanceof TokenizerError) {
printError(err, file, err.index);
- if(!root)
- throw new CatchedError();
+ if (!root) throw new CatchedError();
} else if (err instanceof ParserError) {
printError(err, file, err.token.startIdx);
- if(!root)
- throw new CatchedError();
- } else if(root && err instanceof CatchedError) {
+ if (!root) throw new CatchedError();
+ } else if (root && err instanceof CatchedError) {
return null;
} else {
- throw err;
+ throw err;
}
}
}
@@ -132,18 +139,21 @@ export default function startCompile(options: CompileOptions) {
} as ProcessContext;
let ir: IR | undefined = undefined;
- if(options.input.endsWith(".json")) {
+ if (options.input.endsWith(".json")) {
ir = JSON.parse(FS.readFileSync(options.input, "utf-8"));
} else {
const parsed = processFile(ctx, options.input, true);
- if(!parsed)
- process.exit(1); // Errors should have already been emitted
+ if (!parsed) process.exit(1); // Errors should have already been emitted
try {
- ir = get_ir(parsed);
- } catch(err) {
- if(err instanceof IRError) {
- printError(err, err.statement.location.file, err.statement.location.idx);
+ ir = get_ir(parsed);
+ } catch (err) {
+ if (err instanceof IRError) {
+ printError(
+ err,
+ err.statement.location.file,
+ err.statement.location.idx
+ );
process.exit(1);
} else {
throw err;
@@ -151,23 +161,25 @@ export default function startCompile(options: CompileOptions) {
}
}
- if(!ir)
- throw new Error("Error compiling: Cannot get IR");
+ if (!ir) throw new Error("Error compiling: Cannot get IR");
- if(options.emitDefinitions) {
- FS.writeFileSync(options.emitDefinitions, JSON.stringify(ir, undefined, 3));
+ if (options.emitDefinitions) {
+ FS.writeFileSync(
+ options.emitDefinitions,
+ JSON.stringify(ir, undefined, 3)
+ );
}
- if(options.targets.length <= 0) {
+ if (options.targets.length <= 0) {
console.log(Color.yellow("WARNING:"), "No targets selected!");
}
- options.targets.forEach(target => {
- const tg = Targets.get(target.type) as any
- if(!tg) {
+ options.targets.forEach((target) => {
+ const tg = Targets.get(target.type) as any;
+ if (!tg) {
console.log(Color.red("ERROR:"), "Target not supported!");
return;
}
- compile(ir, new tg(target.output));
- })
+ compile(ir, new tg(target.output, ir.options));
+ });
}
diff --git a/src/targets/csharp.ts b/src/targets/csharp.ts
new file mode 100644
index 0000000..a46ff0a
--- /dev/null
+++ b/src/targets/csharp.ts
@@ -0,0 +1,328 @@
+import {
+ TypeDefinition,
+ ServiceDefinition,
+ EnumDefinition,
+ TypeFieldDefinition,
+ Step,
+} from "../ir";
+
+import { CompileTarget } from "../compile";
+
+type lineAppender = (ind: number, line: string | string[]) => void;
+
+const conversion = {
+ boolean: "bool",
+ number: "double",
+ string: "string",
+ void: "void",
+};
+
+function toCSharpType(type: string): string {
+ return (conversion as any)[type] || type;
+}
+
+export class CSharpTarget extends CompileTarget<{ CSharp_Namespace: string }> {
+ name: string = "c#";
+
+ get namespace() {
+ return this.options.CSharp_Namespace || "JRPC";
+ }
+
+ start(): void {
+ this.writeFile(
+ this.namespace + ".csproj",
+ this.getTemplate("CSharp/CSharp.csproj")
+ );
+
+ const fixNS = (input: string) =>
+ input.replace("__NAMESPACE__", this.namespace);
+ const copyClass = (name: string) =>
+ this.writeFile(
+ name + ".cs",
+ fixNS(this.getTemplate(`CSharp/${name}.cs`))
+ );
+ copyClass("JRpcClient");
+ copyClass("JRpcServer");
+ copyClass("JRpcTransport");
+ }
+
+ generateType(definition: TypeDefinition): void {
+ let lines: string[] = [];
+ const a: lineAppender = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, `using System.Collections.Generic;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(0, `public class ${definition.name} {`);
+ for (const field of definition.fields) {
+ if (field.array) {
+ a(
+ 1,
+ `public IList<${toCSharpType(field.type)}>? ${
+ field.name
+ } { get; set; }`
+ );
+ } else if (field.map) {
+ a(
+ 1,
+ `public Dictionary<${toCSharpType(field.map)}, ${toCSharpType(
+ field.type
+ )}>? ${field.name} { get; set; }`
+ );
+ } else {
+ a(
+ 1,
+ `public ${toCSharpType(field.type)}? ${field.name} { get; set; }`
+ );
+ }
+ }
+ a(0, `}`);
+
+ this.writeFile(`${definition.name}.cs`, lines.join("\n"));
+ }
+
+ generateEnum(definition: EnumDefinition): void {
+ let lines: string[] = [];
+ const a: lineAppender = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(0, `public enum ${definition.name} {`);
+ for (const field of definition.values) {
+ a(1, `${field.name} = ${field.value},`);
+ }
+ a(0, `}`);
+
+ this.writeFile(`${definition.name}.cs`, lines.join("\n"));
+ }
+
+ generateServiceClient(definition: ServiceDefinition) {
+ let lines: string[] = [];
+ const a: lineAppender = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, `using System.Text.Json.Nodes;`);
+ a(0, `using System.Threading.Tasks;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(0, `public class ${definition.name}Client {`);
+ a(0, ``);
+ a(1, `private JRpcClient Client;`);
+ a(0, ``);
+ a(1, `public ${definition.name}Client(JRpcClient client) {`);
+ a(2, `this.Client = client;`);
+ a(1, `}`);
+ a(0, ``);
+ for (const fnc of definition.functions) {
+ let params = fnc.inputs
+ .map((inp) => {
+ if (inp.array) {
+ return `List<${toCSharpType(inp.type)}> ${inp.name}`;
+ } else {
+ return `${toCSharpType(inp.type)} ${inp.name}`;
+ }
+ })
+ .join(", ");
+
+ const genParam = () =>
+ a(
+ 2,
+ `var param = new JsonArray(${fnc.inputs
+ .map((e) => `JsonSerializer.SerializeToNode(${e.name})`)
+ .join(", ")});`
+ );
+
+ if (fnc.return) {
+ if (fnc.return.type == "void") {
+ a(1, `public async Task ${fnc.name}(${params}) {`);
+ genParam();
+ a(
+ 2,
+ `await this.Client.SendRequestRaw("${definition.name}.${fnc.name}", param);`
+ );
+ a(1, `}`);
+ } else {
+ let ret = fnc.return
+ ? fnc.return.array
+ ? `IList<${toCSharpType(fnc.return.type)}>`
+ : toCSharpType(fnc.return.type)
+ : undefined;
+ a(1, `public async Task<${ret}> ${fnc.name}(${params}) {`);
+ genParam();
+ a(
+ 2,
+ `return await this.Client.SendRequest<${ret}>("${definition.name}.${fnc.name}", param);`
+ );
+ a(1, `}`);
+ }
+ } else {
+ //Notification
+ a(1, `public void ${fnc.name}(${params}) {`);
+ genParam();
+ a(
+ 2,
+ `this.Client.SendNotification("${definition.name}.${fnc.name}", param);`
+ );
+ a(1, `}`);
+ }
+ a(1, ``);
+ }
+ // a(0, ``);
+ // a(0, ``);
+ // a(0, ``);
+ a(0, `}`);
+
+ this.writeFile(`${definition.name}Client.cs`, lines.join("\n"));
+ }
+
+ generateServiceServer(definition: ServiceDefinition) {
+ let lines: string[] = [];
+ const a: lineAppender = (i, t) => {
+ if (!Array.isArray(t)) {
+ t = [t];
+ }
+ t.forEach((l) => lines.push(" ".repeat(i) + l.trim()));
+ };
+
+ a(0, `using System.Text.Json;`);
+ a(0, `using System.Text.Json.Serialization;`);
+ a(0, `using System.Text.Json.Nodes;`);
+ a(0, `using System.Threading.Tasks;`);
+ a(0, ``);
+ a(0, `namespace ${this.namespace};`);
+ a(0, ``);
+ a(
+ 0,
+ `public abstract class ${definition.name}Server : JRpcService {`
+ );
+
+ a(0, ``);
+ a(1, `public ${definition.name}Server() {`);
+ for (const fnc of definition.functions) {
+ a(2, `this.RegisterFunction("${fnc.name}");`);
+ }
+ a(1, `}`);
+ a(0, ``);
+ for (const fnc of definition.functions) {
+ let params = [
+ ...fnc.inputs.map((inp) => {
+ if (inp.array) {
+ return `List<${toCSharpType(inp.type)}> ${inp.name}`;
+ } else {
+ return `${toCSharpType(inp.type)} ${inp.name}`;
+ }
+ }),
+ "TContext ctx",
+ ].join(", ");
+
+ if (fnc.return) {
+ if (fnc.return.type == "void") {
+ a(1, `public abstract Task ${fnc.name}(${params});`);
+ } else {
+ let ret = fnc.return
+ ? fnc.return.array
+ ? `IList<${toCSharpType(fnc.return.type)}>`
+ : toCSharpType(fnc.return.type)
+ : undefined;
+ a(1, `public abstract Task<${ret}> ${fnc.name}(${params});`);
+ }
+ } else {
+ a(1, `public abstract void ${fnc.name}(${params});`);
+ }
+ }
+ a(0, ``);
+ a(
+ 1,
+ `public async override Task HandleRequest(string func, JsonNode param, TContext context) {`
+ );
+ a(2, `switch(func) {`);
+ for (const fnc of definition.functions) {
+ a(3, `case "${fnc.name}": {`);
+ a(4, `if(param is JsonObject) {`);
+ a(
+ 5,
+ `var ja = new JsonArray(${fnc.inputs
+ .map((inp) => {
+ return `param["${inp.name}"]`;
+ })
+ .join(", ")});`
+ );
+ a(5, `param = ja;`);
+ a(4, `}`);
+
+ let pref = "";
+ if (fnc.return) {
+ if (fnc.return.type != "void") pref = "var result = await ";
+ else pref = "await ";
+ }
+
+ a(
+ 4,
+ pref +
+ `this.${fnc.name}(${[
+ ...fnc.inputs.map((inp, idx) => {
+ let type = inp.array
+ ? `List<${toCSharpType(inp.type)}>`
+ : `${toCSharpType(inp.type)}`;
+ return `param[${idx}]!.Deserialize<${type}>()`;
+ }),
+ "context",
+ ].join(", ")});`
+ );
+
+ if (fnc.return && fnc.return.type != "void") {
+ // if(fnc.return.type == "void") {
+ // a(3, `return null;`);
+ // } else {
+ // a(3, ``);
+ // }
+ a(4, `return JsonSerializer.SerializeToNode(result);`);
+ // a(3, ``);
+ } else {
+ a(4, `return null;`);
+ }
+ a(3, `}`);
+ a(0, ``);
+ }
+ a(3, `default:`);
+ a(4, `throw new Exception("Invalid Method!");`);
+ // a(0, ``);
+ // a(0, ``);
+ // a(0, ``);
+ a(2, `}`);
+ a(1, `}`);
+ a(0, `}`);
+
+ this.writeFile(`${definition.name}Server.cs`, lines.join("\n"));
+ }
+
+ generateService(definition: ServiceDefinition): void {
+ this.generateServiceClient(definition);
+ this.generateServiceServer(definition);
+ }
+
+ finalize(steps: Step[]): void {}
+}
diff --git a/src/tokenizer.ts b/src/tokenizer.ts
index 952afd2..9750138 100644
--- a/src/tokenizer.ts
+++ b/src/tokenizer.ts
@@ -57,7 +57,7 @@ const matcher = [
regexMatcher(/^#.+/, "comment"),
regexMatcher(/^".*?"/, "string"),
// regexMatcher(/(?<=^")(.*?)(?=")/, "string"),
- regexMatcher(/^(type|enum|import|service)\b/, "keyword"),
+ regexMatcher(/^(type|enum|import|service|define)\b/, "keyword"),
regexMatcher(/^\@/, "at"),
regexMatcher(/^\:/, "colon"),
regexMatcher(/^\;/, "semicolon"),
diff --git a/templates/CSharp/CSharp.csproj b/templates/CSharp/CSharp.csproj
new file mode 100644
index 0000000..bafd05b
--- /dev/null
+++ b/templates/CSharp/CSharp.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/templates/CSharp/JRpcClient.cs b/templates/CSharp/JRpcClient.cs
new file mode 100644
index 0000000..502be4b
--- /dev/null
+++ b/templates/CSharp/JRpcClient.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+namespace __NAMESPACE__;
+
+public class JRpcClient
+{
+ private JRpcTransport Transport;
+ private IDictionary> Requests;
+
+ public JRpcClient(JRpcTransport transport)
+ {
+ this.Transport = transport;
+ this.Requests = new Dictionary>();
+
+ this.Transport.OnPacket += this.HandlePacket;
+ }
+
+ private void HandlePacket(string packet)
+ {
+ try
+ {
+ var parsed = JsonNode.Parse(packet);
+ if (parsed == null || (string?)parsed["jsonrpc"] != "2.0")
+ return;
+
+ if (parsed["method"] != null)
+ { // Request or Notification
+ if (parsed["id"] != null) // Requests are not supported on the Client
+ return;
+ //TODO: implement Notifications
+ }
+ else if (parsed["id"] != null && parsed["method"] == null)
+ {
+ // Response
+ //TODO: Somehow remove this warning, since it has no meaning in this context.
+ // ID has to be something, that was checked before
+ var id = (string)parsed["id"]!;
+
+ var task = this.Requests[id];
+ if (task == null)
+ return; //This Request was not from here
+
+ if (parsed["error"] != null)
+ {
+ var err = parsed["error"].Deserialize();
+ if (err == null)
+ {
+ task.SetException(new JRpcException("Internal Server Error"));
+ }
+ else
+ {
+ task.SetException(err.ToException());
+ }
+ }
+ else
+ {
+ task.SetResult(parsed["result"]);
+ }
+ }
+ else
+ {
+ // Ignoring invalid packet!
+ return;
+ }
+ }
+ catch (Exception)
+ {
+ //TODO: Maybe log exception, but don't break!
+ }
+ }
+
+ public async Task SendRequestRaw(string method, JsonArray param)
+ {
+ var id = Guid.NewGuid().ToString();
+ var request = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["id"] = id,
+ ["method"] = method,
+ ["params"] = param
+ };
+
+ var task = new TaskCompletionSource();
+ this.Requests.Add(id, task);
+ await this.Transport.Write(request.ToJsonString());
+
+ return await task.Task;
+ }
+
+ public async Task SendRequest(string method, JsonArray param)
+ {
+ var result = await this.SendRequestRaw(method, param);
+ return result.Deserialize();
+ }
+
+ public async void SendNotification(string method, JsonArray param)
+ {
+ var not = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["method"] = method,
+ ["params"] = param,
+ };
+
+ await this.Transport.Write(not.ToJsonString());
+ }
+}
+
+
+class JRpcError
+{
+ public int code { get; set; }
+ public string? message { get; set; }
+ public JsonNode? data { get; set; }
+
+ public JRpcException ToException()
+ {
+ return new JRpcException(this.message!);
+ }
+}
+
+public class JRpcException : Exception
+{
+ public JRpcException(string message) : base(message) { }
+}
diff --git a/templates/CSharp/JRpcServer.cs b/templates/CSharp/JRpcServer.cs
new file mode 100644
index 0000000..329ac21
--- /dev/null
+++ b/templates/CSharp/JRpcServer.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+namespace __NAMESPACE__;
+
+public class JRpcServer
+{
+ public IDictionary> Services;
+
+ public JRpcServer()
+ {
+ this.Services = new Dictionary>();
+ }
+
+ public void AddService(string name, JRpcService service)
+ {
+ this.Services.Add(name, service);
+ }
+
+ public JRpcServerSession GetSession(JRpcTransport transport, TContext context)
+ {
+ return new JRpcServerSession(this, transport, context);
+ }
+}
+
+public class JRpcServerSession
+{
+ JRpcServer Server;
+ JRpcTransport Transport;
+ TContext Context;
+
+ public JRpcServerSession(JRpcServer server, JRpcTransport transport, TContext context)
+ {
+ this.Server = server;
+ this.Transport = transport;
+ this.Context = context;
+
+ this.Transport.OnPacket += this.HandlePacket;
+ }
+
+ private void HandlePacket(string packet)
+ {
+ try
+ {
+ var parsed = JsonNode.Parse(packet);
+ if (parsed == null || (string?)parsed["jsonrpc"] != "2.0")
+ return;
+
+ if (parsed["method"] != null) // Request or Notification
+ {
+ var id = (string?)parsed["id"];
+ var splitted = ((string)parsed["method"]!).Split(".", 2);
+ var serviceName = splitted[0];
+ var functionName = splitted[1];
+
+ if (serviceName == null || functionName == null)
+ {
+ if (id != null)
+ {
+ var response = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["id"] = id,
+ ["error"] = new JsonObject
+ {
+ ["code"] = -32700,
+ ["message"] = "Method not found!",
+ }
+ };
+ _ = this.Transport.Write(response.ToJsonString()!);
+ }
+ return;
+ }
+
+ var service = this.Server.Services[serviceName];
+ if (service == null)
+ {
+ if (id != null)
+ {
+ var response = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["id"] = id,
+ ["error"] = new JsonObject
+ {
+ ["code"] = -32700,
+ ["message"] = "Method not found!",
+ }
+ };
+ _ = this.Transport.Write(response.ToJsonString()!);
+ }
+ return;
+ }
+
+ if (!service.Functions.Contains(functionName))
+ {
+ if (id != null)
+ {
+ var response = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["id"] = id,
+ ["error"] = new JsonObject
+ {
+ ["code"] = -32700,
+ ["message"] = "Method not found!",
+ }
+ };
+ _ = this.Transport.Write(response.ToJsonString()!);
+ }
+ return;
+ }
+
+ if (!(parsed["params"] is JsonArray || parsed["params"] is JsonObject))
+ {
+ if (id != null)
+ {
+ var response = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["id"] = id,
+ ["error"] = new JsonObject
+ {
+ ["code"] = -32602,
+ ["message"] = "Invalid Parameters!",
+ }
+ };
+ _ = this.Transport.Write(response.ToJsonString()!);
+ }
+ return;
+ }
+
+ _ = service.HandleRequest(functionName, parsed["params"]!, this.Context).ContinueWith(result =>
+ {
+ if (id != null)
+ {
+ var response = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["id"] = id,
+ ["error"] = result.IsFaulted ? new JsonObject
+ {
+ ["code"] = -32603,
+ ["message"] = result.Exception!.InnerException!.Message
+ } : null,
+ ["result"] = !result.IsFaulted ? result.Result : null,
+ };
+ _ = this.Transport.Write(response.ToJsonString()!);
+ }
+ });
+
+
+ //TODO: implement Notifications
+ }
+ else
+ {
+ // Ignoring everyting else. Don't care!
+ return;
+ }
+ }
+ catch (Exception)
+ {
+ //TODO: Maybe log exception, but don't break!
+ }
+ }
+
+
+ public async void SendNotification(string method, JsonArray param)
+ {
+ var not = new JsonObject
+ {
+ ["jsonrpc"] = "2.0",
+ ["method"] = method,
+ ["params"] = param,
+ };
+
+ await this.Transport.Write(not.ToJsonString());
+ }
+}
+
+public abstract class JRpcService
+{
+ public HashSet Functions = new HashSet();
+
+ protected void RegisterFunction(string name)
+ {
+ this.Functions.Add(name);
+ }
+
+ public abstract Task HandleRequest(string function, JsonNode param, TContext context);
+ // public abstract Task HandleNotification(string notification, JsonNode param);
+}
diff --git a/templates/CSharp/JRpcTransport.cs b/templates/CSharp/JRpcTransport.cs
new file mode 100644
index 0000000..ee9709a
--- /dev/null
+++ b/templates/CSharp/JRpcTransport.cs
@@ -0,0 +1,14 @@
+using System.Threading.Tasks;
+
+namespace __NAMESPACE__;
+
+public delegate void NotifyPacket(string data);
+
+public abstract class JRpcTransport {
+ public event NotifyPacket OnPacket;
+ public abstract Task Write(string data);
+
+ public void DevSendPacket(string data) {
+ this.OnPacket.Invoke(data);
+ }
+}
diff --git a/templates/ts_service_base.ts b/templates/ts_service_base.ts
index 86e44e4..f67c7fe 100644
--- a/templates/ts_service_base.ts
+++ b/templates/ts_service_base.ts
@@ -9,10 +9,10 @@ export const Logging = {
export enum ErrorCodes {
ParseError = -32700,
- InvalidRequest = -32700,
- MethodNotFound = -32700,
- InvalidParams = -32700,
- InternalError = -32700,
+ InvalidRequest = -32600,
+ MethodNotFound = -32601,
+ InvalidParams = -32602,
+ InternalError = -32603,
}
export interface RequestObject {
diff --git a/yarn.lock b/yarn.lock
index 5a4d18c..ac8e022 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -26,12 +26,14 @@ __metadata:
resolution: "@hibas123/jrpcgen@workspace:."
dependencies:
"@types/debug": ^4.1.7
+ "@types/fs-extra": ^9.0.13
"@types/node": ^17.0.5
"@types/prettier": ^2.4.2
"@types/yargs": ^17.0.8
chalk: 4
debug: ^4.3.3
esbuild: ^0.14.10
+ fs-extra: ^10.0.0
prettier: ^2.5.1
ts-node: ^10.4.0
typescript: ^4.5.4
@@ -78,6 +80,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/fs-extra@npm:^9.0.13":
+ version: 9.0.13
+ resolution: "@types/fs-extra@npm:9.0.13"
+ dependencies:
+ "@types/node": "*"
+ checksum: add79e212acd5ac76b97b9045834e03a7996aef60a814185e0459088fd290519a3c1620865d588fa36c4498bf614210d2a703af5cf80aa1dbc125db78f6edac3
+ languageName: node
+ linkType: hard
+
"@types/ms@npm:*":
version: 0.7.31
resolution: "@types/ms@npm:0.7.31"
@@ -85,6 +96,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/node@npm:*":
+ version: 17.0.8
+ resolution: "@types/node@npm:17.0.8"
+ checksum: f4cadeb9e602027520abc88c77142697e33cf6ac98bb02f8b595a398603cbd33df1f94d01c055c9f13cde0c8eaafc5e396ca72645458d42b4318b845bc7f1d0f
+ languageName: node
+ linkType: hard
+
"@types/node@npm:^17.0.5":
version: 17.0.5
resolution: "@types/node@npm:17.0.5"
@@ -422,6 +440,17 @@ __metadata:
languageName: node
linkType: hard
+"fs-extra@npm:^10.0.0":
+ version: 10.0.0
+ resolution: "fs-extra@npm:10.0.0"
+ dependencies:
+ graceful-fs: ^4.2.0
+ jsonfile: ^6.0.1
+ universalify: ^2.0.0
+ checksum: 5285a3d8f34b917cf2b66af8c231a40c1623626e9d701a20051d3337be16c6d7cac94441c8b3732d47a92a2a027886ca93c69b6a4ae6aee3c89650d2a8880c0a
+ languageName: node
+ linkType: hard
+
"get-caller-file@npm:^2.0.5":
version: 2.0.5
resolution: "get-caller-file@npm:2.0.5"
@@ -429,6 +458,13 @@ __metadata:
languageName: node
linkType: hard
+"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0":
+ version: 4.2.9
+ resolution: "graceful-fs@npm:4.2.9"
+ checksum: 68ea4e07ff2c041ada184f9278b830375f8e0b75154e3f080af6b70f66172fabb4108d19b3863a96b53fc068a310b9b6493d86d1291acc5f3861eb4b79d26ad6
+ languageName: node
+ linkType: hard
+
"has-flag@npm:^4.0.0":
version: 4.0.0
resolution: "has-flag@npm:4.0.0"
@@ -443,6 +479,19 @@ __metadata:
languageName: node
linkType: hard
+"jsonfile@npm:^6.0.1":
+ version: 6.1.0
+ resolution: "jsonfile@npm:6.1.0"
+ dependencies:
+ graceful-fs: ^4.1.6
+ universalify: ^2.0.0
+ dependenciesMeta:
+ graceful-fs:
+ optional: true
+ checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354
+ languageName: node
+ linkType: hard
+
"make-error@npm:^1.1.1":
version: 1.3.6
resolution: "make-error@npm:1.3.6"
@@ -558,6 +607,13 @@ __metadata:
languageName: node
linkType: hard
+"universalify@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "universalify@npm:2.0.0"
+ checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44
+ languageName: node
+ linkType: hard
+
"wrap-ansi@npm:^7.0.0":
version: 7.0.0
resolution: "wrap-ansi@npm:7.0.0"