Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

Commit 8edbb31

Browse files
authored
Merge pull request #930 from codeoverflow-org/feat/895-nodecg-v2-typing
Migrate NodeCG types from `nodecg-types` to the new NodeCG v2 official ones
2 parents df6c0c6 + e7551a5 commit 8edbb31

File tree

204 files changed

+8567
-7444
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

204 files changed

+8567
-7444
lines changed

.scripts/create-service.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
os.mkdir(f'services/nodecg-io-{service_name}/extension')
4848
with open(f'services/nodecg-io-{service_name}/extension/index.ts', mode='w') as file:
4949
file.writelines([
50-
'import { NodeCG } from "nodecg-types/types/server";\n',
50+
'import NodeCG from "@nodecg/types";\n',
5151
'import { Result, emptySuccess, success, ServiceBundle } from "nodecg-io-core";\n',
5252
f'import {{ {service_name_c}Client }} from "./{service_name_cc}Client";\n',
5353
'\n',
@@ -57,7 +57,7 @@
5757
'\n',
5858
f'export {{ {service_name_c}Client }} from "./{service_name_cc}Client";\n',
5959
'\n',
60-
'module.exports = (nodecg: NodeCG) => {\n',
60+
'module.exports = (nodecg: NodeCG.ServerAPI) => {\n',
6161
f' new {service_name_c}Service(nodecg, "{service_name}", __dirname, "../schema.json").register();\n',
6262
'};\n',
6363
'\n',
@@ -135,11 +135,11 @@
135135
os.mkdir(f'samples/{sample_name}/extension')
136136
with open(f'samples/{sample_name}/extension/index.ts', mode='w') as file:
137137
file.writelines([
138-
'import { NodeCG } from "nodecg-types/types/server";\n',
138+
'import NodeCG from "@nodecg/types";\n',
139139
f'import {{ {service_name_c}Client }} from "nodecg-io-{service_name}";\n',
140140
'import { requireService } from "nodecg-io-core";\n',
141141
'\n',
142-
'module.exports = function (nodecg: NodeCG) {\n',
142+
'module.exports = function (nodecg: NodeCG.ServerAPI) {\n',
143143
f' nodecg.log.info("Sample bundle for {service_name_c} started.");\n',
144144
'\n',
145145
f' const {service_name_cc} = requireService<{service_name_c}Client>(nodecg, "{service_name}");\n',

nodecg-io-core/dashboard/authentication.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/// <reference types="nodecg-types/types/browser" />
2-
31
import { updateMonacoLayout } from "./serviceInstance";
42
import { setPassword, isPasswordSet } from "./crypto";
53

@@ -41,7 +39,7 @@ document.addEventListener("DOMContentLoaded", () => {
4139

4240
export async function isLoaded(): Promise<boolean> {
4341
return new Promise((resolve, _reject) => {
44-
nodecg.sendMessage("isLoaded", (_err, res) => resolve(res));
42+
nodecg.sendMessage("isLoaded", (_err, res: boolean) => resolve(res));
4543
setTimeout(() => resolve(false), 5000); // Fallback in case connection gets lost.
4644
});
4745
}

nodecg-io-core/dashboard/main.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
// Define NodeCG instance on global scope
2+
import type { NodeCGAPIClient } from "@nodecg/types/client/api/api.client";
3+
4+
declare global {
5+
const NodeCG: typeof NodeCGAPIClient;
6+
const nodecg: NodeCGAPIClient;
7+
}
8+
19
// Re-export functions that are used in panel.html to the global scope
210
import { loadFramework } from "./authentication";
311
import {

nodecg-io-core/dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"devDependencies": {
2222
"esbuild": "^0.16.12",
2323
"monaco-editor": "^0.36.1",
24-
"nodecg-types": "^1.9.0",
24+
"@nodecg/types": "^2.1.3",
2525
"typescript": "^5.0.3"
2626
},
2727
"dependencies": {

nodecg-io-core/extension/__tests__/bundleManager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MockNodeCG, testBundle, testService, testServiceInstance } from "./mocks";
1+
import { mockNodeCG, testBundle, testService, testServiceInstance } from "./mocks";
22
import { BundleManager } from "../bundleManager";
33

44
describe("BundleManager", () => {
@@ -12,7 +12,7 @@ describe("BundleManager", () => {
1212

1313
beforeEach(() => {
1414
changeCb.mockReset();
15-
bundleManager = new BundleManager(new MockNodeCG());
15+
bundleManager = new BundleManager(mockNodeCG());
1616
bundleManager.on("change", changeCb);
1717
});
1818

@@ -30,7 +30,7 @@ describe("BundleManager", () => {
3030
});
3131

3232
test("should error if registering a dependency on the same service twice", () => {
33-
const bundleManager = new BundleManager(new MockNodeCG());
33+
const bundleManager = new BundleManager(mockNodeCG());
3434
// Depending on testService for the first time => fine
3535
bundleManager.registerServiceDependency(testBundle, testService);
3636
// Depending on testService for the second time => not fine

nodecg-io-core/extension/__tests__/instanceManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ServiceInstance } from "../service";
44
import { ServiceManager } from "../serviceManager";
55
import { emptySuccess, error, success } from "../utils/result";
66
import {
7-
MockNodeCG,
7+
mockNodeCG,
88
testBundle,
99
testBundle2,
1010
testInstance,
@@ -14,7 +14,7 @@ import {
1414
} from "./mocks";
1515

1616
describe("InstanceManager", () => {
17-
const nodecg = new MockNodeCG();
17+
const nodecg = mockNodeCG();
1818

1919
const noConfigService = {
2020
...testService,

nodecg-io-core/extension/__tests__/mocks.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ObjectMap, ServiceInstance } from "../service";
2-
import type { NodeCG, ReplicantOptions, Replicant, Logger } from "nodecg-types/types/server";
2+
import NodeCG from "@nodecg/types";
33
import { EventEmitter } from "events";
44

55
// The mock-nodecg package has a few problems like no typings and some unimplemented functions that are a dealbreaker for us.
@@ -8,7 +8,7 @@ import { EventEmitter } from "events";
88
// But for now we use these mocks that we can easily change if we need something
99
// that mock-nodecg hasn't implemented yet.
1010

11-
export class MockNodeCG implements NodeCG {
11+
export class MockNodeCG {
1212
constructor(
1313
public bundleName: string = "nodecg-io-core",
1414
public bundleConfig = {},
@@ -31,7 +31,9 @@ export class MockNodeCG implements NodeCG {
3131
logging: {},
3232
sentry: {},
3333
login: {},
34-
};
34+
exitOnUncaught: false,
35+
bundles: {},
36+
} as unknown as NodeCG.Config;
3537

3638
sendMessage = jest.fn();
3739
sendMessageToBundle = jest.fn();
@@ -41,8 +43,12 @@ export class MockNodeCG implements NodeCG {
4143
// We don't care about the type that all replicants have. The user has to ensure that the type they provide
4244
// to the replicant method matches the actual content of the replicant.
4345
// eslint-disable-next-line @typescript-eslint/no-explicit-any
44-
private declaredReplicants: ObjectMap<ObjectMap<Replicant<any>>> = {};
45-
Replicant<V>(name: string, namespaceOrOpts?: string | ReplicantOptions<V>, o?: ReplicantOptions<V>): Replicant<V> {
46+
private declaredReplicants: ObjectMap<ObjectMap<MockedReplicant<any>>> = {};
47+
Replicant<V>(
48+
name: string,
49+
namespaceOrOpts?: string | NodeCG.Replicant.OptionsWithDefault<V>,
50+
o?: NodeCG.Replicant.OptionsWithDefault<V>,
51+
): MockedReplicant<V> {
4652
const namespace = typeof namespaceOrOpts === "string" ? namespaceOrOpts : this.bundleName;
4753

4854
// Check if this replicant was already declared once and return it if found
@@ -54,7 +60,7 @@ export class MockNodeCG implements NodeCG {
5460
// This replicant was not already declared and needs to be created.
5561

5662
const opts = typeof namespaceOrOpts === "object" ? namespaceOrOpts : o;
57-
const newReplicant = new MockReplicant(this.log, name, namespace, opts ?? {});
63+
const newReplicant = new MockReplicant(this.log, name, namespace, opts ?? {}) as unknown as MockedReplicant<V>;
5864

5965
const namespaceObj = this.declaredReplicants[namespace];
6066
if (namespaceObj === undefined) {
@@ -68,7 +74,7 @@ export class MockNodeCG implements NodeCG {
6874

6975
readReplicant<V>(name: string): V;
7076
readReplicant<V>(name: string, namespace: string): V;
71-
readReplicant<V>(name: string, namespace?: string): V {
77+
readReplicant<V>(name: string, namespace?: string): V | undefined {
7278
return this.Replicant<V>(name, namespace).value;
7379
}
7480

@@ -82,24 +88,26 @@ export class MockNodeCG implements NodeCG {
8288
}
8389

8490
class MockLogger {
91+
name: "logger";
8592
trace = jest.fn();
8693
debug = jest.fn();
8794
info = jest.fn();
8895
warn = jest.fn();
8996
error = jest.fn();
9097
replicants = jest.fn();
91-
static globalReconfigure = jest.fn();
9298
}
9399

94-
class MockReplicant<V> extends EventEmitter implements Replicant<V> {
95-
private _value: V | undefined = this.opts.defaultValue;
100+
type MockedReplicant<V> = MockReplicant<V> & NodeCG.ServerReplicant<V>;
101+
102+
class MockReplicant<V> extends EventEmitter {
103+
_value: V | undefined = this.opts.defaultValue;
96104
revision = 0;
97105

98106
constructor(
99-
public readonly log: Logger,
107+
public readonly log: NodeCG.Logger,
100108
public readonly name: string,
101109
public readonly namespace: string,
102-
public readonly opts: ReplicantOptions<V>,
110+
public readonly opts: Partial<NodeCG.Replicant.OptionsWithDefault<V>>,
103111
) {
104112
super();
105113
}
@@ -124,6 +132,10 @@ class MockReplicant<V> extends EventEmitter implements Replicant<V> {
124132
}
125133
}
126134

135+
export function mockNodeCG(): MockNodeCG & NodeCG.ServerAPI {
136+
return new MockNodeCG() as unknown as MockNodeCG & NodeCG.ServerAPI;
137+
}
138+
127139
// Test objects
128140

129141
// These variables all contain a string of their name and are mainly

nodecg-io-core/extension/__tests__/persistenceManager.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import { decryptData, EncryptedData, PersistenceManager, PersistentData } from "
55
import { ServiceManager } from "../serviceManager";
66
import { ServiceProvider } from "../serviceProvider";
77
import { emptySuccess, error } from "../utils/result";
8-
import { MockNodeCG, testBundle, testInstance, testService, testServiceInstance } from "./mocks";
8+
import { mockNodeCG, testBundle, testInstance, testService, testServiceInstance } from "./mocks";
99

1010
describe("PersistenceManager", () => {
1111
const validPassword = "myPassword";
1212
const invalidPassword = "someOtherPassword";
1313

14-
const nodecg = new MockNodeCG();
14+
const nodecg = mockNodeCG();
1515
const serviceManager = new ServiceManager(nodecg);
1616
serviceManager.registerService(testService);
1717

@@ -379,6 +379,10 @@ describe("PersistenceManager", () => {
379379
test("should automatically save if BundleManager or InstanceManager emit a change event", async () => {
380380
await persistenceManager.load(validPassword); // Set password so that we can save stuff
381381

382+
if (!encryptedDataReplicant.value) {
383+
throw new Error("encryptedDataReplicant.value was undefined");
384+
}
385+
382386
encryptedDataReplicant.value.cipherText = undefined;
383387
bundleManager.emit("change");
384388
expect(encryptedDataReplicant.value.cipherText).toBeDefined();

nodecg-io-core/extension/__tests__/serviceManager.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { ServiceManager } from "../serviceManager";
2-
import { MockNodeCG, testService } from "./mocks";
2+
import { mockNodeCG, testService } from "./mocks";
33

44
describe("ServiceManager", () => {
55
test("should start with no services", () => {
6-
const serviceManager = new ServiceManager(new MockNodeCG());
6+
const serviceManager = new ServiceManager(mockNodeCG());
77
expect(serviceManager.getServices().length).toBe(0);
88
});
99

1010
test("should return all registered services", () => {
11-
const serviceManager = new ServiceManager(new MockNodeCG());
11+
const serviceManager = new ServiceManager(mockNodeCG());
1212
serviceManager.registerService(testService);
1313

1414
// Make sure that the freshly registered service is also in the service list.
@@ -17,14 +17,14 @@ describe("ServiceManager", () => {
1717
});
1818

1919
test("getService should return a error if service is not registered", () => {
20-
const serviceManager = new ServiceManager(new MockNodeCG());
20+
const serviceManager = new ServiceManager(mockNodeCG());
2121

2222
const result = serviceManager.getService("someInvalidServiceType");
2323
expect(result.failed).toBe(true);
2424
});
2525

2626
test("getService should return success if service is registered", () => {
27-
const serviceManager = new ServiceManager(new MockNodeCG());
27+
const serviceManager = new ServiceManager(mockNodeCG());
2828
serviceManager.registerService(testService);
2929

3030
const result = serviceManager.getService(testService.serviceType);

nodecg-io-core/extension/bundleManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NodeCG } from "nodecg-types/types/server";
1+
import NodeCG from "@nodecg/types";
22
import { ObjectMap, Service, ServiceDependency, ServiceInstance } from "./service";
33
import { emptySuccess, error, Result } from "./utils/result";
44
import { EventEmitter } from "events";
@@ -11,7 +11,7 @@ export class BundleManager extends EventEmitter {
1111
// Object that maps a bundle name to the array that contains all services that this bundle depends upon
1212
private readonly bundles: ObjectMap<ServiceDependency<unknown>[]> = {};
1313

14-
constructor(private readonly nodecg: NodeCG) {
14+
constructor(private readonly nodecg: NodeCG.ServerAPI) {
1515
super();
1616
}
1717

0 commit comments

Comments
 (0)