Merge pull request 'Strongly typed config (and ts strict mode)' (#1) from nea/amyjr:typed-config into main

Reviewed-on: https://git.amy.rip/amy/amyjr/pulls/1
This commit is contained in:
amy arson 2025-02-23 15:20:04 +00:00
commit a2cf556bcf
7 changed files with 31 additions and 16 deletions

View file

@ -1,7 +1,7 @@
import {ChatInputCommandInteraction, SharedSlashCommand} from "discord.js"; import {ChatInputCommandInteraction, SharedSlashCommand} from "discord.js";
import { Config } from "./config";
export class Command { export abstract class Command {
constructor(){} abstract run(interaction: ChatInputCommandInteraction, config: Config): Promise<void>;
async run (interaction: ChatInputCommandInteraction, config): Promise<void>{}; abstract slashCommand: SharedSlashCommand
slashCommand: SharedSlashCommand }
}

View file

@ -11,8 +11,9 @@ import {
} from "discord.js"; } from "discord.js";
import { getSongOnPreferredProvider } from "../helper.ts" import { getSongOnPreferredProvider } from "../helper.ts"
import { Config } from "../config.ts";
function keepV(url) { function keepV(url: string): string {
const urlObj = new URL(url); const urlObj = new URL(url);
const vParam = urlObj.searchParams.get("v"); const vParam = urlObj.searchParams.get("v");
@ -26,7 +27,7 @@ function keepV(url) {
} }
export default class PingCommand extends Command { export default class PingCommand extends Command {
async run(interaction: ChatInputCommandInteraction, config) { async run(interaction: ChatInputCommandInteraction, config: Config) {
await interaction.deferReply() await interaction.deferReply()
@ -76,4 +77,4 @@ export default class PingCommand extends Command {
InteractionContextType.Guild, InteractionContextType.Guild,
InteractionContextType.PrivateChannel InteractionContextType.PrivateChannel
]); ]);
} }

View file

@ -5,9 +5,10 @@ import {
InteractionContextType, InteractionContextType,
SlashCommandBuilder SlashCommandBuilder
} from "discord.js"; } from "discord.js";
import { Config } from "../config.ts";
export default class PingCommand extends Command { export default class PingCommand extends Command {
async run(interaction: ChatInputCommandInteraction, config) { async run(interaction: ChatInputCommandInteraction, config: Config) {
await interaction.reply({ await interaction.reply({
content: 'Pong!', content: 'Pong!',
}); });
@ -23,4 +24,4 @@ export default class PingCommand extends Command {
InteractionContextType.Guild, InteractionContextType.Guild,
InteractionContextType.PrivateChannel InteractionContextType.PrivateChannel
]); ]);
} }

View file

@ -6,9 +6,10 @@ import {
InteractionContextType, InteractionContextType,
SlashCommandBuilder SlashCommandBuilder
} from "discord.js"; } from "discord.js";
import { Config } from "../config.ts";
export default class PingCommand extends Command { export default class PingCommand extends Command {
async run(interaction: ChatInputCommandInteraction, config) { async run(interaction: ChatInputCommandInteraction, config: Config) {
const repo = interaction.options.getString("repo") const repo = interaction.options.getString("repo")
const meow = await fetch(config.gitapi + repo).then(res => res.json()); const meow = await fetch(config.gitapi + repo).then(res => res.json());
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
@ -38,4 +39,4 @@ export default class PingCommand extends Command {
InteractionContextType.Guild, InteractionContextType.Guild,
InteractionContextType.PrivateChannel InteractionContextType.PrivateChannel
]); ]);
} }

11
src/config.ts Normal file
View file

@ -0,0 +1,11 @@
import rawconfig from "../config.json" with {type: "json"};
import {z} from 'zod';
const configT = z.object({
token: z.string(),
listenbrainzAccount: z.string(),
gitapi: z.string(),
});
export type Config = z.infer<typeof configT>;
export const config: Config = configT.parse(rawconfig);

View file

@ -1,4 +1,3 @@
import config from "../config.json" with {type: "json"};
import { import {
Client, Client,
Events, Events,
@ -10,6 +9,7 @@ import path from "node:path";
import fs from "node:fs"; import fs from "node:fs";
import { Command } from "./command.ts"; import { Command } from "./command.ts";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import { config } from "./config.ts";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@ -36,7 +36,7 @@ client.once(Events.ClientReady, async () => {
console.log("Ready"); console.log("Ready");
const rest = new REST().setToken(config.token); const rest = new REST().setToken(config.token);
const data = await rest.put( const data = await rest.put(
Routes.applicationCommands(client.user.id), { body: commands.map(command => command.slashCommand.toJSON()) }, Routes.applicationCommands(client.user!.id), { body: commands.map(command => command.slashCommand.toJSON()) },
); );
// @ts-ignore // @ts-ignore
console.log(`Successfully reloaded ${data.length} application (/) commands.`); console.log(`Successfully reloaded ${data.length} application (/) commands.`);
@ -62,4 +62,4 @@ client.on(Events.InteractionCreate, async (interaction) => {
}) })
await client.login(config.token); await client.login(config.token);

View file

@ -8,7 +8,8 @@
"esModuleInterop": true, "esModuleInterop": true,
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"noEmit": true, "noEmit": true,
"forceConsistentCasingInFileNames": true "forceConsistentCasingInFileNames": true,
"strict": true
}, },
"ts-node": { "ts-node": {
"compilerOptions": { "compilerOptions": {