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

Commit 7797f83

Browse files
authored
feat: add support for nodecg-io 0.2 (#39)
* feat: add support for nodecg-io 0.2 * Fix test compile errors due to unchecked array access
1 parent 0fac3ea commit 7797f83

File tree

12 files changed

+72
-37
lines changed

12 files changed

+72
-37
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ The following table show which versions of the CLI are compatible with which nod
5959
| CLI versions | nodecg-io versions |
6060
| ------------ | ------------------ |
6161
| `0.1` | `0.1` |
62+
| `0.2` | `0.2`, `0.1` |
6263

6364
Currently, they are the same, but we will follow [semver2](https://semver.org/) using [semantic-release](https://semantic-release.gitbook.io/semantic-release/) and the versions will diverge at some point.
6465

src/install/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ async function install(): Promise<void> {
3232
logger.debug(`Detected nodecg installation at ${nodecgDir}.`);
3333
const nodecgIODir = getNodeCGIODirectory(nodecgDir);
3434

35-
const currentInstall = await readInstallInfo(nodecgIODir);
35+
let currentInstall = await readInstallInfo(nodecgIODir);
3636
const requestedInstall = await promptForInstallInfo(currentInstall);
3737

3838
// If the minor version changed and we already have another one installed, we need to delete it, so it can be properly installed.
3939
if (currentInstall && currentInstall.version !== requestedInstall.version && (await directoryExists(nodecgIODir))) {
4040
logger.info(`Deleting nodecg-io version ${currentInstall.version}...`);
4141
await removeDirectory(nodecgIODir);
42+
currentInstall = undefined;
4243
}
4344

4445
logger.info(`Installing nodecg-io version ${requestedInstall.version}...`);
@@ -56,7 +57,7 @@ async function install(): Promise<void> {
5657

5758
// Add bundle dirs to the nodecg config, so that they are loaded.
5859
await manageBundleDir(nodecgDir, nodecgIODir, true);
59-
await manageBundleDir(nodecgDir, path.join(nodecgIODir, "services"), requestedInstall.version !== "0.1");
60+
await manageBundleDir(nodecgDir, path.join(nodecgIODir, "services"), requestedInstall.version === "development");
6061
await manageBundleDir(
6162
nodecgDir,
6263
path.join(nodecgIODir, "samples"),

src/install/prompt.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export async function promptForInstallInfo(currentInstall: Installation | undefi
4040
message: "Which version do you want to install?",
4141
choices: [...versions, developmentVersion].reverse(),
4242
loop: false,
43-
default: currentInstall?.version ?? versions.slice(-1)[0],
43+
default: currentInstall?.version ?? versions[versions.length - 1],
4444
},
4545
// Options for development installs
4646
{
@@ -131,7 +131,7 @@ export async function buildPackageList(version: string, services: string[]): Pro
131131
name: pkgName,
132132
path: getPackagePath(pkgName),
133133
version: await getPackageVersion(pkgName, version),
134-
symlink: getPackageSymlinks(pkgName),
134+
symlink: getPackageSymlinks(version, pkgName),
135135
}));
136136

137137
return await Promise.all(resolvePromises);
@@ -154,9 +154,10 @@ async function getPackageVersion(pkgName: string, minorVersion: string) {
154154
return version?.version ?? `${minorVersion}.0`;
155155
}
156156

157-
function getPackageSymlinks(pkgName: string) {
158-
// special case: dashboard needs monaco-editor to be symlink into the local node_modules directory.
159-
if (pkgName === dashboardPackage) {
157+
function getPackageSymlinks(version: string, pkgName: string) {
158+
// special case: dashboard of version 0.1 needs monaco-editor to be symlink into the local node_modules directory.
159+
// with 0.2 and onwards monaco-editor is built with webpack and included in the build output.
160+
if (pkgName === dashboardPackage && version === "0.1") {
160161
return ["monaco-editor"];
161162
}
162163

src/nodecgIOVersions.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,27 @@ const version01Services = {
4747
youtube: "YoutubeServiceClient",
4848
};
4949

50-
export const supportedNodeCGIORange = new semver.Range("<=0.1");
50+
const version02Services = {
51+
...version01Services,
52+
artnet: "ArtNetServiceClient",
53+
atem: "AtemServiceClient",
54+
dbus: "DBusClient",
55+
debug: "DebugHelper",
56+
"discord-rpc": "DiscordRpcClient",
57+
"elgato-light": "ElgatoLightClient",
58+
googleapis: "GoogleApisServiceClient",
59+
github: "GitHubClient",
60+
"mqtt-client": "MQTTClientServiceClient",
61+
shlink: "ShlinkServiceClient",
62+
sql: "SQLClient",
63+
youtube: undefined,
64+
};
65+
66+
export const supportedNodeCGIORange = new semver.Range("<=0.2");
5167

52-
export const versionServiceMap: Record<string, Record<string, string>> = {
68+
export const versionServiceMap: Record<string, Record<string, string | undefined>> = {
5369
"0.1": version01Services,
70+
"0.2": version02Services,
5471
};
5572

5673
/**
@@ -65,7 +82,12 @@ export function getServicesForVersion(version: string): string[] {
6582
throw new Error(`Don't have any service list for version ${version}. Something might be wrong here.`);
6683
}
6784

68-
return Object.keys(services);
85+
const serviceNames = Object.keys(services)
86+
// only services which have a corresponding service class
87+
// this is not the case when e.g. the service only existed in a previous version
88+
.filter((svcName) => services[svcName] !== undefined);
89+
serviceNames.sort();
90+
return serviceNames;
6991
}
7092

7193
/**
@@ -76,6 +98,10 @@ export function getServicesForVersion(version: string): string[] {
7698
*/
7799
export function getServiceClientName(service: string, version: string): string {
78100
const svcClientMapping = versionServiceMap[version];
79-
const clientName = svcClientMapping[service];
101+
const clientName = svcClientMapping?.[service];
102+
if (clientName === undefined) {
103+
throw new Error(`Access of undefined service client name for ${service}@${version}`);
104+
}
105+
80106
return clientName;
81107
}

src/utils/nodecgInstallation.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ async function isNodeCGDirectory(dir: string): Promise<boolean> {
4747
*/
4848
export async function getNodeCGVersion(nodecgDir: string): Promise<SemVer> {
4949
const packageJson = await readPackageJson(nodecgDir);
50-
return new SemVer(packageJson["version"]);
50+
const version = packageJson["version"];
51+
if (version === undefined) {
52+
throw new Error("Version field is missin in the NodeCG package.json.");
53+
}
54+
55+
return new SemVer(version);
5156
}
5257

5358
async function readPackageJson(nodecgDir: string): Promise<Record<string, string>> {

test/install/development.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe("getGitRepo", () => {
9393
test("should use correct git url for nodecg-io and docs", async () => {
9494
await dev.getGitRepo(nodecgIODir, "nodecg-io");
9595
await dev.getGitRepo(nodecgIODir, "nodecg-io-docs");
96-
expect(fetchSpy.mock.calls[0][0].url?.endsWith("nodecg-io.git")).toBe(true);
97-
expect(fetchSpy.mock.calls[1][0].url?.endsWith("nodecg-io-docs.git")).toBe(true);
96+
expect(fetchSpy.mock.calls[0]?.[0].url?.endsWith("nodecg-io.git")).toBe(true);
97+
expect(fetchSpy.mock.calls[1]?.[0].url?.endsWith("nodecg-io-docs.git")).toBe(true);
9898
});
9999
});

test/install/prompt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ describe("getCompatibleVersions", () => {
2020
const spy = jest.spyOn(logger, "warn");
2121
await getCompatibleVersions(compatibleRange);
2222
expect(spy).toHaveBeenCalled();
23-
expect(spy.mock.calls[0][0]).toContain("Cannot install");
24-
expect(spy.mock.calls[0][0]).toContain("1.0, 1.1");
23+
expect(spy.mock.calls[0]?.[0]).toContain("Cannot install");
24+
expect(spy.mock.calls[0]?.[0]).toContain("1.0, 1.1");
2525
});
2626
});
2727

test/uninstall/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ describe("uninstall", () => {
3535
expect(spyManageBundleDir).toBeCalledTimes(3);
3636

3737
// Should remove nodecg-io directory and sample bundle directory (if applicable)
38-
expect(spyManageBundleDir.mock.calls[0][1]).toBe(nodecgIODir);
39-
expect(spyManageBundleDir.mock.calls[1][1]).toBe(path.join(nodecgIODir, "services"));
40-
expect(spyManageBundleDir.mock.calls[2][1]).toBe(path.join(nodecgIODir, "samples"));
38+
expect(spyManageBundleDir.mock.calls[0]?.[1]).toBe(nodecgIODir);
39+
expect(spyManageBundleDir.mock.calls[1]?.[1]).toBe(path.join(nodecgIODir, "services"));
40+
expect(spyManageBundleDir.mock.calls[2]?.[1]).toBe(path.join(nodecgIODir, "samples"));
4141
// Should remove them, not add them
42-
expect(spyManageBundleDir.mock.calls[0][2]).toBe(false);
43-
expect(spyManageBundleDir.mock.calls[1][2]).toBe(false);
44-
expect(spyManageBundleDir.mock.calls[2][2]).toBe(false);
42+
expect(spyManageBundleDir.mock.calls[0]?.[2]).toBe(false);
43+
expect(spyManageBundleDir.mock.calls[1]?.[2]).toBe(false);
44+
expect(spyManageBundleDir.mock.calls[2]?.[2]).toBe(false);
4545
});
4646

4747
test("should remove nodecg-io directory", async () => {

test/utils/fs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,13 @@ describe("executeCommand", () => {
7474
test("should inherit io streams", async () => {
7575
const spy = jest.spyOn(child_process, "spawn");
7676
await executeCommand("exit", ["0"]);
77-
expect(spy.mock.calls[0][2].stdio).toBe("inherit");
77+
expect(spy.mock.calls[0]?.[2].stdio).toBe("inherit");
7878
});
7979

8080
test("should log the command that gets executed", async () => {
8181
const spy = jest.spyOn(logger, "info");
8282
await executeCommand("exit", ["0"]);
8383
expect(spy).toHaveBeenCalled();
84-
expect(spy.mock.calls[0][0]).toContain("exit 0");
84+
expect(spy.mock.calls[0]?.[0]).toContain("exit 0");
8585
});
8686
});

test/utils/npm/npmVersion.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe("getNpmVersion", () => {
4141
const execSpy = createExecMock(validNpmVersion);
4242
await getNpmVersion();
4343
expect(execSpy).toHaveBeenCalled();
44-
expect(execSpy.mock.calls[0][0]).toBe("npm --version");
44+
expect(execSpy.mock.calls[0]?.[0]).toBe("npm --version");
4545
});
4646

4747
test("should return undefined if npm is not installed", async () => {

0 commit comments

Comments
 (0)