Skip to content

Commit

Permalink
[bin] Remove yargs in favor of cmd-ts.
Browse files Browse the repository at this point in the history
  • Loading branch information
lgarron committed Oct 29, 2024
1 parent 013ffc4 commit b049e8f
Show file tree
Hide file tree
Showing 7 changed files with 366 additions and 291 deletions.
Binary file modified bun.lockb
Binary file not shown.
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"dependencies": {
"@types/three": "^0.169.0",
"@types/web-bluetooth": "^0.0.20",
"cmd-ts": "^0.13.0",
"comlink": "^4.4.1",
"random-uint-below": "v3.3.0",
"three": "^0.169.0"
Expand All @@ -69,7 +70,6 @@
"@types/dom-speech-recognition": "^0.0.4",
"@types/mocha": "^10.0.8",
"@types/node": "^22.7.4",
"@types/yargs": "^17.0.33",
"@web/dev-server-esbuild": "^1.0.2",
"@web/test-runner": "^0.19.0",
"@web/test-runner-playwright": "^0.11.0",
Expand All @@ -82,16 +82,15 @@
"playwright": "^1.47.2",
"tsup": "^8.3.0",
"typedoc": "^0.26.7",
"typescript": "^5.6.2",
"yargs": "^17.7.2"
"typescript": "^5.6.2"
},
"minimalDevDependencies": [
"getbuiltinmodule-ponyfill",
"barely-a-dev-server",
"esbuild",
"jszip",
"@biomejs/biome",
"yargs"
"cmd-ts"
],
"engines": {
"node": ">=20.16.0",
Expand Down
275 changes: 158 additions & 117 deletions script/bin/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,130 +5,171 @@
*
* */

import {
binary,
number as cmdNumber,
string as cmdString,
command,
flag,
oneOf,
option,
optional,
positional,
run,
type Type,
} from "cmd-ts";
import { Alg } from "cubing/alg";

// We would use named imports, but that doesn't seem to be an option.
import { visualizationFormats } from "cubing/twisty/model/props/viewer/VisualizationProp.js";
import { chromium } from "playwright";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import type { TwistyPlayerConfig } from "../../src/cubing/twisty/index.js";
import type {
PuzzleID,
TwistyPlayerConfig,
VisualizationFormat,
} from "../../src/cubing/twisty/index.js";
import { startServer } from "../lib/experiments-server/index.js";

const DEBUG = false;
const PAGE_URL =
"http://localhost:4443/experiments.cubing.net/cubing.js/screenshot/";

startServer();

const args = (yargs as any)(hideBin(process.argv))
.command(
"[alg]",
"Screenshot an alg. (You can specify an empty alg string.)",
() => {},
(argv: string[]) => {
console.info(argv);
},
)
.option("puzzle", {
fill: "string",
})
.option("stickering", {
fill: "string",
})
.option("anchor", {
fill: "string",
choices: ["start", "end"],
})
.option("hint-facelets", {
fill: "string",
choices: ["none", "floating"],
})
.option("visualization", {
fill: "string",
})
.option("debug", {
fill: "boolean",
})
.option("out-file", {
fill: "string",
})
.option("width", {
fill: "number",
default: 2048,
})
.option("height", {
fill: "number",
default: null,
description: "Defaults to width",
})
.option("camera-latitude", {
fill: "number",
})
.option("camera-longitude", {
fill: "number",
})
.strictOptions()
.demandCommand(1).argv as any;

args.alg = args._[0];

const options: TwistyPlayerConfig = {
alg: args.alg,
puzzle: args.puzzle,
experimentalStickering: args.stickering,
experimentalSetupAnchor: args.anchor,
hintFacelets: args["hint-facelets"],
visualization: args.visualization,
cameraLatitudeLimit: 90,
// TODO: dedup with `order` implementation.
const ReadAlg: Type<string, Alg> = {
async from(str) {
return Alg.fromString(str);
},
};

if ("camera-latitude" in args) {
options.cameraLatitude = args["camera-latitude"];
}
if ("camera-longitude" in args) {
options.cameraLongitude = args["camera-longitude"];
}

for (const key in options) {
if (typeof (options as any)[key] === "undefined") {
delete (options as any)[key];
}
}

console.log(options);

options.background = "none";
options.controlPanel = "none";

(async () => {
const browser = await chromium.launch({ headless: !DEBUG });
const context = await browser.newContext();
const page = await context.newPage();
const height = args["height"] ?? args["width"];
page.setViewportSize({
width: args["width"],
height,
});

const url = new URL(PAGE_URL);
url.searchParams.set("options", JSON.stringify(options));

if (args.debug) {
console.log(url.toString());
}

await page.goto(url.toString());
const path = args["out-file"] ?? `${args.alg ?? "puzzle"}.png`;
console.log("Output file:", path);

await page.waitForSelector("#screenshot");

await page.screenshot({
path,
omitBackground: true,
fullPage: true,
});

if (!DEBUG) {
await browser.close();
process.exit(0);
}
})();
const anchorValues = ["start", "end"] as const;
const hintFaceletOptions = ["none", "floating"] as const;

const app = command({
name: "screenshot",
description: "Screenshot an alg. (You can specify an empty alg string.)",
args: {
alg: positional({
type: ReadAlg,
displayName: "Puzzle geometry ID",
}),
puzzle: option({
type: optional(cmdString),
long: "puzzle",
}),
stickering: option({
type: optional(cmdString),
long: "stickering",
}),
anchor: option({
type: optional(oneOf(anchorValues)),
long: "anchor",
}),
hintFacelets: option({
type: optional(oneOf(hintFaceletOptions)),
long: "hint-facelets",
}),
visualization: option({
type: optional(oneOf(Object.keys(visualizationFormats))),
long: "visualization",
}),
debug: flag({
long: "debug",
}),
outFile: option({
// TODO: implement a file path that does *not* exist: https://cmd-ts.vercel.app/batteries_file_system.html
type: optional(cmdString),
long: "out-file",
}),
width: option({
type: cmdNumber,
long: "width",
defaultValue: () => 2048,
defaultValueIsSerializable: true,
}),
height: option({
description: "Defaults to width",
type: optional(cmdNumber),
long: "height",
}),
cameraLatitude: option({
type: optional(cmdNumber),
long: "camera-latitude",
}),
cameraLongitude: option({
type: optional(cmdNumber),
long: "camera-longitude",
}),
},
handler: async (args) => {
startServer();

// The `alg` field needs to be a string to be serializable.
// Note that `TwistyPlayerConfig & Record<string, string | number>` does not work here.
// TODO: Introduce a `SerializableTwistyPlayerConfig` type?
const options: TwistyPlayerConfig & { alg: string } = {
alg: args.alg.toString(),
puzzle: args.puzzle as PuzzleID, // TODO
experimentalStickering: args.stickering,
experimentalSetupAnchor: args.anchor,
hintFacelets: args.hintFacelets,
visualization: args.visualization as VisualizationFormat,
cameraLatitudeLimit: 90,
};

// TODO: can we inline these above?
if ("cameraLatitude" in args) {
options.cameraLatitude = args.cameraLatitude;
}
if ("cameraLongitude" in args) {
options.cameraLongitude = args.cameraLongitude;
}

for (const key in options) {
if (typeof (options as any)[key] === "undefined") {
delete (options as any)[key];
}
}

console.log(options);

options.background = "none";
options.controlPanel = "none";

await (async () => {
const browser = await chromium.launch({ headless: !DEBUG });
const context = await browser.newContext();
const page = await context.newPage();
const height = args.height ?? args.width;
page.setViewportSize({
width: args.width,
height,
});

const url = new URL(PAGE_URL);
url.searchParams.set("options", JSON.stringify(options));

if (args.debug) {
console.log(url.toString());
}

await page.goto(url.toString());
const path = args.outFile ?? `${args.alg ?? "puzzle"}.png`;
console.log("Output file:", path);

await page.waitForSelector("#screenshot");

await page.screenshot({
path,
omitBackground: true,
fullPage: true,
});

if (!DEBUG) {
await browser.close();
process.exit(0);
}
})();
},
});

await run(binary(app), process.argv);
8 changes: 4 additions & 4 deletions script/test/src/import-restrictions/allowedImports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ export const mainAllowedImports: AllowedImports = {
"esbuild",
"node-fetch",
"playwright",
"yargs",
"cmd-ts",
],
dynamic: ["cubing", "node:repl"],
},
// src/bin
"src/bin": {
static: ["cubing"],
static: ["cubing", "cmd-ts"],
},
"src/bin/scramble.ts": {
static: ["src/cubing"],
dynamic: ["yargs"],
static: ["cmd-ts", "src/cubing"],
dynamic: ["cmd-ts"],
},
// src/lib
"src/cubing/alg": {},
Expand Down
Loading

0 comments on commit b049e8f

Please sign in to comment.