diff --git a/package-lock.json b/package-lock.json index 515e47fc..1da7a64a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3853,6 +3853,11 @@ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", "dev": true }, + "deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==" + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", diff --git a/package.json b/package.json index 37d6f875..c29277a1 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "dependencies": { "cors": "^2.8.5", "cross-env": "^5.2.0", + "deep-diff": "^1.0.2", "dotenv": "^4.0.0", "emoji-regex": "^8.0.0", "eris": "^0.10.1", diff --git a/src/configValidator.ts b/src/configValidator.ts index bd1aad7c..0e60ad48 100644 --- a/src/configValidator.ts +++ b/src/configValidator.ts @@ -18,7 +18,7 @@ const guildConfigRootSchema = t.type({ levels: t.record(t.string, t.number), plugins: t.record(t.string, t.unknown), }); -const partialGuildConfigRootSchema = t.exact(t.partial(guildConfigRootSchema.props)); +const partialGuildConfigRootSchema = t.partial(guildConfigRootSchema.props); const globalConfigRootSchema = t.type({ url: t.string, diff --git a/src/plugins/ZeppelinPlugin.ts b/src/plugins/ZeppelinPlugin.ts index a5ddd86a..325a8f17 100644 --- a/src/plugins/ZeppelinPlugin.ts +++ b/src/plugins/ZeppelinPlugin.ts @@ -63,7 +63,7 @@ export class ZeppelinPlugin extends Plug {}, (this.getStaticDefaultOptions() as any).config || {}, options.config || {}, - ...options.overrides.slice(0, i), + ...options.overrides.slice(0, i).map(o => o.config || {}), override.config, ); const errors = validateStrict(this.configSchema, merged); diff --git a/src/validatorUtils.ts b/src/validatorUtils.ts index 94aa9cd8..ddbddf44 100644 --- a/src/validatorUtils.ts +++ b/src/validatorUtils.ts @@ -2,6 +2,7 @@ import * as t from "io-ts"; import { pipe } from "fp-ts/lib/pipeable"; import { fold } from "fp-ts/lib/Either"; import { noop } from "./utils"; +import deepDiff from "deep-diff"; // From io-ts/lib/PathReporter function stringify(v) { @@ -42,8 +43,8 @@ const report = fold((errors: any) => { * Validates the given value against the given schema while also disallowing extra properties * See: https://github.com/gcanti/io-ts/issues/322 */ -export function validateStrict(schema: t.Type, value: any): string[] | null { - const validationResult = schema.decode(value); +export function validateStrict(schema: t.HasProps, value: any): string[] | null { + const validationResult = t.exact(schema).decode(value); return pipe( validationResult, fold( @@ -51,8 +52,9 @@ export function validateStrict(schema: t.Type, value: any): strin result => { // Make sure there are no extra properties if (JSON.stringify(value) !== JSON.stringify(result)) { - // TODO: Actually mention what the unknown property is - return ["Found unknown properties"]; + const diff = deepDiff(result, value); + const errors = diff.filter(d => d.kind === "N").map(d => `Unknown property <${d.path.join(".")}>`); + return errors.length ? errors : ["Found unknown properties"]; } return null;