Skip to content

Commit e35eb23

Browse files
committed
Support setting NACP metadata properties via the "nacp" object in package.json
1 parent f2e4925 commit e35eb23

File tree

8 files changed

+122
-41
lines changed

8 files changed

+122
-41
lines changed

.changeset/ten-bears-explain.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@nx.js/patch-nacp": major
3+
"@nx.js/nro": patch
4+
"@nx.js/nsp": patch
5+
---
6+
7+
Support setting NACP metadata properties via the "nacp" object in `package.json`

packages/nro/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"license": "MIT",
2626
"dependencies": {
2727
"@nx.js/patch-nacp": "0.1.0",
28-
"@tootallnate/nacp": "^0.1.0",
29-
"@tootallnate/nro": "^0.1.1",
28+
"@tootallnate/nacp": "^0.2.0",
29+
"@tootallnate/nro": "^0.1.2",
3030
"@tootallnate/romfs": "^0.1.0",
3131
"bytes": "^3.1.2",
3232
"chalk": "^5.3.0",

packages/nro/src/main.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,27 @@ console.log(` JPEG size: ${bytes(logoBuf.length).toLowerCase()}`);
5252
console.log(await terminalImage.buffer(logoBuf, { height: 18 }));
5353

5454
// NACP
55-
const nacp = new NACP(await nxjsNro.nacp!.arrayBuffer());
56-
const packageJson = patchNACP(nacp, new URL('package.json', appRoot));
55+
const originalNacp = new NACP(await nxjsNro.nacp!.arrayBuffer());
56+
const nacp = new NACP(originalNacp.buffer.slice(0));
57+
const { packageJson, updated, warnings } = patchNACP(
58+
nacp,
59+
new URL('package.json', appRoot),
60+
);
5761
console.log();
58-
console.log(chalk.bold('Setting metadata:'));
59-
console.log(` ID: ${chalk.green(nacp.id.toString(16).padStart(16, '0'))}`);
60-
console.log(` Title: ${chalk.green(nacp.title)}`);
61-
console.log(` Version: ${chalk.green(nacp.version)}`);
62-
console.log(` Author: ${chalk.green(nacp.author)}`);
62+
console.log(chalk.bold('NACP Metadata:'));
63+
for (const warning of warnings) {
64+
console.log(chalk.yellow(`⚠️ ${warning}`));
65+
}
66+
for (const [k, v] of updated) {
67+
console.log(` ${chalk.green(k)}: ${v}`);
68+
}
6369

6470
// RomFS
6571
const romfsDir = new URL('romfs/', appRoot);
6672
const romfsDirPath = fileURLToPath(romfsDir);
6773
const romfs = await RomFS.decode(nxjsNro.romfs!);
6874
console.log();
69-
console.log(chalk.bold('Adding RomFS files:'));
75+
console.log(chalk.bold('RomFS Files:'));
7076

7177
function walk(dir: URL, dirEntry: RomFS.RomFsEntry) {
7278
for (const name of readdirSync(dir)) {

packages/nsp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"license": "MIT",
3232
"dependencies": {
3333
"@nx.js/patch-nacp": "0.1.0",
34-
"@tootallnate/nacp": "^0.1.0",
34+
"@tootallnate/nacp": "^0.2.0",
3535
"bytes": "^3.1.2",
3636
"chalk": "^5.3.0",
3737
"jimp": "^1.6.0",

packages/nsp/src/main.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,20 @@ try {
100100
throw err;
101101
}
102102

103-
const packageJson = patchNACP(nacp, new URL('package.json', appRoot));
103+
const { packageJson, updated, warnings } = patchNACP(
104+
nacp,
105+
new URL('package.json', appRoot),
106+
);
104107
writeFileSync(new URL('control.nacp', controlDir), Buffer.from(nacp.buffer));
105108
const titleid = nacp.id.toString(16).padStart(16, '0');
106109
console.log();
107-
console.log(chalk.bold('Setting metadata:'));
108-
console.log(` ID: ${chalk.green(titleid)}`);
109-
console.log(` Title: ${chalk.green(nacp.title)}`);
110-
console.log(` Version: ${chalk.green(nacp.version)}`);
111-
console.log(` Author: ${chalk.green(nacp.author)}`);
110+
console.log(chalk.bold('NACP Metadata:'));
111+
for (const warning of warnings) {
112+
console.log(chalk.yellow(`⚠️ ${warning}`));
113+
}
114+
for (const [k, v] of updated) {
115+
console.log(` ${chalk.green(k)}: ${v}`);
116+
}
112117

113118
// RomFS
114119
for (const file of readdirSync(baseRomfsDir)) {

packages/patch-nacp/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
"author": "Nathan Rajlich <[email protected]>",
1717
"license": "MIT",
1818
"dependencies": {
19+
"@tootallnate/nacp": "^0.2.0",
1920
"parse-author": "^2.0.0",
21+
"title-case": "^4.3.2",
2022
"types-package-json": "^2.0.39"
2123
},
2224
"devDependencies": {
23-
"@tootallnate/nacp": "^0.1.0",
24-
"@types/parse-author": "^2.0.3",
25-
"@types/node": "^20.10.3"
25+
"@types/node": "^20.10.3",
26+
"@types/parse-author": "^2.0.3"
2627
}
2728
}

packages/patch-nacp/src/index.ts

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
import parseAuthor from 'parse-author';
22
import { readFileSync } from 'node:fs';
3-
import type { NACP } from '@tootallnate/nacp';
3+
import { NACP } from '@tootallnate/nacp';
4+
import { titleCase } from 'title-case';
45
import type { PackageJson as BasePackageJson } from 'types-package-json';
56

7+
export type PackageJsonNacp = Omit<NACP, 'buffer'>;
8+
69
export interface PackageJson extends BasePackageJson {
710
titleId?: string;
811
productName?: string;
12+
nacp?: PackageJsonNacp;
913
}
1014

15+
const VALID_NACP_PROPERTIES = Object.getOwnPropertyNames(NACP.prototype);
16+
1117
export function patchNACP(nacp: NACP, packageJsonUrl: URL) {
18+
const warnings: string[] = [];
19+
const updated = new Map<string, string>();
1220
const packageJsonStr = readFileSync(packageJsonUrl, 'utf8');
1321
const packageJson: PackageJson = JSON.parse(packageJsonStr);
1422
const {
@@ -17,13 +25,59 @@ export function patchNACP(nacp: NACP, packageJsonUrl: URL) {
1725
productName,
1826
version,
1927
author: rawAuthor,
28+
nacp: pkgNacp = {},
2029
} = packageJson;
30+
31+
if (titleId) {
32+
warnings.push(
33+
'The "titleId" property is deprecated. Use "nacp.id" instead.',
34+
);
35+
nacp.id = titleId;
36+
updated.set('ID', titleId);
37+
}
38+
39+
const title = productName || name;
40+
if (title) {
41+
if (productName) {
42+
warnings.push(
43+
'The "productName" property is deprecated. Use "nacp.title" instead.',
44+
);
45+
}
46+
updated.set('Title', title);
47+
nacp.title = title;
48+
}
49+
50+
if (version) {
51+
nacp.version = version;
52+
updated.set('Version', version);
53+
}
54+
2155
const author =
2256
typeof rawAuthor === 'string' ? parseAuthor(rawAuthor) : rawAuthor;
23-
if (titleId) nacp.id = titleId;
24-
const title = productName || name;
25-
if (title) nacp.title = title;
26-
if (version) nacp.version = version;
27-
if (author?.name) nacp.author = author.name;
28-
return packageJson;
57+
if (author?.name) {
58+
nacp.author = author.name;
59+
updated.set('Author', author.name);
60+
}
61+
62+
for (const [k, v] of Object.entries(pkgNacp)) {
63+
if (!VALID_NACP_PROPERTIES.includes(k)) {
64+
warnings.push(`Ignoring invalid NACP property: ${JSON.stringify(k)}`);
65+
continue;
66+
}
67+
68+
// @ts-expect-error
69+
const oldValue = nacp[k];
70+
// @ts-expect-error
71+
nacp[k] = v;
72+
// @ts-expect-error
73+
const newValue = nacp[k];
74+
75+
if (newValue !== oldValue) {
76+
const titleCased =
77+
k === 'id' ? 'ID' : titleCase(k.replace(/([A-Z])/g, ' $1'));
78+
updated.set(titleCased, newValue);
79+
}
80+
}
81+
82+
return { packageJson, updated, warnings };
2983
}

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)