diff --git a/bin/config-validator.js b/lib/config-validator.ts
old mode 100755
new mode 100644
similarity index 67%
rename from bin/config-validator.js
rename to lib/config-validator.ts
index 68f5a1b1bdc83e230bde3011f01a4905efae8eeb..69a2ec2292ba6363e31194ef2e133308f70241e2
--- a/bin/config-validator.js
+++ b/lib/config-validator.ts
@@ -1,16 +1,21 @@
 #!/usr/bin/env node
-
-const fs = require('fs-extra');
-const { validateConfig } = require('../dist/config/validation');
-const { massageConfig } = require('../dist/config/massage');
-const { getConfig } = require('../dist/config/file');
-const { configFileNames } = require('../dist/config/app-strings');
+// istanbul ignore file
+import { readFileSync } from 'fs-extra';
+import { configFileNames } from './config/app-strings';
+import { RenovateConfig } from './config/common';
+import { getConfig } from './config/file';
+import { massageConfig } from './config/massage';
+import { validateConfig } from './config/validation';
 
 /* eslint-disable no-console */
 
 let returnVal = 0;
 
-async function validate(desc, config, isPreset = false) {
+async function validate(
+  desc: string,
+  config: RenovateConfig,
+  isPreset = false
+): Promise<void> {
   const res = await validateConfig(massageConfig(config), isPreset);
   if (res.errors.length) {
     console.log(
@@ -26,15 +31,20 @@ async function validate(desc, config, isPreset = false) {
   }
 }
 
+type PackageJson = {
+  renovate?: RenovateConfig;
+  'renovate-config'?: Record<string, RenovateConfig>;
+};
+
 (async () => {
   for (const file of configFileNames.filter(
     (name) => name !== 'package.json'
   )) {
     try {
-      const rawContent = fs.readFileSync(file, 'utf8');
+      const rawContent = readFileSync(file, 'utf8');
       console.log(`Validating ${file}`);
       try {
-        const jsonContent = JSON.parse(rawContent);
+        const jsonContent = JSON.parse(rawContent) as PackageJson;
         await validate(file, jsonContent);
       } catch (err) {
         console.log(`${file} is not valid Renovate config`);
@@ -45,7 +55,9 @@ async function validate(desc, config, isPreset = false) {
     }
   }
   try {
-    const pkgJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
+    const pkgJson = JSON.parse(
+      readFileSync('package.json', 'utf8')
+    ) as PackageJson;
     if (pkgJson.renovate) {
       console.log(`Validating package.json > renovate`);
       await validate('package.json > renovate', pkgJson.renovate);
@@ -75,4 +87,7 @@ async function validate(desc, config, isPreset = false) {
     process.exit(returnVal);
   }
   console.log('OK');
-})();
+})().catch((e) => {
+  console.error(e);
+  process.exit(99);
+});
diff --git a/package.json b/package.json
index a4fa07a534f6059e7cfbdd731ed47a1ac73b0d92..8c7a59375de17e5f7723898833290c6aebeb27c9 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "version": "0.0.0-semantic-release",
   "bin": {
     "renovate": "dist/renovate.js",
-    "renovate-config-validator": "bin/config-validator.js"
+    "renovate-config-validator": "dist/config-validator.js"
   },
   "scripts": {
     "build": "run-s clean generate:* compile:*",
@@ -261,7 +261,6 @@
     "**/kind-of": ">=6.0.3"
   },
   "files": [
-    "bin/config-validator.js",
     "data",
     "dist"
   ],