3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00

Typing fixes; show last reload time in !about

This commit is contained in:
Dragory 2019-07-22 00:09:45 +03:00
parent 2ff93f71db
commit 3e0498f96b
26 changed files with 154 additions and 75 deletions

View file

@ -21,7 +21,7 @@ export class AutoReactionsPlugin extends ZeppelinPlugin<TConfigSchema> {
private onMessageCreateFn; private onMessageCreateFn;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_manage: false, can_manage: false,

View file

@ -10,10 +10,11 @@ import { IPluginOptions } from "knub";
import { GuildLogs } from "../data/GuildLogs"; import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType"; import { LogType } from "../data/LogType";
import * as t from "io-ts"; import * as t from "io-ts";
import { tNullable } from "../utils";
const ConfigSchema = t.type({ const ConfigSchema = t.type({
log_automatic_actions: t.boolean, log_automatic_actions: t.boolean,
case_log_channel: t.string, case_log_channel: tNullable(t.string),
}); });
type TConfigSchema = t.TypeOf<typeof ConfigSchema>; type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
@ -50,7 +51,7 @@ export class CasesPlugin extends ZeppelinPlugin<TConfigSchema> {
protected archives: GuildArchives; protected archives: GuildArchives;
protected logs: GuildLogs; protected logs: GuildLogs;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
log_automatic_actions: true, log_automatic_actions: true,

View file

@ -9,6 +9,7 @@ import {
getInviteCodesInString, getInviteCodesInString,
getUrlsInString, getUrlsInString,
stripObjectToScalars, stripObjectToScalars,
tNullable,
} from "../utils"; } from "../utils";
import { ZalgoRegex } from "../data/Zalgo"; import { ZalgoRegex } from "../data/Zalgo";
import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { GuildSavedMessages } from "../data/GuildSavedMessages";
@ -20,17 +21,17 @@ import * as t from "io-ts";
const ConfigSchema = t.type({ const ConfigSchema = t.type({
filter_zalgo: t.boolean, filter_zalgo: t.boolean,
filter_invites: t.boolean, filter_invites: t.boolean,
invite_guild_whitelist: t.array(t.string), invite_guild_whitelist: tNullable(t.array(t.string)),
invite_guild_blacklist: t.array(t.string), invite_guild_blacklist: tNullable(t.array(t.string)),
invite_code_whitelist: t.array(t.string), invite_code_whitelist: tNullable(t.array(t.string)),
invite_code_blacklist: t.array(t.string), invite_code_blacklist: tNullable(t.array(t.string)),
allow_group_dm_invites: t.boolean, allow_group_dm_invites: t.boolean,
filter_domains: t.boolean, filter_domains: t.boolean,
domain_whitelist: t.array(t.string), domain_whitelist: tNullable(t.array(t.string)),
domain_blacklist: t.array(t.string), domain_blacklist: tNullable(t.array(t.string)),
blocked_tokens: t.array(t.string), blocked_tokens: tNullable(t.array(t.string)),
blocked_words: t.array(t.string), blocked_words: tNullable(t.array(t.string)),
blocked_regex: t.array(t.string), blocked_regex: tNullable(t.array(t.string)),
}); });
type TConfigSchema = t.TypeOf<typeof ConfigSchema>; type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
@ -43,7 +44,7 @@ export class CensorPlugin extends ZeppelinPlugin<TConfigSchema> {
private onMessageCreateFn; private onMessageCreateFn;
private onMessageUpdateFn; private onMessageUpdateFn;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
filter_zalgo: false, filter_zalgo: false,

View file

@ -25,7 +25,7 @@ export class CompanionChannelPlugin extends ZeppelinPlugin<TConfigSchema> {
companionChannels: Map<string, TCompanionChannel> = new Map(); companionChannels: Map<string, TCompanionChannel> = new Map();
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
channels: {}, channels: {},

View file

@ -75,7 +75,7 @@ export class CustomEventsPlugin extends ZeppelinPlugin<TConfigSchema> {
private clearTriggers: () => void; private clearTriggers: () => void;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
events: {}, events: {},

View file

@ -23,7 +23,7 @@ export class LocatePlugin extends ZeppelinPlugin<TConfigSchema> {
private outdatedAlertsTimeout; private outdatedAlertsTimeout;
private usersWithAlerts: string[] = []; private usersWithAlerts: string[] = [];
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_where: false, can_where: false,

View file

@ -71,7 +71,7 @@ export class LogsPlugin extends ZeppelinPlugin<TConfigSchema> {
private excludedUserProps = ["user", "member", "mod"]; private excludedUserProps = ["user", "member", "mod"];
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
channels: {}, channels: {},

View file

@ -16,7 +16,7 @@ export class MessageSaverPlugin extends ZeppelinPlugin<TConfigSchema> {
protected savedMessages: GuildSavedMessages; protected savedMessages: GuildSavedMessages;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_manage: false, can_manage: false,

View file

@ -13,6 +13,7 @@ import {
NotifyUserStatus, NotifyUserStatus,
stripObjectToScalars, stripObjectToScalars,
successMessage, successMessage,
tNullable,
trimLines, trimLines,
ucfirst, ucfirst,
UnknownUser, UnknownUser,
@ -35,12 +36,12 @@ const ConfigSchema = t.type({
message_on_warn: t.boolean, message_on_warn: t.boolean,
message_on_kick: t.boolean, message_on_kick: t.boolean,
message_on_ban: t.boolean, message_on_ban: t.boolean,
message_channel: t.string, message_channel: tNullable(t.string),
warn_message: t.string, warn_message: tNullable(t.string),
kick_message: t.string, kick_message: tNullable(t.string),
ban_message: t.string, ban_message: tNullable(t.string),
alert_on_rejoin: t.boolean, alert_on_rejoin: t.boolean,
alert_channel: t.string, alert_channel: tNullable(t.string),
can_note: t.boolean, can_note: t.boolean,
can_warn: t.boolean, can_warn: t.boolean,
can_mute: t.boolean, can_mute: t.boolean,
@ -84,7 +85,7 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
this.ignoredEvents = []; this.ignoredEvents = [];
} }
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
dm_on_warn: true, dm_on_warn: true,

View file

@ -13,6 +13,7 @@ import {
NotifyUserStatus, NotifyUserStatus,
stripObjectToScalars, stripObjectToScalars,
successMessage, successMessage,
tNullable,
ucfirst, ucfirst,
UnknownUser, UnknownUser,
} from "../utils"; } from "../utils";
@ -28,14 +29,14 @@ import { Case } from "../data/entities/Case";
import * as t from "io-ts"; import * as t from "io-ts";
const ConfigSchema = t.type({ const ConfigSchema = t.type({
mute_role: t.string, mute_role: tNullable(t.string),
move_to_voice_channel: t.string, move_to_voice_channel: tNullable(t.string),
dm_on_mute: t.boolean, dm_on_mute: t.boolean,
message_on_mute: t.boolean, message_on_mute: t.boolean,
message_channel: t.string, message_channel: tNullable(t.string),
mute_message: t.string, mute_message: tNullable(t.string),
timed_mute_message: t.string, timed_mute_message: tNullable(t.string),
can_view_list: t.boolean, can_view_list: t.boolean,
can_cleanup: t.boolean, can_cleanup: t.boolean,
@ -70,7 +71,7 @@ export class MutesPlugin extends ZeppelinPlugin<TConfigSchema> {
protected serverLogs: GuildLogs; protected serverLogs: GuildLogs;
private muteClearIntervalId: NodeJS.Timer; private muteClearIntervalId: NodeJS.Timer;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
mute_role: null, mute_role: null,
@ -366,7 +367,7 @@ export class MutesPlugin extends ZeppelinPlugin<TConfigSchema> {
if (!member) { if (!member) {
if (!bannedIds) { if (!bannedIds) {
const bans = await this.guild.getBans(); const bans = await this.guild.getBans();
bannedIds = bans.map(u => u.id); bannedIds = bans.map(u => u.user.id);
} }
muteWithDetails.banned = bannedIds.includes(mute.user_id); muteWithDetails.banned = bannedIds.includes(mute.user_id);

View file

@ -18,7 +18,7 @@ export class NameHistoryPlugin extends ZeppelinPlugin<TConfigSchema> {
protected nicknameHistory: GuildNicknameHistory; protected nicknameHistory: GuildNicknameHistory;
protected usernameHistory: UsernameHistory; protected usernameHistory: UsernameHistory;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_view: false, can_view: false,

View file

@ -22,7 +22,7 @@ export class PersistPlugin extends ZeppelinPlugin<TConfigSchema> {
protected persistedData: GuildPersistedData; protected persistedData: GuildPersistedData;
protected logs: GuildLogs; protected logs: GuildLogs;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
persisted_roles: [], persisted_roles: [],

View file

@ -21,7 +21,7 @@ export class PingableRolesPlugin extends ZeppelinPlugin<TConfigSchema> {
protected cache: Map<string, PingableRole[]>; protected cache: Map<string, PingableRole[]>;
protected timeouts: Map<string, any>; protected timeouts: Map<string, any>;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_manage: false, can_manage: false,

View file

@ -58,7 +58,7 @@ export class PostPlugin extends ZeppelinPlugin<TConfigSchema> {
clearTimeout(this.scheduledPostLoopTimeout); clearTimeout(this.scheduledPostLoopTimeout);
} }
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_post: false, can_post: false,

View file

@ -55,7 +55,7 @@ export class ReactionRolesPlugin extends ZeppelinPlugin<TConfigSchema> {
private autoRefreshTimeout; private autoRefreshTimeout;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
auto_refresh_interval: MIN_AUTO_REFRESH, auto_refresh_interval: MIN_AUTO_REFRESH,

View file

@ -32,7 +32,7 @@ export class RemindersPlugin extends ZeppelinPlugin<TConfigSchema> {
private postRemindersTimeout; private postRemindersTimeout;
private unloaded = false; private unloaded = false;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_use: false, can_use: false,

View file

@ -18,7 +18,7 @@ export class SelfGrantableRolesPlugin extends ZeppelinPlugin<TConfigSchema> {
protected selfGrantableRoles: GuildSelfGrantableRoles; protected selfGrantableRoles: GuildSelfGrantableRoles;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_manage: false, can_manage: false,

View file

@ -42,7 +42,7 @@ export class SlowmodePlugin extends ZeppelinPlugin<TConfigSchema> {
private onMessageCreateFn; private onMessageCreateFn;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
use_native_slowmode: true, use_native_slowmode: true,

View file

@ -8,6 +8,7 @@ import {
getUserMentions, getUserMentions,
noop, noop,
stripObjectToScalars, stripObjectToScalars,
tNullable,
trimLines, trimLines,
} from "../utils"; } from "../utils";
import { LogType } from "../data/LogType"; import { LogType } from "../data/LogType";
@ -23,30 +24,26 @@ import { MuteResult, MutesPlugin } from "./Mutes";
import { CasesPlugin } from "./Cases"; import { CasesPlugin } from "./Cases";
import * as t from "io-ts"; import * as t from "io-ts";
const BaseSingleSpamConfig = t.intersection([ const BaseSingleSpamConfig = t.type({
t.type({ interval: t.number,
interval: t.number, count: t.number,
count: t.number, mute: tNullable(t.boolean),
}), mute_time: tNullable(t.number),
t.partial({ clean: tNullable(t.boolean),
mute: t.boolean, });
mute_time: t.number,
clean: t.boolean,
}),
]);
type TBaseSingleSpamConfig = t.TypeOf<typeof BaseSingleSpamConfig>; type TBaseSingleSpamConfig = t.TypeOf<typeof BaseSingleSpamConfig>;
const ConfigSchema = t.type({ const ConfigSchema = t.type({
max_censor: BaseSingleSpamConfig, max_censor: tNullable(BaseSingleSpamConfig),
max_messages: BaseSingleSpamConfig, max_messages: tNullable(BaseSingleSpamConfig),
max_mentions: BaseSingleSpamConfig, max_mentions: tNullable(BaseSingleSpamConfig),
max_links: BaseSingleSpamConfig, max_links: tNullable(BaseSingleSpamConfig),
max_attachments: BaseSingleSpamConfig, max_attachments: tNullable(BaseSingleSpamConfig),
max_emojis: BaseSingleSpamConfig, max_emojis: tNullable(BaseSingleSpamConfig),
max_newlines: BaseSingleSpamConfig, max_newlines: tNullable(BaseSingleSpamConfig),
max_duplicates: BaseSingleSpamConfig, max_duplicates: tNullable(BaseSingleSpamConfig),
max_characters: BaseSingleSpamConfig, max_characters: tNullable(BaseSingleSpamConfig),
max_voice_moves: BaseSingleSpamConfig, max_voice_moves: tNullable(BaseSingleSpamConfig),
}); });
type TConfigSchema = t.TypeOf<typeof ConfigSchema>; type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
@ -99,7 +96,7 @@ export class SpamPlugin extends ZeppelinPlugin<TConfigSchema> {
private expiryInterval; private expiryInterval;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
max_censor: null, max_censor: null,

View file

@ -32,7 +32,7 @@ export class StarboardPlugin extends ZeppelinPlugin<TConfigSchema> {
private onMessageDeleteFn; private onMessageDeleteFn;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_manage: false, can_manage: false,

View file

@ -34,7 +34,7 @@ export class TagsPlugin extends ZeppelinPlugin<TConfigSchema> {
protected tagFunctions; protected tagFunctions;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
prefix: "!!", prefix: "!!",

View file

@ -90,8 +90,9 @@ export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
protected archives: GuildArchives; protected archives: GuildArchives;
protected lastFullMemberRefresh = 0; protected lastFullMemberRefresh = 0;
protected lastReload;
getDefaultOptions(): IPluginOptions<TConfigSchema> { protected static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return { return {
config: { config: {
can_roles: false, can_roles: false,
@ -142,6 +143,8 @@ export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
this.savedMessages = GuildSavedMessages.getGuildInstance(this.guildId); this.savedMessages = GuildSavedMessages.getGuildInstance(this.guildId);
this.archives = GuildArchives.getGuildInstance(this.guildId); this.archives = GuildArchives.getGuildInstance(this.guildId);
this.lastReload = Date.now();
if (activeReloads && activeReloads.has(this.guildId)) { if (activeReloads && activeReloads.has(this.guildId)) {
activeReloads.get(this.guildId).createMessage(successMessage("Reloaded!")); activeReloads.get(this.guildId).createMessage(successMessage("Reloaded!"));
activeReloads.delete(this.guildId); activeReloads.delete(this.guildId);
@ -1003,8 +1006,14 @@ export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
const shard = this.bot.shards.get(this.bot.guildShardMap[this.guildId]); const shard = this.bot.shards.get(this.bot.guildShardMap[this.guildId]);
const lastReload = humanizeDuration(Date.now() - this.lastReload, {
largest: 2,
round: true,
});
const basicInfoRows = [ const basicInfoRows = [
["Uptime", prettyUptime], ["Uptime", prettyUptime],
["Last reload", `${lastReload} ago`],
["Last update", moment(lastCommit.committer.date, "X").format("LL [at] H:mm [(UTC)]")], ["Last update", moment(lastCommit.committer.date, "X").format("LL [at] H:mm [(UTC)]")],
["Version", lastCommit.shortHash], ["Version", lastCommit.shortHash],
["API latency", `${shard.latency}ms`], ["API latency", `${shard.latency}ms`],

View file

@ -1,4 +1,4 @@
import { IBasePluginConfig, IPluginOptions, logger, Plugin } from "knub"; import { IBasePluginConfig, IPluginOptions, logger, Plugin, configUtils } from "knub";
import { PluginRuntimeError } from "../PluginRuntimeError"; import { PluginRuntimeError } from "../PluginRuntimeError";
import * as t from "io-ts"; import * as t from "io-ts";
import { pipe } from "fp-ts/lib/pipeable"; import { pipe } from "fp-ts/lib/pipeable";
@ -29,19 +29,47 @@ export class ZeppelinPlugin<TConfig extends {} = IBasePluginConfig> extends Plug
return ourLevel > memberLevel; return ourLevel > memberLevel;
} }
protected static getStaticDefaultOptions() {
// Implemented by plugin
return {};
}
protected getDefaultOptions(): IPluginOptions<TConfig> {
return (this.constructor as typeof ZeppelinPlugin).getStaticDefaultOptions() as IPluginOptions<TConfig>;
}
public static validateOptions(options: any): string[] | null { public static validateOptions(options: any): string[] | null {
// Validate config values // Validate config values
if (this.configSchema) { if (this.configSchema) {
if (options.config) { if (options.config) {
const errors = validateStrict(this.configSchema, options.config); const merged = configUtils.mergeConfig(
if (errors) return errors; {},
(this.getStaticDefaultOptions() as any).config || {},
options.config,
);
const errors = validateStrict(this.configSchema, merged);
if (errors) {
return errors;
}
} }
if (options.overrides) { if (options.overrides) {
for (const override of options.overrides) { for (const [i, override] of options.overrides.entries()) {
if (override.config) { if (override.config) {
const errors = validateStrict(this.configSchema, override.config); // For type checking overrides, apply default config + supplied config + any overrides preceding this override + finally this override
if (errors) return errors; // Exhaustive type checking would require checking against all combinations of preceding overrides but that's... costy. This will do for now.
// TODO: Override default config retrieval functions and do some sort of memoized checking there?
const merged = configUtils.mergeConfig(
{},
(this.getStaticDefaultOptions() as any).config || {},
options.config || {},
...options.overrides.slice(0, i),
override.config,
);
const errors = validateStrict(this.configSchema, merged);
if (errors) {
return errors;
}
} }
} }
} }
@ -55,7 +83,7 @@ export class ZeppelinPlugin<TConfig extends {} = IBasePluginConfig> extends Plug
const mergedOptions = this.getMergedOptions(); const mergedOptions = this.getMergedOptions();
const validationErrors = ((this.constructor as unknown) as typeof ZeppelinPlugin).validateOptions(mergedOptions); const validationErrors = ((this.constructor as unknown) as typeof ZeppelinPlugin).validateOptions(mergedOptions);
if (validationErrors) { if (validationErrors) {
throw new Error(`Invalid options:\n${validationErrors.join("\n")}`); throw new Error(validationErrors.join("\n"));
} }
return super.runLoad(); return super.runLoad();

View file

@ -25,6 +25,7 @@ import { GuildInfoSaverPlugin } from "./GuildInfoSaver";
import { LogServerPlugin } from "./LogServer"; import { LogServerPlugin } from "./LogServer";
import { CompanionChannelPlugin } from "./CompanionChannels"; import { CompanionChannelPlugin } from "./CompanionChannels";
import { LocatePlugin } from "./LocateUser"; import { LocatePlugin } from "./LocateUser";
import { GuildConfigReloader } from "./GuildConfigReloader";
/** /**
* Plugins available to be loaded for individual guilds * Plugins available to be loaded for individual guilds
@ -70,4 +71,4 @@ export const basePlugins = [
/** /**
* Available global plugins (can't be loaded per-guild, only globally) * Available global plugins (can't be loaded per-guild, only globally)
*/ */
export const availableGlobalPlugins = [BotControlPlugin, UsernameSaver, LogServerPlugin]; export const availableGlobalPlugins = [BotControlPlugin, UsernameSaver, LogServerPlugin, GuildConfigReloader];

View file

@ -11,7 +11,8 @@ import {
} from "eris"; } from "eris";
import url from "url"; import url from "url";
import tlds from "tlds"; import tlds from "tlds";
import emojiRegex from "emoji-regex/es2015/text"; import emojiRegex from "emoji-regex/text";
import * as t from "io-ts";
import fs from "fs"; import fs from "fs";
const fsp = fs.promises; const fsp = fs.promises;
@ -28,6 +29,10 @@ const delayStringMultipliers = {
s: 1000, s: 1000,
}; };
export function tNullable(type: t.Mixed) {
return t.union([type, t.undefined, t.null]);
}
/** /**
* Turns a "delay string" such as "1h30m" to milliseconds * Turns a "delay string" such as "1h30m" to milliseconds
*/ */

View file

@ -1,7 +1,42 @@
import * as t from "io-ts"; import * as t from "io-ts";
import { pipe } from "fp-ts/lib/pipeable"; import { pipe } from "fp-ts/lib/pipeable";
import { fold } from "fp-ts/lib/Either"; import { fold } from "fp-ts/lib/Either";
import { PathReporter } from "io-ts/lib/PathReporter"; import { noop } from "./utils";
// From io-ts/lib/PathReporter
function stringify(v) {
if (typeof v === "function") {
return t.getFunctionName(v);
}
if (typeof v === "number" && !isFinite(v)) {
if (isNaN(v)) {
return "NaN";
}
return v > 0 ? "Infinity" : "-Infinity";
}
return JSON.stringify(v);
}
// From io-ts/lib/PathReporter
// tslint:disable
function getContextPath(context) {
return context
.map(function(_a) {
var key = _a.key,
type = _a.type;
return key + ": " + type.name;
})
.join("/");
}
// tslint:enable
const report = fold((errors: any) => {
return errors.map(err => {
if (err.message) return err.message;
const context = err.context.map(c => c.key).filter(k => k && !k.startsWith("{"));
return `Invalid value <${stringify(err.value)}> supplied to <${context.join("/")}>`;
});
}, noop);
/** /**
* Validates the given value against the given schema while also disallowing extra properties * Validates the given value against the given schema while also disallowing extra properties
@ -12,7 +47,7 @@ export function validateStrict(schema: t.Type<any, any, any>, value: any): strin
return pipe( return pipe(
validationResult, validationResult,
fold( fold(
err => PathReporter.report(validationResult), err => report(validationResult),
result => { result => {
// Make sure there are no extra properties // Make sure there are no extra properties
if (JSON.stringify(value) !== JSON.stringify(result)) { if (JSON.stringify(value) !== JSON.stringify(result)) {