Skip to content

Commit

Permalink
Support setting NACP metadata properties via the "nacp" object in `pa…
Browse files Browse the repository at this point in the history
…ckage.json`
  • Loading branch information
TooTallNate committed Dec 9, 2024
1 parent f2e4925 commit e35eb23
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 41 deletions.
7 changes: 7 additions & 0 deletions .changeset/ten-bears-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@nx.js/patch-nacp": major
"@nx.js/nro": patch
"@nx.js/nsp": patch
---

Support setting NACP metadata properties via the "nacp" object in `package.json`
4 changes: 2 additions & 2 deletions packages/nro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
"license": "MIT",
"dependencies": {
"@nx.js/patch-nacp": "0.1.0",
"@tootallnate/nacp": "^0.1.0",
"@tootallnate/nro": "^0.1.1",
"@tootallnate/nacp": "^0.2.0",
"@tootallnate/nro": "^0.1.2",
"@tootallnate/romfs": "^0.1.0",
"bytes": "^3.1.2",
"chalk": "^5.3.0",
Expand Down
22 changes: 14 additions & 8 deletions packages/nro/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,27 @@ console.log(` JPEG size: ${bytes(logoBuf.length).toLowerCase()}`);
console.log(await terminalImage.buffer(logoBuf, { height: 18 }));

// NACP
const nacp = new NACP(await nxjsNro.nacp!.arrayBuffer());
const packageJson = patchNACP(nacp, new URL('package.json', appRoot));
const originalNacp = new NACP(await nxjsNro.nacp!.arrayBuffer());
const nacp = new NACP(originalNacp.buffer.slice(0));
const { packageJson, updated, warnings } = patchNACP(
nacp,
new URL('package.json', appRoot),
);
console.log();
console.log(chalk.bold('Setting metadata:'));
console.log(` ID: ${chalk.green(nacp.id.toString(16).padStart(16, '0'))}`);
console.log(` Title: ${chalk.green(nacp.title)}`);
console.log(` Version: ${chalk.green(nacp.version)}`);
console.log(` Author: ${chalk.green(nacp.author)}`);
console.log(chalk.bold('NACP Metadata:'));
for (const warning of warnings) {
console.log(chalk.yellow(`⚠️ ${warning}`));
}
for (const [k, v] of updated) {
console.log(` ${chalk.green(k)}: ${v}`);
}

// RomFS
const romfsDir = new URL('romfs/', appRoot);
const romfsDirPath = fileURLToPath(romfsDir);
const romfs = await RomFS.decode(nxjsNro.romfs!);
console.log();
console.log(chalk.bold('Adding RomFS files:'));
console.log(chalk.bold('RomFS Files:'));

function walk(dir: URL, dirEntry: RomFS.RomFsEntry) {
for (const name of readdirSync(dir)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/nsp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"license": "MIT",
"dependencies": {
"@nx.js/patch-nacp": "0.1.0",
"@tootallnate/nacp": "^0.1.0",
"@tootallnate/nacp": "^0.2.0",
"bytes": "^3.1.2",
"chalk": "^5.3.0",
"jimp": "^1.6.0",
Expand Down
17 changes: 11 additions & 6 deletions packages/nsp/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,20 @@ try {
throw err;
}

const packageJson = patchNACP(nacp, new URL('package.json', appRoot));
const { packageJson, updated, warnings } = patchNACP(
nacp,
new URL('package.json', appRoot),
);
writeFileSync(new URL('control.nacp', controlDir), Buffer.from(nacp.buffer));
const titleid = nacp.id.toString(16).padStart(16, '0');
console.log();
console.log(chalk.bold('Setting metadata:'));
console.log(` ID: ${chalk.green(titleid)}`);
console.log(` Title: ${chalk.green(nacp.title)}`);
console.log(` Version: ${chalk.green(nacp.version)}`);
console.log(` Author: ${chalk.green(nacp.author)}`);
console.log(chalk.bold('NACP Metadata:'));
for (const warning of warnings) {
console.log(chalk.yellow(`⚠️ ${warning}`));
}
for (const [k, v] of updated) {
console.log(` ${chalk.green(k)}: ${v}`);
}

// RomFS
for (const file of readdirSync(baseRomfsDir)) {
Expand Down
7 changes: 4 additions & 3 deletions packages/patch-nacp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
"author": "Nathan Rajlich <[email protected]>",
"license": "MIT",
"dependencies": {
"@tootallnate/nacp": "^0.2.0",
"parse-author": "^2.0.0",
"title-case": "^4.3.2",
"types-package-json": "^2.0.39"
},
"devDependencies": {
"@tootallnate/nacp": "^0.1.0",
"@types/parse-author": "^2.0.3",
"@types/node": "^20.10.3"
"@types/node": "^20.10.3",
"@types/parse-author": "^2.0.3"
}
}
68 changes: 61 additions & 7 deletions packages/patch-nacp/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import parseAuthor from 'parse-author';
import { readFileSync } from 'node:fs';
import type { NACP } from '@tootallnate/nacp';
import { NACP } from '@tootallnate/nacp';
import { titleCase } from 'title-case';
import type { PackageJson as BasePackageJson } from 'types-package-json';

export type PackageJsonNacp = Omit<NACP, 'buffer'>;

export interface PackageJson extends BasePackageJson {
titleId?: string;
productName?: string;
nacp?: PackageJsonNacp;
}

const VALID_NACP_PROPERTIES = Object.getOwnPropertyNames(NACP.prototype);

export function patchNACP(nacp: NACP, packageJsonUrl: URL) {
const warnings: string[] = [];
const updated = new Map<string, string>();
const packageJsonStr = readFileSync(packageJsonUrl, 'utf8');
const packageJson: PackageJson = JSON.parse(packageJsonStr);
const {
Expand All @@ -17,13 +25,59 @@ export function patchNACP(nacp: NACP, packageJsonUrl: URL) {
productName,
version,
author: rawAuthor,
nacp: pkgNacp = {},
} = packageJson;

if (titleId) {
warnings.push(
'The "titleId" property is deprecated. Use "nacp.id" instead.',
);
nacp.id = titleId;
updated.set('ID', titleId);
}

const title = productName || name;
if (title) {
if (productName) {
warnings.push(
'The "productName" property is deprecated. Use "nacp.title" instead.',
);
}
updated.set('Title', title);
nacp.title = title;
}

if (version) {
nacp.version = version;
updated.set('Version', version);
}

const author =
typeof rawAuthor === 'string' ? parseAuthor(rawAuthor) : rawAuthor;
if (titleId) nacp.id = titleId;
const title = productName || name;
if (title) nacp.title = title;
if (version) nacp.version = version;
if (author?.name) nacp.author = author.name;
return packageJson;
if (author?.name) {
nacp.author = author.name;
updated.set('Author', author.name);
}

for (const [k, v] of Object.entries(pkgNacp)) {
if (!VALID_NACP_PROPERTIES.includes(k)) {
warnings.push(`Ignoring invalid NACP property: ${JSON.stringify(k)}`);
continue;
}

// @ts-expect-error
const oldValue = nacp[k];
// @ts-expect-error
nacp[k] = v;
// @ts-expect-error
const newValue = nacp[k];

if (newValue !== oldValue) {
const titleCased =
k === 'id' ? 'ID' : titleCase(k.replace(/([A-Z])/g, ' $1'));
updated.set(titleCased, newValue);
}
}

return { packageJson, updated, warnings };
}
36 changes: 22 additions & 14 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e35eb23

Please sign in to comment.