Repository: lingui/js-lingui (ts)

Issue:
Warnings for compilerBabelOptions other than empty.
**Describe the bug**
When using anything other than `compilerBabelOptions: {}` in my lingui configuration, I am issued a warning.

**To Reproduce**

create a lingui configuration file with

```json
{
    "compilerBabelOptions": {
      "minified": false
    },
    "locales": ["en"]
}
```

and run `npm run extract`, to be served with:

```none
● Validation Warning:

  Unknown option "compilerBabelOptions.minified" with value false was found.
  This is probably a typing mistake. Fixing it will remove this message.

Documentation: https://lingui.js.org/ref/conf.html
● Validation Warning:

  Unknown option "compilerBabelOptions.minified" with value false was found.
  This is probably a typing mistake. Fixing it will remove this message.

Documentation: https://lingui.js.org/ref/conf.html
```

`npm run compile` produces the same message, albeit just once.

**Expected behavior**

The configuration is correct, and should not result in a warning.

**Additional context**

- jsLingui version ``lingui --version``: 3.3.0

I suspect the `defaultConfig` definition in `@lingui/conf` needs updating, it currently sets `compilerBabelOptions` to an empty object. If I set it to the default from https://lingui.js.org/ref/conf.html#compilerbabeloptions, the warnings are gone. 


Pull request description:
fix: compilerBabelOptions jest-validate
Will close #935 

unfortunately jest-validate doesn't work if in the example config we set an empty object, we must strict declare the values we accept. I'll setup the default values that we're using and probably the only ones that the final user should be able to change.. Dunno



Patch:
diff --git a/packages/cli/src/api/compile.ts b/packages/cli/src/api/compile.ts
index de37bfde..a4babd72 100644
--- a/packages/cli/src/api/compile.ts
+++ b/packages/cli/src/api/compile.ts
@@ -1,5 +1,5 @@
 import * as t from "@babel/types"
-import generate from "@babel/generator"
+import generate, { GeneratorOptions } from "@babel/generator"
 import { parse } from "messageformat-parser"
 import * as R from "ramda"
 
@@ -15,7 +15,7 @@ export type CreateCompileCatalogOptions = {
   strict?: boolean
   namespace?: CompiledCatalogNamespace
   pseudoLocale?: string
-  compilerBabelOptions?: Record<string, unknown>
+  compilerBabelOptions?: GeneratorOptions
 }
 
 export function createCompiledCatalog(
diff --git a/packages/conf/index.d.ts b/packages/conf/index.d.ts
index 02606c5c..0b49e511 100644
--- a/packages/conf/index.d.ts
+++ b/packages/conf/index.d.ts
@@ -1,3 +1,5 @@
+import type { GeneratorOptions } from "@babel/core";
+
 export declare type CatalogFormat = "lingui" | "minimal" | "po" | "csv" | "po-gettext";
 export type CatalogFormatOptions = {
     origins?: boolean;
@@ -24,7 +26,7 @@ export declare type LinguiConfig = {
     catalogs: CatalogConfig[];
     compileNamespace: string;
     extractBabelOptions: Record<string, unknown>;
-    compilerBabelOptions: Record<string, unknown>;
+    compilerBabelOptions: GeneratorOptions;
     fallbackLocales: FallbackLocales;
     format: CatalogFormat;
     prevFormat: CatalogFormat;
@@ -52,7 +54,7 @@ export declare const configValidation: {
             plugins: string[];
             presets: string[];
         };
-        compilerBabelOptions: Record<string, unknown>;
+        compilerBabelOptions: GeneratorOptions;
         catalogs: CatalogConfig[];
         compileNamespace: string;
         fallbackLocales: FallbackLocales;
diff --git a/packages/conf/package.json b/packages/conf/package.json
index 171c8687..3f60b945 100644
--- a/packages/conf/package.json
+++ b/packages/conf/package.json
@@ -19,6 +19,7 @@
   },
   "dependencies": {
     "@babel/runtime": "^7.11.2",
+    "@endemolshinegroup/cosmiconfig-typescript-loader": "^3.0.2",
     "chalk": "^4.1.0",
     "cosmiconfig": "^7.0.0",
     "jest-validate": "^26.5.2"
diff --git a/packages/conf/src/index.ts b/packages/conf/src/index.ts
index 2fdd483c..29af1271 100644
--- a/packages/conf/src/index.ts
+++ b/packages/conf/src/index.ts
@@ -1,8 +1,10 @@
+import type { GeneratorOptions } from "@babel/core"
 import path from "path"
 import fs from "fs"
 import chalk from "chalk"
-import { cosmiconfigSync } from "cosmiconfig"
+import { Loader, cosmiconfigSync } from "cosmiconfig"
 import { multipleValidOptions, validate } from "jest-validate"
+import get from "lodash.get"
 
 export type CatalogFormat = "lingui" | "minimal" | "po" | "csv"
 
@@ -27,13 +29,13 @@ type DefaultLocaleObject = {
 }
 export type FallbackLocales = LocaleObject | DefaultLocaleObject | false
 
-type ModuleSource = [string, string?];
+type ModuleSource = [string, string?]
 
 export type LinguiConfig = {
   catalogs: CatalogConfig[]
   compileNamespace: string
   extractBabelOptions: Record<string, unknown>
-  compilerBabelOptions: Record<string, unknown>
+  compilerBabelOptions: GeneratorOptions
   fallbackLocales?: FallbackLocales
   format: CatalogFormat
   formatOptions: CatalogFormatOptions
@@ -42,7 +44,7 @@ export type LinguiConfig = {
   orderBy: OrderBy
   pseudoLocale: string
   rootDir: string
-  runtimeConfigModule: ModuleSource | {[symbolName: string]: ModuleSource},
+  runtimeConfigModule: ModuleSource | { [symbolName: string]: ModuleSource }
   sourceLocale: string
 }
 
@@ -65,7 +67,12 @@ export const defaultConfig: LinguiConfig = {
   ],
   catalogsMergePath: "",
   compileNamespace: "cjs",
-  compilerBabelOptions: {},
+  compilerBabelOptions: {
+    minified: true,
+    jsescOption: {
+      minimal: true,
+    }
+  },
   extractBabelOptions: { plugins: [], presets: [] },
   fallbackLocales: {},
   format: "po",
@@ -92,7 +99,23 @@ export function getConfig({
   skipValidation?: boolean
 } = {}): LinguiConfig {
   const defaultRootDir = cwd || process.cwd()
-  const configExplorer = cosmiconfigSync("lingui")
+  const moduleName = "lingui"
+  const configExplorer = cosmiconfigSync(moduleName, {
+    searchPlaces: [
+      "package.json",
+      `.${moduleName}rc`,
+      `.${moduleName}rc.json`,
+      `.${moduleName}rc.yaml`,
+      `.${moduleName}rc.yml`,
+      `.${moduleName}rc.ts`,
+      `.${moduleName}rc.js`,
+      `${moduleName}.config.ts`,
+      `${moduleName}.config.js`,
+    ],
+    loaders: {
+      ".ts": TypeScriptLoader,
+    },
+  })
 
   const result = configExists(configPath)
     ? configExplorer.load(configPath)
@@ -141,7 +164,7 @@ const exampleConfig = {
 }
 
 const deprecatedConfig = {
-    fallbackLocale: (config: LinguiConfig & DeprecatedFallbackLanguage) =>
+  fallbackLocale: (config: LinguiConfig & DeprecatedFallbackLanguage) =>
     ` Option ${chalk.bold("fallbackLocale")} was replaced by ${chalk.bold(
       "fallbackLocales"
     )}
@@ -151,9 +174,7 @@ const deprecatedConfig = {
     @lingui/cli now treats your current configuration as:
     {
       ${chalk.bold('"fallbackLocales"')}: {
-        default: ${chalk.bold(
-          `"${config.fallbackLocale}"`
-        )}
+        default: ${chalk.bold(`"${config.fallbackLocale}"`)}
       }
     }
 
@@ -251,7 +272,7 @@ export function replaceRootDir(
     } else if (typeof value === "string") {
       return replace(value)
     } else if (Array.isArray(value)) {
-      return value.map((item) => replaceDeep(item, rootDir)) as any
+      return (value as any).map((item) => replaceDeep(item, rootDir))
     } else if (typeof value === "object") {
       Object.keys(value).forEach((key) => {
         const newKey = replaceDeep(key, rootDir)
@@ -276,17 +297,18 @@ export function fallbackLanguageMigration(
 ): LinguiConfig {
   const { fallbackLocale, fallbackLocales } = config
 
-  if (fallbackLocales === false) return {
-    ...config,
-    fallbackLocales: null,
-  }
+  if (fallbackLocales === false)
+    return {
+      ...config,
+      fallbackLocales: null,
+    }
 
   config.locales.forEach((locale) => {
     const fl = getCldrParentLocale(locale.toLowerCase())
     if (fl && !config.fallbackLocales[locale]) {
       config.fallbackLocales = {
         ...config.fallbackLocales,
-        [locale]: fl
+        [locale]: fl,
       }
     }
   })
@@ -475,7 +497,7 @@ function getCldrParentLocale(sourceLocale: string) {
     "yue-hans": "yue",
     "zh-hant": "zh",
     "zh-hant-hk": "zh",
-    "zh-hant-mo": "zh-hant-hk"
+    "zh-hant-mo": "zh-hant-hk",
   }[sourceLocale]
 }
 
@@ -525,3 +547,21 @@ export function catalogMigration(
 
 const pipe = (...functions: Array<Function>) => (args: any): any =>
   functions.reduce((arg, fn) => fn(arg), args)
+
+// copied from @EndemolShineGroup/cosmiconfig-typescript-loader
+// to support sync operations
+// if this PR gets merged and published, this piece of code can be thrown away
+// https://github.com/EndemolShineGroup/cosmiconfig-typescript-loader/pull/132
+function TypeScriptLoader(filePath: string) {
+  try {
+    require("ts-node/register")
+    const result = require(filePath)
+
+    return get(result, "default", result)
+  } catch (error) {
+    // Replace with logger class OR throw a more specific error
+    throw require("@endemolshinegroup/cosmiconfig-typescript-loader/dist/Errors/TypeScriptCompileError").fromError(
+      error
+    )
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index d2efb0ef..1de0e5ee 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1068,6 +1068,16 @@
     exec-sh "^0.3.2"
     minimist "^1.2.0"
 
+"@endemolshinegroup/cosmiconfig-typescript-loader@^3.0.2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz#eea4635828dde372838b0909693ebd9aafeec22d"
+  integrity sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==
+  dependencies:
+    lodash.get "^4"
+    make-error "^1"
+    ts-node "^9"
+    tslib "^2"
+
 "@eslint/eslintrc@^0.1.3":
   version "0.1.3"
   resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085"
@@ -3386,6 +3396,11 @@ are-we-there-yet@~1.1.2:
     delegates "^1.0.0"
     readable-stream "^2.0.6"
 
+arg@^4.1.0:
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
+  integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
+
 argparse@^1.0.7:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@@ -4758,6 +4773,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
     safe-buffer "^5.0.1"
     sha.js "^2.4.8"
 
+create-require@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
+  integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
+
 cross-env@^7.0.2:
   version "7.0.2"
   resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9"
@@ -8244,7 +8264,7 @@ lodash.foreach@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
   integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=
 
-lodash.get@^4.4.2:
+lodash.get@^4, lodash.get@^4.4.2:
   version "4.4.2"
   resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
   integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
@@ -8484,7 +8504,7 @@ make-dir@^3.0.0, make-dir@^3.0.2:
   dependencies:
     semver "^6.0.0"
 
-make-error@1.x:
+make-error@1.x, make-error@^1, make-error@^1.1.1:
   version "1.3.6"
   resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
   integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
@@ -11448,7 +11468,7 @@ source-map-resolve@^0.5.0:
     source-map-url "^0.4.0"
     urix "^0.1.0"
 
-source-map-support@^0.5.11, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@^0.5.7, source-map-support@~0.5.12:
+source-map-support@^0.5.11, source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@^0.5.7, source-map-support@~0.5.12:
   version "0.5.19"
   resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
   integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
@@ -12302,6 +12322,18 @@ ts-jest@^26.4.1:
     semver "7.x"
     yargs-parser "20.x"
 
+ts-node@^9:
+  version "9.1.1"
+  resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
+  integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
+  dependencies:
+    arg "^4.1.0"
+    create-require "^1.1.0"
+    diff "^4.0.1"
+    make-error "^1.1.1"
+    source-map-support "^0.5.17"
+    yn "3.1.1"
+
 ts-toolbelt@^6.3.3:
   version "6.15.5"
   resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz#cb3b43ed725cb63644782c64fbcad7d8f28c0a83"
@@ -12332,6 +12364,11 @@ tslib@^1, tslib@^1.10.0, tslib@^1.11.1, tslib@^1.11.2, tslib@^1.13.0, tslib@^1.8
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
   integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
 
+tslib@^2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
+  integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
+
 tsutils@^3.17.1:
   version "3.17.1"
   resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
@@ -13154,3 +13191,8 @@ yargs@^7.1.0:
     which-module "^1.0.0"
     y18n "^3.2.1"
     yargs-parser "5.0.0-security.0"
+
+yn@3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
+  integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==


Test patch:
diff --git a/packages/conf/src/__snapshots__/index.test.ts.snap b/packages/conf/src/__snapshots__/index.test.ts.snap
index 08b1bd90..56fcc524 100644
--- a/packages/conf/src/__snapshots__/index.test.ts.snap
+++ b/packages/conf/src/__snapshots__/index.test.ts.snap
@@ -110,7 +110,12 @@ Object {
   ],
   catalogsMergePath: ,
   compileNamespace: cjs,
-  compilerBabelOptions: Object {},
+  compilerBabelOptions: Object {
+    jsescOption: Object {
+      minimal: true,
+    },
+    minified: true,
+  },
   extractBabelOptions: Object {
     plugins: Array [],
     presets: Array [],