diff --git a/changelog.d/205.misc b/changelog.d/205.misc new file mode 100644 index 00000000..7af8a6f2 --- /dev/null +++ b/changelog.d/205.misc @@ -0,0 +1 @@ +Typescriptify ConfigValidator \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 91a8eb54..f9f8c0a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -399,6 +399,12 @@ "@types/range-parser": "*" } }, + "@types/extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/extend/-/extend-3.0.1.tgz", + "integrity": "sha512-R1g/VyKFFI2HLC1QGAeTtCBWCo6n75l41OnsVYNbmKG+kempOESaodf6BeJyUM3Q0rKa/NQcTHbB2+66lNnxLw==", + "dev": true + }, "@types/js-yaml": { "version": "3.12.5", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.5.tgz", diff --git a/package.json b/package.json index 94a254b0..d99c8739 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ }, "devDependencies": { "@types/bluebird": "^3.5.32", + "@types/extend": "^3.0.1", "@types/js-yaml": "^3.12.5", "@types/node": "^10", "@types/nopt": "^3.0.29", diff --git a/src/components/cli.ts b/src/components/cli.ts index c3d9c3c4..dac52cae 100644 --- a/src/components/cli.ts +++ b/src/components/cli.ts @@ -32,7 +32,7 @@ interface CliOpts> { bridgeConfig?: { affectsRegistration?: boolean; schema: string|Record; - defaults: string|Record; + defaults: Record; }; registrationPath: string; enableRegistration?: boolean; diff --git a/src/components/config-validator.js b/src/components/config-validator.js deleted file mode 100644 index 6d78d861..00000000 --- a/src/components/config-validator.js +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -const fs = require("fs"); -const yaml = require("js-yaml"); -const Validator = require("is-my-json-valid"); -const extend = require("extend"); - -/** - * Construct a validator of YAML files. - * @constructor - * @param {string|Object} schema The JSON schema file (as YAML) or object. - */ -function ConfigValidator(schema) { - this.schema = schema; - if (typeof schema === "string") { - this.schema = this._loadFromFile(schema); - } -} - -/** - * Validate the input config. - * @param {string|Object} inputConfig The input config file path (string) or - * parsed config (Object). - * @param {Object=} defaultConfig The default config options. - * @return {Object} The input config with defaults applied. - * @throws On validation errors - */ -ConfigValidator.prototype.validate = function(inputConfig, defaultConfig) { - defaultConfig = defaultConfig || {}; - if (typeof inputConfig === "string") { - inputConfig = this._loadFromFile(inputConfig); - } - const js = Validator(this.schema, { - verbose: true, - }); - const res = js(inputConfig, this.schema); - if (!res) { - js.errors.forEach(function(error) { - console.error(JSON.stringify(error)); - console.error(`The field ${error.field} is ${error.value}` + - ` which ${error.message}`); - }); - var e = new Error("Failed to validate file"); - e._validationErrors = js.errors; - throw e; - } - // mux in the default config - return extend(true, defaultConfig, inputConfig); -} - -ConfigValidator.prototype._loadFromFile = function(filename) { - return yaml.safeLoad(fs.readFileSync(filename, 'utf8')); -}; - -module.exports = ConfigValidator; diff --git a/src/components/config-validator.ts b/src/components/config-validator.ts new file mode 100644 index 00000000..727171d4 --- /dev/null +++ b/src/components/config-validator.ts @@ -0,0 +1,75 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +import * as fs from "fs"; +import yaml from "js-yaml"; +import validator from "is-my-json-valid"; +import extend from "extend"; + +type Schema = any; + +export default class ConfigValidator { + + /** + * Construct a validator of YAML files. + * @param schema The JSON schema file object. + */ + constructor (private schema: Schema) { } + + /** + * Validate the input config. + * @param inputConfig The input config file path (string) or + * parsed config (Object). + * @param defaultConfig The default config options. + * @return The input config with defaults applied. + * @throws On validation errors + */ + public validate(inputConfig: string|Schema, defaultConfig: Record = {}) { + if (typeof inputConfig === "string") { + inputConfig = ConfigValidator.loadFromFile(inputConfig); + } + const js = validator(this.schema, { + verbose: true, + }); + const res = js(inputConfig, this.schema); + if (!res) { + js.errors.forEach(error => { + console.error(JSON.stringify(error)); + console.error(`The field ${error.field} is ${error.value}` + + ` which ${error.message}`); + }); + // This is a bit awful, but it's how we return validation errors. + const e: any = new Error("Failed to validate file"); + e._validationErrors = js.errors; + throw e; + } + // mux in the default config + return extend(true, defaultConfig, inputConfig); + } + + private static loadFromFile(filename: string): Schema { + const result = yaml.safeLoad(fs.readFileSync(filename, 'utf8')); + if (typeof(result) !== "object") { + throw Error('Was expecting yaml as an object'); + } + return result; + } + + private static fromSchemaFile(filename: string): ConfigValidator { + return new ConfigValidator(ConfigValidator.loadFromFile(filename)); + } +} + +module.exports = ConfigValidator; diff --git a/src/index.ts b/src/index.ts index 49bfe6d5..f99c7409 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,7 @@ export * from "./components/state-lookup"; // Config and CLI export * from "./components/cli"; +export * from "./components/config-validator"; module.exports.ConfigValidator = require("./components/config-validator"); // Store