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

Commit 77f4c26

Browse files
authored
Merge pull request #40 from codeoverflow-org/next
Release nodecg-io-cli `0.2.0`
2 parents 98063e0 + 7797f83 commit 77f4c26

20 files changed

+146
-435
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

package-lock.json

Lines changed: 28 additions & 351 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
"devDependencies": {
4040
"@semantic-release/git": "^10.0.0",
4141
"@types/glob": "^7.1.4",
42-
"@types/gunzip-maybe": "^1.4.0",
4342
"@types/inquirer": "^8.1.3",
4443
"@types/jest": "^27.0.2",
4544
"@types/node": "^16.10.3",
@@ -64,9 +63,7 @@
6463
"axios": "^0.24.0",
6564
"chalk": "^4.1.2",
6665
"code-block-writer": "^11.0.0",
67-
"find-up": "^5.0.0",
6866
"glob": "^7.2.0",
69-
"gunzip-maybe": "^1.4.2",
7067
"inquirer": "^8.2.0",
7168
"isomorphic-git": "^1.10.1",
7269
"semver": "^7.3.5",

src/generate/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export async function genExtension(opts: GenerationOptions, install: ProductionI
4242
genImport(writer, "requireService", opts.corePackage.name, opts.language);
4343

4444
if (opts.language === "typescript") {
45-
genImport(writer, "NodeCG", "nodecg/types/server", opts.language);
45+
genImport(writer, "NodeCG", `${opts.nodeeCGTypingsPackage}/types/server`, opts.language);
4646
// Service import statements
4747
services.forEach((svc) => {
4848
genImport(writer, svc.clientName, svc.packageName, opts.language);

src/generate/index.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const generateModule: CommandModule = {
2929

3030
const opts = await promptGenerationOpts(nodecgDir, install);
3131

32-
await generateBundle(nodecgDir, opts, install);
32+
await generateBundle(opts, install);
3333

3434
logger.success(`Successfully generated bundle ${opts.bundleName}.`);
3535
} catch (e) {
@@ -63,11 +63,7 @@ export function ensureValidInstallation(install: Installation | undefined): inst
6363
return true;
6464
}
6565

66-
export async function generateBundle(
67-
nodecgDir: string,
68-
opts: GenerationOptions,
69-
install: ProductionInstallation,
70-
): Promise<void> {
66+
export async function generateBundle(opts: GenerationOptions, install: ProductionInstallation): Promise<void> {
7167
// Create dir if necessary
7268
if (!(await directoryExists(opts.bundlePath))) {
7369
await fs.promises.mkdir(opts.bundlePath);
@@ -84,7 +80,7 @@ export async function generateBundle(
8480
}
8581

8682
// All of these calls only generate files if they are set accordingly in the GenerationOptions
87-
await genPackageJson(nodecgDir, opts);
83+
await genPackageJson(opts);
8884
await genTsConfig(opts);
8985
await genGitIgnore(opts);
9086
await genExtension(opts, install);

src/generate/packageJson.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { GenerationOptions } from "./prompt";
22
import { logger } from "../utils/log";
3-
import { getNodeCGVersion } from "../utils/nodecgInstallation";
43
import { getLatestPackageVersion } from "../utils/npm";
54
import { genNodeCGDashboardConfig, genNodeCGGraphicConfig } from "./panel";
65
import { SemVer } from "semver";
@@ -17,7 +16,7 @@ type Dependency = [string, string];
1716
* @param nodecgDir the directory in which nodecg is installed
1817
* @param opts the options that the user chose for the bundle.
1918
*/
20-
export async function genPackageJson(nodecgDir: string, opts: GenerationOptions): Promise<void> {
19+
export async function genPackageJson(opts: GenerationOptions): Promise<void> {
2120
const serviceDeps: Dependency[] = opts.servicePackages.map((pkg) => [pkg.name, addSemverCaret(pkg.version)]);
2221

2322
const content = {
@@ -32,7 +31,7 @@ export async function genPackageJson(nodecgDir: string, opts: GenerationOptions)
3231
},
3332
// These scripts are for compiling TS and thus are only needed when generating a TS bundle
3433
scripts: genScripts(opts),
35-
dependencies: Object.fromEntries(await genDependencies(opts, serviceDeps, nodecgDir)),
34+
dependencies: Object.fromEntries(await genDependencies(opts, serviceDeps)),
3635
};
3736

3837
await writeBundleFile(content, opts.bundlePath, "package.json");
@@ -46,12 +45,12 @@ export async function genPackageJson(nodecgDir: string, opts: GenerationOptions)
4645
* @param nodecgDir the directory in which nodecg is installed
4746
* @return the dependencies for a bundle with the given options.
4847
*/
49-
async function genDependencies(opts: GenerationOptions, serviceDeps: Dependency[], nodecgDir: string) {
48+
async function genDependencies(opts: GenerationOptions, serviceDeps: Dependency[]) {
5049
const core = [opts.corePackage.name, addSemverCaret(opts.corePackage.version)];
5150

5251
if (opts.language === "typescript") {
5352
// For typescript we need core, all services (for typings) and special packages like ts itself or node typings.
54-
const deps = [core, ...serviceDeps, ...(await genTypeScriptDependencies(nodecgDir))];
53+
const deps = [core, ...serviceDeps, ...(await genTypeScriptDependencies(opts))];
5554
deps.sort();
5655
return deps;
5756
} else {
@@ -65,16 +64,16 @@ async function genDependencies(opts: GenerationOptions, serviceDeps: Dependency[
6564
* and types for node.
6665
* @param nodecgDir the directory in which nodecg is installed. Used to get nodecg version which will be used by nodecg dependency.
6766
*/
68-
async function genTypeScriptDependencies(nodecgDir: string): Promise<Dependency[]> {
69-
logger.debug("Fetching latest typescript and @types/node versions...");
67+
async function genTypeScriptDependencies(opts: GenerationOptions): Promise<Dependency[]> {
68+
logger.debug(`Fetching latest ${opts.nodeeCGTypingsPackage}, typescript and @types/node versions...`);
7069
const [nodecgVersion, latestNodeTypes, latestTypeScript] = await Promise.all([
71-
getNodeCGVersion(nodecgDir),
70+
getLatestPackageVersion(opts.nodeeCGTypingsPackage),
7271
getLatestPackageVersion("@types/node"),
7372
getLatestPackageVersion("typescript"),
7473
]);
7574

7675
return [
77-
["nodecg", addSemverCaret(nodecgVersion)],
76+
[opts.nodeeCGTypingsPackage, addSemverCaret(nodecgVersion)],
7877
["@types/node", addSemverCaret(latestNodeTypes)],
7978
["typescript", addSemverCaret(latestTypeScript)],
8079
];

src/generate/prompt.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface PromptedGenerationOptions {
2828
export interface GenerationOptions extends PromptedGenerationOptions {
2929
servicePackages: NpmPackage[];
3030
corePackage: NpmPackage;
31+
nodeeCGTypingsPackage: "nodecg" | "nodecg-types";
3132
bundlePath: string;
3233
}
3334

@@ -169,5 +170,6 @@ export function computeGenOptsFields(
169170
return svcPackage;
170171
}),
171172
bundlePath: path.join(opts.bundleDir, opts.bundleName),
173+
nodeeCGTypingsPackage: install.version === "0.1" ? "nodecg" : "nodecg-types",
172174
};
173175
}

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
}

0 commit comments

Comments
 (0)