From cea00adc7f28aae033d7b11a303a281c58b3de8a Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 17 Jun 2021 19:41:32 +0200 Subject: [PATCH 1/3] Don't lint generated typescript declaration files --- nodecg-io-core/dashboard/tsconfig.json | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/nodecg-io-core/dashboard/tsconfig.json b/nodecg-io-core/dashboard/tsconfig.json index ae9b14f2d..ac0276efa 100644 --- a/nodecg-io-core/dashboard/tsconfig.json +++ b/nodecg-io-core/dashboard/tsconfig.json @@ -4,7 +4,8 @@ "lib": ["ES2015", "dom"], "module": "ES2015", - "sourceMap": true + "sourceMap": true, + "declaration": false }, "extends": "../../tsconfig.common.json" } diff --git a/package.json b/package.json index c4bae6e9e..1fcd26f34 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "bsb": "npm run bootstrap && npm run build", "rebuild": "npm run clean && npm run build", "watch": "lerna run --parallel watch", - "lint": "eslint . --ext ts", + "lint": "eslint . --ext ts --ignore-pattern '**/*.d.ts'", "format": "prettier --write \"./**/*.{ts,html,css,json}\"", "format-pre-commit": "pretty-quick --staged --pattern '*/**/*.{ts,html,css,json}'", "prepare": "husky install" From 8407e5250365a38b37c193c9f1928c88f86195aa Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 17 Jun 2021 19:46:50 +0200 Subject: [PATCH 2/3] Transform declaration files into actual typescript files --- nodecg-io-core/dashboard/crypto.ts | 2 +- nodecg-io-core/dashboard/utils/selectUtils.ts | 2 +- nodecg-io-core/extension/bundleManager.ts | 2 +- nodecg-io-core/extension/index.ts | 2 +- nodecg-io-core/extension/instanceManager.ts | 11 +++++++---- nodecg-io-core/extension/persistenceManager.ts | 2 +- .../extension/{types.d.ts => service.ts} | 16 ++++++++-------- nodecg-io-core/extension/serviceBundle.ts | 6 +++--- nodecg-io-core/extension/serviceManager.ts | 2 +- nodecg-io-core/index.ts | 2 +- .../extension/StreamElements.ts | 2 +- .../{types.d.ts => StreamElementsEvent.ts} | 0 12 files changed, 26 insertions(+), 23 deletions(-) rename nodecg-io-core/extension/{types.d.ts => service.ts} (92%) rename nodecg-io-streamelements/extension/{types.d.ts => StreamElementsEvent.ts} (100%) diff --git a/nodecg-io-core/dashboard/crypto.ts b/nodecg-io-core/dashboard/crypto.ts index 11047fc30..84c9ac597 100644 --- a/nodecg-io-core/dashboard/crypto.ts +++ b/nodecg-io-core/dashboard/crypto.ts @@ -1,6 +1,6 @@ import { PersistentData, EncryptedData, decryptData } from "nodecg-io-core/extension/persistenceManager"; import { EventEmitter } from "events"; -import { ObjectMap, ServiceInstance, ServiceDependency, Service } from "nodecg-io-core/extension/types"; +import { ObjectMap, ServiceInstance, ServiceDependency, Service } from "nodecg-io-core/extension/service"; import { isLoaded } from "./authentication"; import { PasswordMessage } from "nodecg-io-core/extension/messageManager"; diff --git a/nodecg-io-core/dashboard/utils/selectUtils.ts b/nodecg-io-core/dashboard/utils/selectUtils.ts index fc3ce08af..f7eb5eb67 100644 --- a/nodecg-io-core/dashboard/utils/selectUtils.ts +++ b/nodecg-io-core/dashboard/utils/selectUtils.ts @@ -1,4 +1,4 @@ -import { ObjectMap } from "nodecg-io-core/extension/types"; +import { ObjectMap } from "nodecg-io-core/extension/service"; export function updateOptionsMap(node: HTMLSelectElement, options: ObjectMap): void { updateOptionsArr(node, Object.keys(options)); diff --git a/nodecg-io-core/extension/bundleManager.ts b/nodecg-io-core/extension/bundleManager.ts index be7592642..89cd37c44 100644 --- a/nodecg-io-core/extension/bundleManager.ts +++ b/nodecg-io-core/extension/bundleManager.ts @@ -1,5 +1,5 @@ import { NodeCG } from "nodecg/types/server"; -import { ObjectMap, Service, ServiceDependency, ServiceInstance } from "./types"; +import { ObjectMap, Service, ServiceDependency, ServiceInstance } from "./service"; import { emptySuccess, error, Result } from "./utils/result"; import { EventEmitter } from "events"; import { ServiceProvider } from "./serviceProvider"; diff --git a/nodecg-io-core/extension/index.ts b/nodecg-io-core/extension/index.ts index df766b3dc..78f26099b 100644 --- a/nodecg-io-core/extension/index.ts +++ b/nodecg-io-core/extension/index.ts @@ -3,7 +3,7 @@ import { ServiceManager } from "./serviceManager"; import { BundleManager } from "./bundleManager"; import { MessageManager } from "./messageManager"; import { InstanceManager } from "./instanceManager"; -import { Service } from "./types"; +import { Service } from "./service"; import { PersistenceManager } from "./persistenceManager"; import { ServiceProvider } from "./serviceProvider"; diff --git a/nodecg-io-core/extension/instanceManager.ts b/nodecg-io-core/extension/instanceManager.ts index 4a160fb71..e2e621804 100644 --- a/nodecg-io-core/extension/instanceManager.ts +++ b/nodecg-io-core/extension/instanceManager.ts @@ -1,5 +1,5 @@ import { NodeCG } from "nodecg/types/server"; -import { ObjectMap, Service, ServiceInstance } from "./types"; +import { ObjectMap, Service, ServiceInstance } from "./service"; import { emptySuccess, error, Result } from "./utils/result"; import { ServiceManager } from "./serviceManager"; import { BundleManager } from "./bundleManager"; @@ -164,9 +164,12 @@ export class InstanceManager extends EventEmitter { // We need to do validation, spawn a Promise return (async () => { - const schemaValid = this.ajv.validate(service.result.schema, config); - if (!schemaValid) { - return error("Config invalid: " + this.ajv.errorsText()); + // If the service has a schema, check it. + if (service.result.schema) { + const schemaValid = this.ajv.validate(service.result.schema, config); + if (!schemaValid) { + return error("Config invalid: " + this.ajv.errorsText()); + } } // Validation by the service. diff --git a/nodecg-io-core/extension/persistenceManager.ts b/nodecg-io-core/extension/persistenceManager.ts index 34c8f3a3d..773feb2d5 100644 --- a/nodecg-io-core/extension/persistenceManager.ts +++ b/nodecg-io-core/extension/persistenceManager.ts @@ -3,7 +3,7 @@ import { InstanceManager } from "./instanceManager"; import { BundleManager } from "./bundleManager"; import * as crypto from "crypto-js"; import { emptySuccess, error, Result, success } from "./utils/result"; -import { ObjectMap, ServiceDependency, ServiceInstance } from "./types"; +import { ObjectMap, ServiceDependency, ServiceInstance } from "./service"; import { ServiceManager } from "./serviceManager"; /** diff --git a/nodecg-io-core/extension/types.d.ts b/nodecg-io-core/extension/service.ts similarity index 92% rename from nodecg-io-core/extension/types.d.ts rename to nodecg-io-core/extension/service.ts index 371750fc3..46dcaed85 100644 --- a/nodecg-io-core/extension/types.d.ts +++ b/nodecg-io-core/extension/service.ts @@ -1,4 +1,4 @@ -// Holds generic types for the whole project +// Holds types/interfaces related to services import { Result } from "./utils/result"; import { ServiceProvider } from "./serviceProvider"; @@ -12,7 +12,7 @@ import { ServiceProvider } from "./serviceProvider"; * A normal es6 map would use a iterator which can't be serialized by the NodeCG Replicant and thus * can't be used to give the gui access to the data in this map. */ -export type ObjectMap = Record; +export type ObjectMap = Record; /** * Models a service that a bundle can depend upon and use to access e.g. a twitch chat or similar. @@ -20,7 +20,7 @@ export type ObjectMap = Record; * Intended to hold configurations and authentication information that the service needs to provide a client. * @typeParam C the type of a client that the service will provide to bundles using {@link createClient}. */ -export interface Service> { +export interface Service { /** * User friendly name of the service that should explain the type of service, e.g. "twitch". */ @@ -30,7 +30,7 @@ export interface Service> { * A json schema object of the config. The config will then be validated against this json schema. * Ensures that the types of the config are correct and therefore is compatible with the provided config type. */ - readonly schema?: ObjectMap; + readonly schema?: ObjectMap; /** * The default value for the config. @@ -43,7 +43,7 @@ export interface Service> { * @param config the config which should be validated. * @return void if the config passes validation and an error string describing the issue if not. */ - readonly validateConfig(config: R): Promise>; + validateConfig(config: R): Promise>; /** * Creates a client to the service using the validated config. @@ -52,7 +52,7 @@ export interface Service> { * @param config the user provided config for the service. * @return the client if everything went well and an error string describing the issue if a error occured. */ - readonly createClient(config: R): Promise>; + createClient(config: R): Promise>; /** * Stops a client of this service that is not needed anymore. @@ -60,7 +60,7 @@ export interface Service> { * * @param client the client that needs to be stopped. */ - readonly stopClient(client: C): void; + stopClient(client: C): void; /** * Removes all handlers from a service client. @@ -72,7 +72,7 @@ export interface Service> { * Can be left unimplemented if the serivce doesn't has any handlers e.g. a http wrapper * @param client the client of which all handlers should be removed */ - readonly removeHandlers?(client: C): void; + removeHandlers?(client: C): void; /** * This flag can be enabled by services if they can't implement {@link removeHandlers} but also have some handlers that diff --git a/nodecg-io-core/extension/serviceBundle.ts b/nodecg-io-core/extension/serviceBundle.ts index 0d8a3f26d..29a09bf19 100644 --- a/nodecg-io-core/extension/serviceBundle.ts +++ b/nodecg-io-core/extension/serviceBundle.ts @@ -1,6 +1,6 @@ import { NodeCGIOCore } from "."; import { NodeCG } from "nodecg/types/server"; -import { Service } from "./types"; +import { ObjectMap, Service } from "./service"; import { Result } from "./utils/result"; import * as fs from "fs"; @@ -18,7 +18,7 @@ export abstract class ServiceBundle implements Service { public core: NodeCGIOCore | undefined; public nodecg: NodeCG; public serviceType: string; - public schema: unknown; + public schema?: ObjectMap; /** * The default value for the config. @@ -107,7 +107,7 @@ export abstract class ServiceBundle implements Service { */ requiresNoConfig = false; - private readSchema(pathSegments: string[]): unknown { + private readSchema(pathSegments: string[]): ObjectMap | undefined { const joinedPath = path.resolve(...pathSegments); try { const fileContent = fs.readFileSync(joinedPath, "utf8"); diff --git a/nodecg-io-core/extension/serviceManager.ts b/nodecg-io-core/extension/serviceManager.ts index cba9e1cca..fdb72baae 100644 --- a/nodecg-io-core/extension/serviceManager.ts +++ b/nodecg-io-core/extension/serviceManager.ts @@ -1,4 +1,4 @@ -import { Service } from "./types"; +import { Service } from "./service"; import { NodeCG } from "nodecg/types/server"; import { error, Result, success } from "./utils/result"; diff --git a/nodecg-io-core/index.ts b/nodecg-io-core/index.ts index d4006674e..8ff0545b8 100644 --- a/nodecg-io-core/index.ts +++ b/nodecg-io-core/index.ts @@ -2,7 +2,7 @@ // This can be used by services and bundles to import everything by just using "nodecg-io-core" and they don't need to know paths // or where the thing they want to import is located. // You can obviously still provide the full path if you wish. -export type { ObjectMap, Service, ServiceDependency, ServiceInstance } from "./extension/types"; +export type { ObjectMap, Service, ServiceDependency, ServiceInstance } from "./extension/service"; export * from "./extension/utils/result"; export * from "./extension/serviceBundle"; export * from "./extension/serviceProvider"; diff --git a/nodecg-io-streamelements/extension/StreamElements.ts b/nodecg-io-streamelements/extension/StreamElements.ts index 81c7586df..6d526b89b 100644 --- a/nodecg-io-streamelements/extension/StreamElements.ts +++ b/nodecg-io-streamelements/extension/StreamElements.ts @@ -1,6 +1,6 @@ import io = require("socket.io-client"); import { Result, emptySuccess, error } from "nodecg-io-core"; -import { StreamElementsEvent } from "./types"; +import { StreamElementsEvent } from "./StreamElementsEvent"; import { EventEmitter } from "events"; export class StreamElementsServiceClient extends EventEmitter { diff --git a/nodecg-io-streamelements/extension/types.d.ts b/nodecg-io-streamelements/extension/StreamElementsEvent.ts similarity index 100% rename from nodecg-io-streamelements/extension/types.d.ts rename to nodecg-io-streamelements/extension/StreamElementsEvent.ts From 62c959338d00b8de026ad17023acabe3a45fc6ca Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 17 Jun 2021 19:55:13 +0200 Subject: [PATCH 3/3] Simplify ObjectMap to always use string as a key type --- nodecg-io-core/dashboard/crypto.ts | 4 ++-- nodecg-io-core/dashboard/utils/selectUtils.ts | 2 +- nodecg-io-core/extension/bundleManager.ts | 6 +++--- nodecg-io-core/extension/instanceManager.ts | 6 +++--- nodecg-io-core/extension/persistenceManager.ts | 12 ++++++------ nodecg-io-core/extension/service.ts | 4 ++-- nodecg-io-core/extension/serviceBundle.ts | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/nodecg-io-core/dashboard/crypto.ts b/nodecg-io-core/dashboard/crypto.ts index 84c9ac597..4ead7cf98 100644 --- a/nodecg-io-core/dashboard/crypto.ts +++ b/nodecg-io-core/dashboard/crypto.ts @@ -15,8 +15,8 @@ let password: string | undefined; * b. having everything at hand using one variable is quite nice so I've added services here to complete it. */ interface ConfigData { - instances: ObjectMap>; - bundles: ObjectMap[]>; + instances: ObjectMap>; + bundles: ObjectMap[]>; services: Service[]; } diff --git a/nodecg-io-core/dashboard/utils/selectUtils.ts b/nodecg-io-core/dashboard/utils/selectUtils.ts index f7eb5eb67..29af0871a 100644 --- a/nodecg-io-core/dashboard/utils/selectUtils.ts +++ b/nodecg-io-core/dashboard/utils/selectUtils.ts @@ -1,6 +1,6 @@ import { ObjectMap } from "nodecg-io-core/extension/service"; -export function updateOptionsMap(node: HTMLSelectElement, options: ObjectMap): void { +export function updateOptionsMap(node: HTMLSelectElement, options: ObjectMap): void { updateOptionsArr(node, Object.keys(options)); } diff --git a/nodecg-io-core/extension/bundleManager.ts b/nodecg-io-core/extension/bundleManager.ts index 89cd37c44..50284b801 100644 --- a/nodecg-io-core/extension/bundleManager.ts +++ b/nodecg-io-core/extension/bundleManager.ts @@ -8,7 +8,7 @@ import { ServiceProvider } from "./serviceProvider"; * Manages bundles and their dependencies on nodecg-io services. */ export class BundleManager extends EventEmitter { - private readonly bundles: ObjectMap[]> = {}; + private readonly bundles: ObjectMap[]> = {}; constructor(private readonly nodecg: NodeCG) { super(); @@ -16,9 +16,9 @@ export class BundleManager extends EventEmitter { /** * Gets all bundle dependencies - * @return {ObjectMap[]>} all bundle dependencies + * @return {ObjectMap[]>} all bundle dependencies */ - getBundleDependencies(): ObjectMap[]> { + getBundleDependencies(): ObjectMap[]> { return this.bundles; } diff --git a/nodecg-io-core/extension/instanceManager.ts b/nodecg-io-core/extension/instanceManager.ts index e2e621804..7fb05f493 100644 --- a/nodecg-io-core/extension/instanceManager.ts +++ b/nodecg-io-core/extension/instanceManager.ts @@ -10,7 +10,7 @@ import { EventEmitter } from "events"; * Manages instances of services and their configs/clients. */ export class InstanceManager extends EventEmitter { - private serviceInstances: ObjectMap> = {}; + private serviceInstances: ObjectMap> = {}; private ajv = new Ajv(); constructor( @@ -35,9 +35,9 @@ export class InstanceManager extends EventEmitter { /** * Returns all existing service instances. - * @return {ObjectMap>} a map of the instance name to the instance. + * @return {ObjectMap>} a map of the instance name to the instance. */ - getServiceInstances(): ObjectMap> { + getServiceInstances(): ObjectMap> { return this.serviceInstances; } diff --git a/nodecg-io-core/extension/persistenceManager.ts b/nodecg-io-core/extension/persistenceManager.ts index 773feb2d5..f3513eb56 100644 --- a/nodecg-io-core/extension/persistenceManager.ts +++ b/nodecg-io-core/extension/persistenceManager.ts @@ -13,11 +13,11 @@ export interface PersistentData { /** * All instance data that is held by the {@link InstanceManager}. */ - instances: ObjectMap>; + instances: ObjectMap>; /** * All bundle dependency data that is held by the {@link BundleManager}. */ - bundleDependencies: ObjectMap[]>; + bundleDependencies: ObjectMap[]>; } /** @@ -142,7 +142,7 @@ export class PersistenceManager { * and then setting the config of the passed object. * @param instances the service instances that should be loaded. */ - private loadServiceInstances(instances: ObjectMap>): Promise[] { + private loadServiceInstances(instances: ObjectMap>): Promise[] { return Object.keys(instances).map((instanceName) => { const inst = instances[instanceName]; if (inst === undefined) { @@ -188,7 +188,7 @@ export class PersistenceManager { * Loads all passed bundle dependencies into the framework by setting them in the bundle manager. * @param bundles the bundle dependencies that should be set. */ - private loadBundleDependencies(bundles: ObjectMap[]>): void { + private loadBundleDependencies(bundles: ObjectMap[]>): void { Object.keys(bundles).forEach((bundleName) => { if (!Object.prototype.hasOwnProperty.call(bundles, bundleName)) { return; @@ -234,9 +234,9 @@ export class PersistenceManager { * Creates a copy of all service instances without the service clients, because those * shouldn't be serialized and don't need to be stored in the encrypted config file. */ - private getServiceInstances(): ObjectMap> { + private getServiceInstances(): ObjectMap> { const instances = this.instances.getServiceInstances(); - const copy: ObjectMap> = {}; + const copy: ObjectMap> = {}; for (const instName in instances) { if (!Object.prototype.hasOwnProperty.call(instances, instName)) { diff --git a/nodecg-io-core/extension/service.ts b/nodecg-io-core/extension/service.ts index 46dcaed85..334b5ce44 100644 --- a/nodecg-io-core/extension/service.ts +++ b/nodecg-io-core/extension/service.ts @@ -12,7 +12,7 @@ import { ServiceProvider } from "./serviceProvider"; * A normal es6 map would use a iterator which can't be serialized by the NodeCG Replicant and thus * can't be used to give the gui access to the data in this map. */ -export type ObjectMap = Record; +export type ObjectMap = Record; /** * Models a service that a bundle can depend upon and use to access e.g. a twitch chat or similar. @@ -30,7 +30,7 @@ export interface Service { * A json schema object of the config. The config will then be validated against this json schema. * Ensures that the types of the config are correct and therefore is compatible with the provided config type. */ - readonly schema?: ObjectMap; + readonly schema?: ObjectMap; /** * The default value for the config. diff --git a/nodecg-io-core/extension/serviceBundle.ts b/nodecg-io-core/extension/serviceBundle.ts index 29a09bf19..4927a7559 100644 --- a/nodecg-io-core/extension/serviceBundle.ts +++ b/nodecg-io-core/extension/serviceBundle.ts @@ -18,7 +18,7 @@ export abstract class ServiceBundle implements Service { public core: NodeCGIOCore | undefined; public nodecg: NodeCG; public serviceType: string; - public schema?: ObjectMap; + public schema?: ObjectMap; /** * The default value for the config. @@ -107,7 +107,7 @@ export abstract class ServiceBundle implements Service { */ requiresNoConfig = false; - private readSchema(pathSegments: string[]): ObjectMap | undefined { + private readSchema(pathSegments: string[]): ObjectMap | undefined { const joinedPath = path.resolve(...pathSegments); try { const fileContent = fs.readFileSync(joinedPath, "utf8");