Skip to content

Commit

Permalink
refactor: replace io-ts with zod
Browse files Browse the repository at this point in the history
  • Loading branch information
Dragory committed Jan 14, 2024
1 parent fafaefa commit 2869296
Show file tree
Hide file tree
Showing 161 changed files with 1,454 additions and 2,109 deletions.
9 changes: 0 additions & 9 deletions backend/package-lock.json

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

1 change: 0 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
"express": "^4.17.0",
"fp-ts": "^2.0.1",
"humanize-duration": "^3.15.0",
"io-ts": "^2.0.0",
"js-yaml": "^3.13.1",
"knub": "^32.0.0-next.16",
"knub-command-manager": "^9.1.0",
Expand Down
2 changes: 1 addition & 1 deletion backend/src/commandTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { createTypeHelper } from "knub-command-manager";
import {
channelMentionRegex,
convertDelayStringToMS,
inputPatternToRegExp,
isValidSnowflake,
resolveMember,
resolveUser,
Expand All @@ -26,7 +27,6 @@ import {
} from "./utils";
import { isValidTimezone } from "./utils/isValidTimezone";
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
import { inputPatternToRegExp } from "./validatorUtils";

export const commandTypes = {
...messageCommandBaseTypeConverters,
Expand Down
16 changes: 9 additions & 7 deletions backend/src/configValidator.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { ConfigValidationError, PluginConfigManager } from "knub";
import { PluginConfigManager } from "knub";
import moment from "moment-timezone";
import { ZodError } from "zod";
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
import { guildPlugins } from "./plugins/availablePlugins";
import { PartialZeppelinGuildConfigSchema, ZeppelinGuildConfig } from "./types";
import { StrictValidationError, decodeAndValidateStrict } from "./validatorUtils";
import { ZeppelinGuildConfig, zZeppelinGuildConfig } from "./types";

const pluginNameToPlugin = new Map<string, ZeppelinPlugin>();
for (const plugin of guildPlugins) {
pluginNameToPlugin.set(plugin.name, plugin);
}

export async function validateGuildConfig(config: any): Promise<string | null> {
const validationResult = decodeAndValidateStrict(PartialZeppelinGuildConfigSchema, config);
if (validationResult instanceof StrictValidationError) return validationResult.getErrors();
const validationResult = zZeppelinGuildConfig.safeParse(config);
if (!validationResult.success) {
return validationResult.error.issues.join("\n");
}

const guildConfig = config as ZeppelinGuildConfig;

Expand Down Expand Up @@ -41,8 +43,8 @@ export async function validateGuildConfig(config: any): Promise<string | null> {
try {
await configManager.init();
} catch (err) {
if (err instanceof ConfigValidationError || err instanceof StrictValidationError) {
return `${pluginName}: ${err.message}`;
if (err instanceof ZodError) {
return `${pluginName}: ${err.issues.join("\n")}`;
}

throw err;
Expand Down
48 changes: 2 additions & 46 deletions backend/src/pluginUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,18 @@ import {
PermissionsBitField,
TextBasedChannel,
} from "discord.js";
import * as t from "io-ts";
import {
AnyPluginData,
CommandContext,
ConfigValidationError,
ExtendedMatchParams,
GuildPluginData,
PluginOverrideCriteria,
helpers,
helpers
} from "knub";
import { logger } from "./logger";
import { isStaff } from "./staff";
import { TZeppelinKnub } from "./types";
import { errorMessage, successMessage, tNullable } from "./utils";
import { errorMessage, successMessage } from "./utils";
import { Tail } from "./utils/typeUtils";
import { StrictValidationError, parseIoTsSchema } from "./validatorUtils";

const { getMemberLevel } = helpers;

Expand Down Expand Up @@ -59,46 +55,6 @@ export async function hasPermission(
return helpers.hasPermission(config, permission);
}

const PluginOverrideCriteriaType: t.Type<PluginOverrideCriteria<unknown>> = t.recursion(
"PluginOverrideCriteriaType",
() =>
t.partial({
channel: tNullable(t.union([t.string, t.array(t.string)])),
category: tNullable(t.union([t.string, t.array(t.string)])),
level: tNullable(t.union([t.string, t.array(t.string)])),
user: tNullable(t.union([t.string, t.array(t.string)])),
role: tNullable(t.union([t.string, t.array(t.string)])),

all: tNullable(t.array(PluginOverrideCriteriaType)),
any: tNullable(t.array(PluginOverrideCriteriaType)),
not: tNullable(PluginOverrideCriteriaType),

extra: t.unknown,
}),
);

export function strictValidationErrorToConfigValidationError(err: StrictValidationError) {
return new ConfigValidationError(
err
.getErrors()
.map((e) => e.toString())
.join("\n"),
);
}

export function makeIoTsConfigParser<Schema extends t.Type<any>>(schema: Schema): (input: unknown) => t.TypeOf<Schema> {
return (input: unknown) => {
try {
return parseIoTsSchema(schema, input);
} catch (err) {
if (err instanceof StrictValidationError) {
throw strictValidationErrorToConfigValidationError(err);
}
throw err;
}
};
}

export async function sendSuccessMessage(
pluginData: AnyPluginData<any>,
channel: TextBasedChannel,
Expand Down
7 changes: 3 additions & 4 deletions backend/src/plugins/AutoDelete/AutoDeletePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { PluginOptions } from "knub";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { makeIoTsConfigParser } from "../../pluginUtils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AutoDeletePluginType, ConfigSchema } from "./types";
import { AutoDeletePluginType, zAutoDeleteConfig } from "./types";
import { onMessageCreate } from "./util/onMessageCreate";
import { onMessageDelete } from "./util/onMessageDelete";
import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk";
Expand All @@ -24,11 +23,11 @@ export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()({
prettyName: "Auto-delete",
description: "Allows Zeppelin to auto-delete messages from a channel after a delay",
configurationGuide: "Maximum deletion delay is currently 5 minutes",
configSchema: ConfigSchema,
configSchema: zAutoDeleteConfig,
},

dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configParser: makeIoTsConfigParser(ConfigSchema),
configParser: (input) => zAutoDeleteConfig.parse(input),
defaultOptions,

beforeLoad(pluginData) {
Expand Down
13 changes: 6 additions & 7 deletions backend/src/plugins/AutoDelete/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as t from "io-ts";
import { BasePluginType } from "knub";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { SavedMessage } from "../../data/entities/SavedMessage";
import { MINUTES, tDelayString } from "../../utils";
import { MINUTES, zDelayString } from "../../utils";
import Timeout = NodeJS.Timeout;
import z from "zod";

export const MAX_DELAY = 5 * MINUTES;

Expand All @@ -13,14 +13,13 @@ export interface IDeletionQueueItem {
message: SavedMessage;
}

export const ConfigSchema = t.type({
enabled: t.boolean,
delay: tDelayString,
export const zAutoDeleteConfig = z.strictObject({
enabled: z.boolean(),
delay: zDelayString,
});
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;

export interface AutoDeletePluginType extends BasePluginType {
config: TConfigSchema;
config: z.output<typeof zAutoDeleteConfig>;
state: {
guildSavedMessages: GuildSavedMessages;
guildLogs: GuildLogs;
Expand Down
7 changes: 3 additions & 4 deletions backend/src/plugins/AutoReactions/AutoReactionsPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { PluginOptions } from "knub";
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { makeIoTsConfigParser } from "../../pluginUtils";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd";
import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd";
import { AddReactionsEvt } from "./events/AddReactionsEvt";
import { AutoReactionsPluginType, ConfigSchema } from "./types";
import { AutoReactionsPluginType, zAutoReactionsConfig } from "./types";

const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
config: {
Expand All @@ -32,15 +31,15 @@ export const AutoReactionsPlugin = zeppelinGuildPlugin<AutoReactionsPluginType>(
description: trimPluginDescription(`
Allows setting up automatic reactions to all new messages on a channel
`),
configSchema: ConfigSchema,
configSchema: zAutoReactionsConfig,
},

// prettier-ignore
dependencies: () => [
LogsPlugin,
],

configParser: makeIoTsConfigParser(ConfigSchema),
configParser: (input) => zAutoReactionsConfig.parse(input),
defaultOptions,

// prettier-ignore
Expand Down
9 changes: 4 additions & 5 deletions backend/src/plugins/AutoReactions/types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import * as t from "io-ts";
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
import z from "zod";
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { AutoReaction } from "../../data/entities/AutoReaction";

export const ConfigSchema = t.type({
can_manage: t.boolean,
export const zAutoReactionsConfig = z.strictObject({
can_manage: z.boolean(),
});
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;

export interface AutoReactionsPluginType extends BasePluginType {
config: TConfigSchema;
config: z.output<typeof zAutoReactionsConfig>;
state: {
logs: GuildLogs;
savedMessages: GuildSavedMessages;
Expand Down
Loading

0 comments on commit 2869296

Please sign in to comment.