Prettier pass
This commit is contained in:
parent
6369534169
commit
bc39f10a8e
19 changed files with 303 additions and 301 deletions
|
@ -5,7 +5,9 @@ A file synchronisation utility for Bitburner, using the Remote File API.
|
|||
It allows players to synchronize scripts and text files from their computer's disk to the game in both the Electron build and website.
|
||||
|
||||
## How to use (for users)
|
||||
|
||||
You must have a recent version of `npm` installed after which you can run
|
||||
|
||||
```
|
||||
npx bitburner-filesync
|
||||
```
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env ts-node
|
||||
import { start } from "../src/index"
|
||||
import { start } from "../src/index";
|
||||
|
||||
await start();
|
||||
|
|
140
src/config.ts
140
src/config.ts
|
@ -3,82 +3,80 @@ import { existsSync } from "fs";
|
|||
|
||||
// Define a schema
|
||||
export let config = convict({
|
||||
allowedFiletypes: {
|
||||
doc: 'Filetypes that are synchronized to the game.',
|
||||
format: 'Array',
|
||||
default: [".js", ".script", ".txt"]
|
||||
allowedFiletypes: {
|
||||
doc: "Filetypes that are synchronized to the game.",
|
||||
format: "Array",
|
||||
default: [".js", ".script", ".txt"],
|
||||
},
|
||||
allowDeletingFiles: {
|
||||
doc: "Allow deleting files in game if they get deleted off disk.",
|
||||
format: "Boolean",
|
||||
default: false,
|
||||
arg: "allowDeletingFiles",
|
||||
},
|
||||
port: {
|
||||
doc: "The port to bind to.",
|
||||
format: "Number",
|
||||
default: 12525,
|
||||
env: "BB_PORT",
|
||||
arg: "port",
|
||||
},
|
||||
scriptsFolder: {
|
||||
doc: "The to be synchronized folder.",
|
||||
format: "String",
|
||||
default: ".",
|
||||
env: "BB_SCRIPTFOLDER",
|
||||
arg: "folder",
|
||||
},
|
||||
quiet: {
|
||||
doc: "Log less internal events to stdout.",
|
||||
format: "Boolean",
|
||||
env: "BB_VERBOSE",
|
||||
default: false,
|
||||
arg: "quiet",
|
||||
},
|
||||
dry: {
|
||||
doc: "Only print the files to be synchronised.",
|
||||
format: "Boolean",
|
||||
env: "BB_DRY",
|
||||
default: false,
|
||||
arg: "dry",
|
||||
},
|
||||
definitionFile: {
|
||||
update: {
|
||||
doc: "Automatically pull the definition file from the game.",
|
||||
format: "Boolean",
|
||||
env: "BB_UPDATE_DEF",
|
||||
default: false,
|
||||
},
|
||||
allowDeletingFiles: {
|
||||
doc: 'Allow deleting files in game if they get deleted off disk.',
|
||||
format: 'Boolean',
|
||||
default: false,
|
||||
arg: 'allowDeletingFiles',
|
||||
location: {
|
||||
doc: "Location/name of where the definition file gets placed.",
|
||||
format: "String",
|
||||
env: "BB_LOCATION_DEF",
|
||||
default: "./NetScriptDefinitions.d.ts",
|
||||
},
|
||||
port: {
|
||||
doc: 'The port to bind to.',
|
||||
format: 'Number',
|
||||
default: 12525,
|
||||
env: 'BB_PORT',
|
||||
arg: 'port'
|
||||
},
|
||||
scriptsFolder: {
|
||||
doc: 'The to be synchronized folder.',
|
||||
format: 'String',
|
||||
default: '.',
|
||||
env: 'BB_SCRIPTFOLDER',
|
||||
arg: 'folder'
|
||||
},
|
||||
quiet: {
|
||||
doc: 'Log less internal events to stdout.',
|
||||
format: 'Boolean',
|
||||
env: 'BB_VERBOSE',
|
||||
default: false,
|
||||
arg: 'quiet'
|
||||
},
|
||||
dry: {
|
||||
doc: 'Only print the files to be synchronised.',
|
||||
format: 'Boolean',
|
||||
env: 'BB_DRY',
|
||||
default: false,
|
||||
arg: 'dry'
|
||||
},
|
||||
definitionFile: {
|
||||
update: {
|
||||
doc: 'Automatically pull the definition file from the game.',
|
||||
format: 'Boolean',
|
||||
env: 'BB_UPDATE_DEF',
|
||||
default: false
|
||||
},
|
||||
location: {
|
||||
doc: 'Location/name of where the definition file gets placed.',
|
||||
format: 'String',
|
||||
env: 'BB_LOCATION_DEF',
|
||||
default: "./NetScriptDefinitions.d.ts"
|
||||
}
|
||||
},
|
||||
pushAllOnConnection: {
|
||||
doc: 'Push all files when initial connection is made.',
|
||||
format: 'Boolean',
|
||||
env: 'BB_CON_PUSH',
|
||||
default: false,
|
||||
arg: 'pushAllOnConnection'
|
||||
}
|
||||
},
|
||||
pushAllOnConnection: {
|
||||
doc: "Push all files when initial connection is made.",
|
||||
format: "Boolean",
|
||||
env: "BB_CON_PUSH",
|
||||
default: false,
|
||||
arg: "pushAllOnConnection",
|
||||
},
|
||||
});
|
||||
|
||||
export function loadConfig() {
|
||||
const configFile = "filesync.json";
|
||||
if (existsSync(configFile)) {
|
||||
try {
|
||||
config.loadFile(configFile);
|
||||
} catch (e) {
|
||||
throw new Error(`Unable to load configuration file at ${configFile}: ${e}`);
|
||||
}
|
||||
} else if (!config.get("quiet")) {
|
||||
console.log("No configuration file found.")
|
||||
const configFile = "filesync.json";
|
||||
if (existsSync(configFile)) {
|
||||
try {
|
||||
config.loadFile(configFile);
|
||||
} catch (e) {
|
||||
throw new Error(`Unable to load configuration file at ${configFile}: ${e}`);
|
||||
}
|
||||
} else if (!config.get("quiet")) {
|
||||
console.log("No configuration file found.");
|
||||
}
|
||||
|
||||
// Perform validation
|
||||
config.validate({ allowed: 'strict' });
|
||||
// Perform validation
|
||||
config.validate({ allowed: "strict" });
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export class EventType {
|
||||
static ConnectionMade = "ConnectionMade";
|
||||
static FileChanged = "FileChanged";
|
||||
static FileDeleted = "FileDeleted";
|
||||
static MessageReceived = "MessageReceived";
|
||||
static MessageSend = "MessageSend";
|
||||
}
|
||||
static ConnectionMade = "ConnectionMade";
|
||||
static FileChanged = "FileChanged";
|
||||
static FileDeleted = "FileDeleted";
|
||||
static MessageReceived = "MessageReceived";
|
||||
static MessageSend = "MessageSend";
|
||||
}
|
||||
|
|
|
@ -2,36 +2,38 @@ import CheapWatch from "cheap-watch";
|
|||
import { config } from "./config";
|
||||
import { EventType } from "./eventTypes";
|
||||
import { resolve } from "path";
|
||||
import type { Signal } from 'signal-js';
|
||||
import type { File } from './interfaces';
|
||||
import type { Signal } from "signal-js";
|
||||
import type { File } from "./interfaces";
|
||||
|
||||
function fileFilter(file: File) {
|
||||
if (config.get("allowedFiletypes").some(extension => file.path.endsWith(extension)))
|
||||
return true;
|
||||
if (file.stats.isDirectory())
|
||||
return true;
|
||||
return false;
|
||||
if (config.get("allowedFiletypes").some((extension) => file.path.endsWith(extension))) return true;
|
||||
if (file.stats.isDirectory()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function setupWatch(signaller: Signal) {
|
||||
const watch = new CheapWatch({
|
||||
dir: config.get("scriptsFolder"),
|
||||
filter: fileFilter,
|
||||
watch: !config.get("dry")
|
||||
});
|
||||
const watch = new CheapWatch({
|
||||
dir: config.get("scriptsFolder"),
|
||||
filter: fileFilter,
|
||||
watch: !config.get("dry"),
|
||||
});
|
||||
|
||||
if (!config.get("quiet")) console.log("Watching folder", resolve(config.get("scriptsFolder")))
|
||||
if (!config.get("quiet")) console.log("Watching folder", resolve(config.get("scriptsFolder")));
|
||||
|
||||
watch.on('+', fileEvent => { if (fileEvent.stats.isFile()) signaller.emit(EventType.FileChanged, fileEvent) });
|
||||
watch.on('-', fileEvent => { if (fileEvent.stats.isFile()) signaller.emit(EventType.FileDeleted, fileEvent) });
|
||||
watch.on("+", (fileEvent) => {
|
||||
if (fileEvent.stats.isFile()) signaller.emit(EventType.FileChanged, fileEvent);
|
||||
});
|
||||
watch.on("-", (fileEvent) => {
|
||||
if (fileEvent.stats.isFile()) signaller.emit(EventType.FileDeleted, fileEvent);
|
||||
});
|
||||
|
||||
// Wait 'till filewatcher is ready to go
|
||||
await watch.init();
|
||||
// Wait 'till filewatcher is ready to go
|
||||
await watch.init();
|
||||
|
||||
if (config.get("dry")) {
|
||||
console.log("Watch would've synchronised:\n", watch.paths)
|
||||
process.exit();
|
||||
}
|
||||
if (config.get("dry")) {
|
||||
console.log("Watch would've synchronised:\n", watch.paths);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
return watch;
|
||||
return watch;
|
||||
}
|
||||
|
|
86
src/index.ts
86
src/index.ts
|
@ -2,57 +2,63 @@ import { setupWatch } from "./fileWatch";
|
|||
import { config, loadConfig } from "./config";
|
||||
import { setupSocket } from "./networking/webSocket";
|
||||
import signal from "signal-js";
|
||||
import { fileChangeEventToMsg, fileRemovalEventToMsg, requestFilenames, requestDefinitionFile } from "./networking/messageGenerators";
|
||||
import {
|
||||
fileChangeEventToMsg,
|
||||
fileRemovalEventToMsg,
|
||||
requestFilenames,
|
||||
requestDefinitionFile,
|
||||
} from "./networking/messageGenerators";
|
||||
import { EventType } from "./eventTypes";
|
||||
import { messageHandler } from "./networking/messageHandler";
|
||||
import { FileEvent, Message } from './interfaces';
|
||||
import { FileEvent, Message } from "./interfaces";
|
||||
|
||||
export async function start() {
|
||||
loadConfig();
|
||||
const watch = await setupWatch(signal);
|
||||
const socket = setupSocket(signal);
|
||||
loadConfig();
|
||||
const watch = await setupWatch(signal);
|
||||
const socket = setupSocket(signal);
|
||||
|
||||
// Add a handler for received messages.
|
||||
signal.on(EventType.MessageReceived, (msg: Message) => messageHandler(signal, msg, watch.paths));
|
||||
// Add a handler for received messages.
|
||||
signal.on(EventType.MessageReceived, (msg: Message) => messageHandler(signal, msg, watch.paths));
|
||||
|
||||
// Add a handler for when a connection to a game is made.
|
||||
signal.on(EventType.ConnectionMade, () => {
|
||||
console.log("Connection made!");
|
||||
// Add a handler for when a connection to a game is made.
|
||||
signal.on(EventType.ConnectionMade, () => {
|
||||
console.log("Connection made!");
|
||||
|
||||
if (config.get("definitionFile").update) {
|
||||
signal.emit(EventType.MessageSend, requestDefinitionFile());
|
||||
}
|
||||
if (config.get("definitionFile").update) {
|
||||
signal.emit(EventType.MessageSend, requestDefinitionFile());
|
||||
}
|
||||
|
||||
if (config.get("pushAllOnConnection")) {
|
||||
const extensions = config.get("allowedFiletypes");
|
||||
for (const path of watch.paths.keys()) {
|
||||
if (extensions.some(extension => path.endsWith(extension)))
|
||||
signal.emit(EventType.MessageSend, fileChangeEventToMsg({ path }))
|
||||
}
|
||||
} else {
|
||||
// Upload missing files to the game.
|
||||
signal.emit(EventType.MessageSend, requestFilenames());
|
||||
}
|
||||
})
|
||||
if (config.get("pushAllOnConnection")) {
|
||||
const extensions = config.get("allowedFiletypes");
|
||||
for (const path of watch.paths.keys()) {
|
||||
if (extensions.some((extension) => path.endsWith(extension)))
|
||||
signal.emit(EventType.MessageSend, fileChangeEventToMsg({ path }));
|
||||
}
|
||||
} else {
|
||||
// Upload missing files to the game.
|
||||
signal.emit(EventType.MessageSend, requestFilenames());
|
||||
}
|
||||
});
|
||||
|
||||
// Add a handler for changed files.
|
||||
signal.on(EventType.FileChanged, (fileEvent: FileEvent) => {
|
||||
if (!config.get("quiet")) console.log(fileEvent.path + " changed");
|
||||
signal.emit(EventType.MessageSend, fileChangeEventToMsg(fileEvent))
|
||||
});
|
||||
// Add a handler for changed files.
|
||||
signal.on(EventType.FileChanged, (fileEvent: FileEvent) => {
|
||||
if (!config.get("quiet")) console.log(fileEvent.path + " changed");
|
||||
signal.emit(EventType.MessageSend, fileChangeEventToMsg(fileEvent));
|
||||
});
|
||||
|
||||
// Add a handler for removed files, if allowed.
|
||||
if (config.get("allowDeletingFiles"))
|
||||
signal.on(EventType.FileDeleted, (fileEvent: FileEvent) =>
|
||||
signal.emit(EventType.MessageSend, fileRemovalEventToMsg(fileEvent)));
|
||||
// Add a handler for removed files, if allowed.
|
||||
if (config.get("allowDeletingFiles"))
|
||||
signal.on(EventType.FileDeleted, (fileEvent: FileEvent) =>
|
||||
signal.emit(EventType.MessageSend, fileRemovalEventToMsg(fileEvent)),
|
||||
);
|
||||
|
||||
console.log(`Server is ready, running on ${config.get("port")}!`)
|
||||
console.log(`Server is ready, running on ${config.get("port")}!`);
|
||||
|
||||
process.on('SIGINT', function () {
|
||||
console.log("Shutting down!");
|
||||
process.on("SIGINT", function () {
|
||||
console.log("Shutting down!");
|
||||
|
||||
watch.close();
|
||||
socket.close();
|
||||
process.exit();
|
||||
});
|
||||
watch.close();
|
||||
socket.close();
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Stats } from 'fs';
|
||||
import type { Stats } from "fs";
|
||||
|
||||
export interface Message {
|
||||
id: string;
|
||||
|
@ -12,5 +12,5 @@ export interface FileEvent {
|
|||
}
|
||||
|
||||
export interface File extends FileEvent {
|
||||
stats: Stats
|
||||
stats: Stats;
|
||||
}
|
||||
|
|
|
@ -1,58 +1,56 @@
|
|||
import { readFileSync } from "fs";
|
||||
import { config } from "../config";
|
||||
import { join } from "path";
|
||||
import type { FileEvent, Message } from '../interfaces';
|
||||
import type { FileEvent, Message } from "../interfaces";
|
||||
|
||||
let messageCounter = 0;
|
||||
|
||||
export function fileChangeEventToMsg({ path }: FileEvent): Message {
|
||||
return {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "pushFile",
|
||||
"params": {
|
||||
"server": "home",
|
||||
"filename": addLeadingSlash(path),
|
||||
"content": readFileSync(join(config.get("scriptsFolder"), path)).toString()
|
||||
},
|
||||
"id": (messageCounter++).toString()
|
||||
}
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
method: "pushFile",
|
||||
params: {
|
||||
server: "home",
|
||||
filename: addLeadingSlash(path),
|
||||
content: readFileSync(join(config.get("scriptsFolder"), path)).toString(),
|
||||
},
|
||||
id: (messageCounter++).toString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function fileRemovalEventToMsg({ path }: FileEvent): Message {
|
||||
return {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "deleteFile",
|
||||
"params": {
|
||||
"server": "home",
|
||||
"filename": addLeadingSlash(path),
|
||||
},
|
||||
"id": (messageCounter++).toString()
|
||||
}
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
method: "deleteFile",
|
||||
params: {
|
||||
server: "home",
|
||||
filename: addLeadingSlash(path),
|
||||
},
|
||||
id: (messageCounter++).toString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function requestDefinitionFile(): Message {
|
||||
return {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getDefinitionFile",
|
||||
"id": (messageCounter++).toString()
|
||||
}
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
method: "getDefinitionFile",
|
||||
id: (messageCounter++).toString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function requestFilenames(): Message {
|
||||
return {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getFileNames",
|
||||
"params": {
|
||||
"server": "home",
|
||||
},
|
||||
"id": (messageCounter++).toString()
|
||||
}
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
method: "getFileNames",
|
||||
params: {
|
||||
server: "home",
|
||||
},
|
||||
id: (messageCounter++).toString(),
|
||||
};
|
||||
}
|
||||
|
||||
function addLeadingSlash(path: string): string {
|
||||
const slashes = path.match('/');
|
||||
if (slashes)
|
||||
return `/${path}`
|
||||
else
|
||||
return path
|
||||
const slashes = path.match("/");
|
||||
if (slashes) return `/${path}`;
|
||||
else return path;
|
||||
}
|
||||
|
|
|
@ -3,41 +3,40 @@ import { Stats, writeFile } from "fs";
|
|||
import { config } from "../config";
|
||||
import { EventType } from "../eventTypes";
|
||||
import { fileChangeEventToMsg } from "./messageGenerators";
|
||||
import type { Signal } from 'signal-js';
|
||||
import { Message } from '../interfaces';
|
||||
import type { Signal } from "signal-js";
|
||||
import { Message } from "../interfaces";
|
||||
|
||||
export function messageHandler(signaller: Signal, msg: Message, paths: Map<string, Stats>) {
|
||||
let incoming;
|
||||
let incoming;
|
||||
|
||||
try { incoming = JSON.parse(msg.toString()); }
|
||||
catch (err) { return console.log(err); }
|
||||
console.log(incoming)
|
||||
if (incoming.id == undefined) return;
|
||||
try {
|
||||
incoming = JSON.parse(msg.toString());
|
||||
} catch (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
console.log(incoming);
|
||||
if (incoming.id == undefined) return;
|
||||
|
||||
if (incoming.result) {
|
||||
const request = messageTracker.get(incoming.id);
|
||||
if (request?.method &&
|
||||
request.method == "getDefinitionFile"
|
||||
&& incoming.result) {
|
||||
writeFile(config.get("definitionFile").location, incoming.result, (err) => {
|
||||
if (err) return console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
if (request?.method &&
|
||||
request.method == "getFileNames"
|
||||
&& incoming.result) {
|
||||
const gameFiles = incoming.result.map((file: string) => removeLeadingSlash(file));
|
||||
|
||||
paths.forEach((stats, fileName) => {
|
||||
if (!stats.isDirectory() && !gameFiles.includes(fileName))
|
||||
signaller.emit(EventType.MessageSend, fileChangeEventToMsg({ path: fileName }));
|
||||
})
|
||||
}
|
||||
if (incoming.result) {
|
||||
const request = messageTracker.get(incoming.id);
|
||||
if (request?.method && request.method == "getDefinitionFile" && incoming.result) {
|
||||
writeFile(config.get("definitionFile").location, incoming.result, (err) => {
|
||||
if (err) return console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
if (request?.method && request.method == "getFileNames" && incoming.result) {
|
||||
const gameFiles = incoming.result.map((file: string) => removeLeadingSlash(file));
|
||||
|
||||
paths.forEach((stats, fileName) => {
|
||||
if (!stats.isDirectory() && !gameFiles.includes(fileName))
|
||||
signaller.emit(EventType.MessageSend, fileChangeEventToMsg({ path: fileName }));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function removeLeadingSlash(path: string) {
|
||||
const reg = /^\//;
|
||||
return path.replace(reg, "")
|
||||
const reg = /^\//;
|
||||
return path.replace(reg, "");
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import type { Message } from '../interfaces';
|
||||
import type { Message } from "../interfaces";
|
||||
|
||||
class MessageTracker {
|
||||
data = new Map<string, Message>();
|
||||
#maxLength = 200;
|
||||
data = new Map<string, Message>();
|
||||
#maxLength = 200;
|
||||
|
||||
push(msg: Message) {
|
||||
this.data.set(msg.id, msg);
|
||||
push(msg: Message) {
|
||||
this.data.set(msg.id, msg);
|
||||
|
||||
if (this.data.size > this.#maxLength) {
|
||||
const [firstKey] = this.data.keys();
|
||||
this.data.delete(firstKey);
|
||||
}
|
||||
if (this.data.size > this.#maxLength) {
|
||||
const [firstKey] = this.data.keys();
|
||||
this.data.delete(firstKey);
|
||||
}
|
||||
}
|
||||
|
||||
get(index: string) {
|
||||
return this.data.get(index);
|
||||
}
|
||||
get(index: string) {
|
||||
return this.data.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
export const messageTracker = new MessageTracker();
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
import type { Signal } from 'signal-js';
|
||||
import { WebSocketServer } from 'ws';
|
||||
import type { Signal } from "signal-js";
|
||||
import { WebSocketServer } from "ws";
|
||||
import { config } from "../config";
|
||||
import { EventType } from "../eventTypes"
|
||||
import { Message } from '../interfaces';
|
||||
import { requestDefinitionFile } from './messageGenerators';
|
||||
import { messageTracker } from "./messageTracker"
|
||||
import { EventType } from "../eventTypes";
|
||||
import { Message } from "../interfaces";
|
||||
import { requestDefinitionFile } from "./messageGenerators";
|
||||
import { messageTracker } from "./messageTracker";
|
||||
|
||||
export function setupSocket(signaller: Signal) {
|
||||
const wss = new WebSocketServer({ port: config.get("port") });
|
||||
|
||||
const wss = new WebSocketServer({ port: config.get("port") });
|
||||
wss.on("connection", function connection(ws) {
|
||||
function sendMessage(msg: Message) {
|
||||
messageTracker.push(msg);
|
||||
ws.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
|
||||
function sendMessage(msg: Message) {
|
||||
messageTracker.push(msg);
|
||||
ws.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
ws.on('message', (msg) => {
|
||||
signaller.emit(EventType.MessageReceived, msg);
|
||||
});
|
||||
|
||||
signaller.on(EventType.MessageSend, (msg: Message) => {
|
||||
sendMessage(msg);
|
||||
});
|
||||
|
||||
signaller.trigger(EventType.ConnectionMade);
|
||||
ws.on("message", (msg) => {
|
||||
signaller.emit(EventType.MessageReceived, msg);
|
||||
});
|
||||
|
||||
return wss;
|
||||
signaller.on(EventType.MessageSend, (msg: Message) => {
|
||||
sendMessage(msg);
|
||||
});
|
||||
|
||||
signaller.trigger(EventType.ConnectionMade);
|
||||
});
|
||||
|
||||
return wss;
|
||||
}
|
||||
|
|
10
src/signals.d.ts
vendored
10
src/signals.d.ts
vendored
|
@ -1,10 +1,8 @@
|
|||
declare module 'signal-js' {
|
||||
|
||||
declare module "signal-js" {
|
||||
export type Signal = typeof signal;
|
||||
export default class signal {
|
||||
static on<T>(event: string, callback: (data: T) => void): void
|
||||
static emit<T>(event: string, data: T): void
|
||||
static trigger(event: string): void
|
||||
static on<T>(event: string, callback: (data: T) => void): void;
|
||||
static emit<T>(event: string, data: T): void;
|
||||
static trigger(event: string): void;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { setupWatch } from '../src/fileWatch';
|
||||
import { expect } from 'chai';
|
||||
import { stub, createStubInstance } from 'sinon';
|
||||
import CheapWatch from 'cheap-watch';
|
||||
import signal from 'signal-js';
|
||||
import { setupWatch } from "../src/fileWatch";
|
||||
import { expect } from "chai";
|
||||
import { stub, createStubInstance } from "sinon";
|
||||
import CheapWatch from "cheap-watch";
|
||||
import signal from "signal-js";
|
||||
|
||||
describe('fileWatch', () => {
|
||||
describe('setupWatch', () => {
|
||||
it('should exist', () => {
|
||||
describe("fileWatch", () => {
|
||||
describe("setupWatch", () => {
|
||||
it("should exist", () => {
|
||||
expect(setupWatch).to.exist;
|
||||
});
|
||||
|
||||
it('should instantiate and initialize CheapWatch', async () => {
|
||||
const consoleStub = stub(console, 'log');
|
||||
it("should instantiate and initialize CheapWatch", async () => {
|
||||
const consoleStub = stub(console, "log");
|
||||
const watchInstance = createStubInstance(CheapWatch);
|
||||
const watchConstructorStub = stub().returns(watchInstance);
|
||||
Object.setPrototypeOf(CheapWatch, watchConstructorStub);
|
||||
|
|
|
@ -1,27 +1,32 @@
|
|||
import { expect } from 'chai';
|
||||
import { fileChangeEventToMsg, fileRemovalEventToMsg, requestDefinitionFile, requestFilenames } from '../../src/networking/messageGenerators';
|
||||
import { expect } from "chai";
|
||||
import {
|
||||
fileChangeEventToMsg,
|
||||
fileRemovalEventToMsg,
|
||||
requestDefinitionFile,
|
||||
requestFilenames,
|
||||
} from "../../src/networking/messageGenerators";
|
||||
|
||||
describe('messageGenerators', () => {
|
||||
describe('fileChangeEventToMsg', () => {
|
||||
it('should exist', () => {
|
||||
describe("messageGenerators", () => {
|
||||
describe("fileChangeEventToMsg", () => {
|
||||
it("should exist", () => {
|
||||
expect(fileChangeEventToMsg).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('fileRemovalEventToMsg', () => {
|
||||
it('should exist', () => {
|
||||
describe("fileRemovalEventToMsg", () => {
|
||||
it("should exist", () => {
|
||||
expect(fileRemovalEventToMsg).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestDefinitionFile', () => {
|
||||
it('should exist', () => {
|
||||
describe("requestDefinitionFile", () => {
|
||||
it("should exist", () => {
|
||||
expect(requestDefinitionFile).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestFilenames', () => {
|
||||
it('should exist', () => {
|
||||
describe("requestFilenames", () => {
|
||||
it("should exist", () => {
|
||||
expect(requestFilenames).to.exist;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { expect } from 'chai';
|
||||
import { messageHandler } from '../../src/networking/messageHandler';
|
||||
import { expect } from "chai";
|
||||
import { messageHandler } from "../../src/networking/messageHandler";
|
||||
|
||||
describe('messageHandler', () => {
|
||||
it('should exist', () => {
|
||||
describe("messageHandler", () => {
|
||||
it("should exist", () => {
|
||||
expect(messageHandler).to.exist;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { expect } from 'chai';
|
||||
import { messageTracker } from '../../src/networking/messageTracker';
|
||||
import { expect } from "chai";
|
||||
import { messageTracker } from "../../src/networking/messageTracker";
|
||||
|
||||
describe('messageTracker', () => {
|
||||
it('should exist', () => {
|
||||
describe("messageTracker", () => {
|
||||
it("should exist", () => {
|
||||
expect(messageTracker).to.exist;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { expect } from 'chai';
|
||||
import { expect } from "chai";
|
||||
|
||||
describe('webSocket', () => {
|
||||
it('should run test', () => {
|
||||
expect(true).to.eq(true)
|
||||
})
|
||||
describe("webSocket", () => {
|
||||
it("should run test", () => {
|
||||
expect(true).to.eq(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai';
|
||||
import { createSandbox, stub } from 'sinon';
|
||||
import sinonChai from 'sinon-chai';
|
||||
import chai from "chai";
|
||||
import { createSandbox, stub } from "sinon";
|
||||
import sinonChai from "sinon-chai";
|
||||
|
||||
export async function mochaGlobalSetup() {
|
||||
// initial global setup
|
||||
|
@ -27,5 +27,5 @@ export const mochaHooks: Mocha.RootHookObject = {
|
|||
afterEach(done: () => void) {
|
||||
this.sandbox.restore();
|
||||
done();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -4,16 +4,12 @@
|
|||
"esm": true,
|
||||
"experimentalSpecifierResolution": "node"
|
||||
},
|
||||
"include": [
|
||||
"src/signals.d.ts",
|
||||
"src/**/*",
|
||||
"test/**/*"
|
||||
],
|
||||
"include": ["src/signals.d.ts", "src/**/*", "test/**/*"],
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
|
||||
"module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
@ -22,7 +18,7 @@
|
|||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "./dist", /* Redirect output structure to the directory. */
|
||||
"outDir": "./dist" /* Redirect output structure to the directory. */,
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
|
@ -32,7 +28,7 @@
|
|||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
|
@ -46,14 +42,14 @@
|
|||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
/* Source Map Options */
|
||||
|
|
Loading…
Add table
Reference in a new issue