diff --git a/.eslintrc.json b/.eslintrc.json index b6ce63da..98eb2203 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,71 +1,104 @@ { "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint", + "eslint-plugin-import", + "typescript-sort-keys", + "prefer-arrow" + ], "extends": [ - "plugin:react/recommended" + "eslint:recommended", + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:jest/recommended", + "plugin:jest/style", + "plugin:typescript-sort-keys/recommended" ], - "settings": { - "react": { - "version": "detect" - } - }, - "env": { - "browser": true - }, "ignorePatterns": [ - "**/node_modules/*" + "**/node_modules/*", + "**/out/*", + "**/.next/*" ], "rules": { - "padded-blocks": 0, - "global-require": 0, - "function-paren-newline": 0, - "no-buffer-constructor": 0, - "import/no-extraneous-dependencies": 0, - "import/no-unresolved": 0, - "import/extensions": 0, - "import/no-mutable-exports": 0, + "comma-dangle": [ + "error", + "always-multiline" + ], + "eol-last": ["error", "always"], + "indent": ["error", 2], + "jest/no-conditional-expect": 0, + "no-console": 2, + "no-trailing-spaces": 2, + "max-len": ["error", { + "code": 80, + "comments": 80, + "ignorePattern": "^import\\s.+\\sfrom\\s.+$", + "ignoreStrings": true, + "ignoreTemplateLiterals": true + }], + "multiline-comment-style": ["error", "separate-lines"], + "no-multiple-empty-lines": "error", + "no-multi-spaces": ["error", { "exceptions": { "Property": false } }], + "no-return-await": 2, + "arrow-body-style": ["error", "as-needed"], + "import/no-amd": 2, + "import/no-commonjs": 2, + "import/no-default-export": 2, + "import/no-namespace": 2, + "import/no-nodejs-modules": 0, + "keyword-spacing": ["error", { "overrides": {} }], + "react/prefer-stateless-function": 2, "react/prop-types": 0, - "react/display-name": 0, - "react/jsx-filename-extension": 0, - "react/prefer-stateless-function": 0, - "react/react-in-jsx-scope": 0, - "no-restricted-syntax": 0, - "no-useless-escape": 0, - "no-console": [ + "react/jsx-wrap-multilines": ["error", { + "declaration": "parens-new-line", + "assignment": "parens-new-line", + "return": "parens-new-line", + "arrow": "parens-new-line", + "condition": "parens-new-line", + "logical": "parens-new-line", + "prop": "parens-new-line" + } + ], + "semi": ["error", "never"], + "sort-keys": 2, + "space-before-blocks": 2, + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/member-delimiter-style": ["error", { + "multiline": { + "delimiter": "none", + "requireLast": false + }, + "singleline": { + "delimiter": "comma", + "requireLast": false + } + }], + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-unused-vars": [ + 2, + { + "argsIgnorePattern": "^_" + } + ], + "@typescript-eslint/no-var-requires": 0, + "prefer-arrow/prefer-arrow-functions": [ "error", { - "allow": [ - "warn", - "error" - ] + "disallowPrototype": true, + "singleReturnOnly": false, + "classPropertiesAllowed": false } - ] + ], + "prefer-destructuring": ["error", {"object": true, "array": true}], + "quotes": ["error", "single"], + "quote-props": ["error", "as-needed"], + "jsx-quotes": ["error", "prefer-single"] }, - "overrides": [ - { - "files": [ - "src/**/*.{ts,tsx}" - ], - "extends": [ - "plugin:@typescript-eslint/recommended" - ], - "rules": { - "@typescript-eslint/indent": [ - "error", - 2 - ], - "semi": "off", - "@typescript-eslint/semi": [ - "error", - "never" - ], - "@typescript-eslint/no-var-requires": 0, - "@typescript-eslint/no-explicit-any": 0, - "@typescript-eslint/explicit-function-return-type": 0, - "@typescript-eslint/explicit-member-accessibility": 0, - "@typescript-eslint/no-object-literal-type-assertion": 0, - "@typescript-eslint/prefer-interface": 0 - }, - "parser": "@typescript-eslint/parser" + "settings": { + "react": { + "pragma": "React", + "version": "16.13.1" } - ] + } } diff --git a/examples/simple/components/Header.js b/examples/simple/components/Header.js index 0e612e74..111b1f39 100644 --- a/examples/simple/components/Header.js +++ b/examples/simple/components/Header.js @@ -6,12 +6,12 @@ export const Header = ({ title }) => (
>(WrappedComponent: React.ComponentType | React.ElementType): React.ComponentType
| React.ElementType
=> { +export const appWithTranslation =
>( + WrappedComponent: React.ComponentType | React.ElementType): + React.ComponentType
| React.ElementType
=> { const AppWithTranslation = (props: AppProps) => { let i18n = null let locale = null @@ -27,7 +29,7 @@ export const appWithTranslation =
>(WrappedCom
const parsedUserConfig = Function(`'use strict';return(${userConfig})`)()
locale = initialLocale;
-
+
({ i18n } = createClient({
...createConfig({
...parsedUserConfig,
diff --git a/src/config/createConfig.test.ts b/src/config/createConfig.test.ts
index 4d0f313f..21c589a7 100644
--- a/src/config/createConfig.test.ts
+++ b/src/config/createConfig.test.ts
@@ -19,14 +19,14 @@ describe('createConfig', () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.readdirSync as jest.Mock).mockReturnValue([])
})
-
+
it('throws when lng is not provided', () => {
expect(createConfig).toThrow('config.lng was not passed into createConfig')
})
-
+
it('returns a valid config when only lng is provided', () => {
const config = createConfig({ lng: 'en' } as UserConfig)
-
+
expect((config.backend as any).addPath).toMatch('/public/locales/{{lng}}/{{ns}}.missing.json')
expect((config.backend as any).loadPath).toMatch('/public/locales/{{lng}}/{{ns}}.json')
expect(config.defaultLocale).toEqual('en')
@@ -49,20 +49,20 @@ describe('createConfig', () => {
it('deep merges backend', () => {
const config = createConfig({
- lng: 'en',
backend: {
hello: 'world',
- }
+ },
+ lng: 'en',
} as UserConfig)
expect((config.backend as any).hello).toEqual('world')
})
it('deep merges detection', () => {
const config = createConfig({
- lng: 'en',
detection: {
hello: 'world',
- }
+ },
+ lng: 'en',
} as UserConfig)
expect((config.detection as any).hello).toEqual('world')
})
@@ -73,7 +73,7 @@ describe('createConfig', () => {
(fs.existsSync as jest.Mock).mockReturnValueOnce(false)
const config = createConfig.bind(null, {
- lng: 'en'
+ lng: 'en',
})
expect(config).toThrow('Default namespace not found at public/locales/en/common.json')
@@ -84,21 +84,21 @@ describe('createConfig', () => {
it('returns a config without calling any fs methods', () => {
(fs.existsSync as jest.Mock).mockReset();
(fs.readdirSync as jest.Mock).mockReset()
-
+
createConfig({
lng: 'en', use: [{
- type: 'backend'
+ type: 'backend',
}] } as UserConfig)
-
+
expect(fs.existsSync).toHaveBeenCalledTimes(0)
expect(fs.readdirSync).toHaveBeenCalledTimes(0)
})
})
- describe('ci mode', () => {
+ describe('ci mode', () => {
it('returns a config without calling any fs methods', () => {
createConfig({ lng: 'cimode' } as UserConfig)
-
+
expect(fs.existsSync).toHaveBeenCalledTimes(0)
expect(fs.readdirSync).toHaveBeenCalledTimes(0)
})
@@ -113,10 +113,10 @@ describe('createConfig', () => {
it('throws when lng is not provided', () => {
expect(createConfig).toThrow('config.lng was not passed into createConfig')
})
-
+
it('returns a valid config when only lng is provided', () => {
const config = createConfig({ lng: 'en' } as UserConfig)
-
+
expect((config.backend as any).addPath).toMatch('/public/locales/{{lng}}/{{ns}}.missing.json')
expect((config.backend as any).loadPath).toMatch('/public/locales/{{lng}}/{{ns}}.json')
expect(config.defaultLocale).toEqual('en')
@@ -129,7 +129,7 @@ describe('createConfig', () => {
expect(config.localeStructure).toEqual('{{lng}}/{{ns}}')
expect(config.locales).toEqual(['en'])
expect(config.ns).toEqual(['common'])
- expect(config.preload).toEqual(undefined)
+ expect(config.preload).toBeUndefined()
expect(config.strictMode).toEqual(true)
expect(config.use).toEqual([])
})
diff --git a/src/config/createConfig.ts b/src/config/createConfig.ts
index dde30fbb..b311f238 100644
--- a/src/config/createConfig.ts
+++ b/src/config/createConfig.ts
@@ -8,9 +8,9 @@ export const createConfig = (userConfig: UserConfig): InternalConfig => {
throw new Error('config.lng was not passed into createConfig')
}
- /*
- Initial merge of default and user-provided config
- */
+ //
+ // Initial merge of default and user-provided config
+ //
const { i18n: userI18n, ...userConfigStripped } = userConfig
const { i18n: defaultI18n, ...defaultConfigStripped } = defaultConfig
const combinedConfig = {
@@ -46,10 +46,10 @@ export const createConfig = (userConfig: UserConfig): InternalConfig => {
const path = require('path')
const serverLocalePath = localePath
- /*
- Validate defaultNS
- https://github.com/isaachinman/next-i18next/issues/358
- */
+ //
+ // Validate defaultNS
+ // https://github.com/isaachinman/next-i18next/issues/358
+ //
if (typeof combinedConfig.defaultNS === 'string') {
const defaultFile = `/${lng}/${combinedConfig.defaultNS}.${localeExtension}`
const defaultNSPath = path.join(localePath, defaultFile)
@@ -59,17 +59,17 @@ export const createConfig = (userConfig: UserConfig): InternalConfig => {
}
}
- /*
- Set server side backend
- */
+ //
+ // Set server side backend
+ //
combinedConfig.backend = {
- loadPath: path.resolve(process.cwd(), `${serverLocalePath}/${localeStructure}.${localeExtension}`),
addPath: path.resolve(process.cwd(), `${serverLocalePath}/${localeStructure}.missing.${localeExtension}`),
+ loadPath: path.resolve(process.cwd(), `${serverLocalePath}/${localeStructure}.${localeExtension}`),
}
- /*
- Set server side preload (namespaces)
- */
+ //
+ // Set server side preload (namespaces)
+ //
if (!combinedConfig.ns) {
const getAllNamespaces = p => fs.readdirSync(p).map(file => file.replace(`.${localeExtension}`, ''))
combinedConfig.ns = getAllNamespaces(path.resolve(process.cwd(), `${serverLocalePath}/${lng}`))
@@ -79,27 +79,27 @@ export const createConfig = (userConfig: UserConfig): InternalConfig => {
let clientLocalePath = localePath
- /*
- Remove public prefix from client site config
- */
+ //
+ // Remove public prefix from client site config
+ //
if (localePath.startsWith('/public/')) {
clientLocalePath = localePath.replace(/^\/public/, '')
}
- /*
- Set client side backend
- */
+ //
+ // Set client side backend
+ //
combinedConfig.backend = {
- loadPath: `${clientLocalePath}/${localeStructure}.${localeExtension}`,
addPath: `${clientLocalePath}/${localeStructure}.missing.${localeExtension}`,
+ loadPath: `${clientLocalePath}/${localeStructure}.${localeExtension}`,
}
combinedConfig.ns = [combinedConfig.defaultNS]
}
- /*
- Deep merge with overwrite - goes last
- */
+ //
+ // Deep merge with overwrite - goes last
+ //
deepMergeObjects.forEach((obj) => {
if (userConfig[obj]) {
combinedConfig[obj] = {
diff --git a/src/config/defaultConfig.ts b/src/config/defaultConfig.ts
index 0c62dc38..0eb78e46 100644
--- a/src/config/defaultConfig.ts
+++ b/src/config/defaultConfig.ts
@@ -6,29 +6,28 @@ const LOCALE_STRUCTURE = '{{lng}}/{{ns}}'
const LOCALE_EXTENSION = 'json'
export const defaultConfig = {
+ defaultNS: DEFAULT_NAMESPACE,
+ errorStackTraceLimit: 0,
i18n: {
defaultLocale: DEFAULT_LOCALE,
locales: LOCALES,
},
-
- load: 'currentOnly',
- localePath: LOCALE_PATH,
- localeStructure: LOCALE_STRUCTURE,
- localeExtension: LOCALE_EXTENSION,
- use: [],
- defaultNS: DEFAULT_NAMESPACE,
+ get initImmediate(): boolean {
+ return process.browser
+ },
interpolation: {
escapeValue: false,
- formatSeparator: ',',
format: (value: string, format: string): string => (format === 'uppercase' ? value.toUpperCase() : value),
+ formatSeparator: ',',
},
+ load: 'currentOnly',
+ localeExtension: LOCALE_EXTENSION,
+ localePath: LOCALE_PATH,
+ localeStructure: LOCALE_STRUCTURE,
react: {
- wait: true,
useSuspense: false,
+ wait: true,
},
strictMode: true,
- errorStackTraceLimit: 0,
- get initImmediate(): boolean {
- return process.browser
- }
+ use: [],
}
diff --git a/src/createClient/.eslintrc.json b/src/createClient/.eslintrc.json
new file mode 100644
index 00000000..cf664baf
--- /dev/null
+++ b/src/createClient/.eslintrc.json
@@ -0,0 +1,5 @@
+{
+ "rules": {
+ "import/no-default-export": "off"
+ }
+}
diff --git a/src/createClient/browser.test.ts b/src/createClient/browser.test.ts
index 7cb27e22..12c67a18 100644
--- a/src/createClient/browser.test.ts
+++ b/src/createClient/browser.test.ts
@@ -13,7 +13,9 @@ describe('createClientBrowser', () => {
expect(typeof client.initPromise.then).toEqual('function')
expect(typeof client.i18n.addResource).toEqual('function')
expect(typeof (client.i18n as any).translator).toEqual('object')
- expect((client.i18n.options as any).defaultLocale).toEqual(config.defaultLocale)
+ expect(
+ (client.i18n.options as any).defaultLocale
+ ).toEqual(config.defaultLocale)
expect((client.i18n.options as any).locales).toEqual(config.locales)
})
})
diff --git a/src/createClient/node.test.ts b/src/createClient/node.test.ts
index 9a7d2d9b..a977efc6 100644
--- a/src/createClient/node.test.ts
+++ b/src/createClient/node.test.ts
@@ -13,7 +13,9 @@ describe('createClientBrowser', () => {
expect(typeof client.initPromise.then).toEqual('function')
expect(typeof client.i18n.addResource).toEqual('function')
expect(typeof (client.i18n as any).translator).toEqual('object')
- expect((client.i18n.options as any).defaultLocale).toEqual(config.defaultLocale)
+ expect(
+ (client.i18n.options as any).defaultLocale
+ ).toEqual(config.defaultLocale)
expect((client.i18n.options as any).locales).toEqual(config.locales)
})
})
diff --git a/src/serverSideTranslations.ts b/src/serverSideTranslations.ts
index feb907d2..32a4151e 100644
--- a/src/serverSideTranslations.ts
+++ b/src/serverSideTranslations.ts
@@ -32,7 +32,7 @@ export const serverSideTranslations = async (
await initPromise
const initialI18nStore = {
- [initialLocale]: {}
+ [initialLocale]: {},
}
namespacesRequired.forEach((ns) => {
@@ -46,6 +46,6 @@ export const serverSideTranslations = async (
initialI18nStore,
initialLocale,
userConfig: serialize(userConfig),
- }
+ },
}
}
diff --git a/src/utils/consoleMessage.test.ts b/src/utils/consoleMessage.test.ts
index f6d25885..af03b4fc 100644
--- a/src/utils/consoleMessage.test.ts
+++ b/src/utils/consoleMessage.test.ts
@@ -1,10 +1,12 @@
+/* eslint-disable no-console */
+
import { consoleMessage } from '../../src/utils'
import { InternalConfig } from '../../types'
const consoleMessageStrictMode = (type, message) =>
consoleMessage(type, message, {
- strictMode: true,
errorStackTraceLimit: 0,
+ strictMode: true,
} as InternalConfig)
const consoleMessageNotStrictMode = (type, message) =>
@@ -90,20 +92,22 @@ describe('consoleMessage utility function', () => {
consoleMessageStrictMode('info', ['An', 'array', 'of', 'message'])
consoleMessageStrictMode('info', () => 'Function message')
- const [[errorObject1], [errorObject2], [errorObject3]] = consoleErrSpy.mock.calls
+ const [
+ [errorObject1], [errorObject2], [errorObject3],
+ ] = consoleErrSpy.mock.calls
expect(errorObject1.name).toBe('Meta')
expect(errorObject1.message).toMatch(
- "Param message needs to be of type: string. Instead, 'object' was provided",
+ 'Param message needs to be of type: string. Instead, \'object\' was provided',
)
expect(errorObject2.name).toBe('Meta')
expect(errorObject2.message).toMatch(
- "Param message needs to be of type: string. Instead, 'object' was provided",
+ 'Param message needs to be of type: string. Instead, \'object\' was provided',
)
expect(errorObject3.name).toBe('Meta')
expect(errorObject3.message).toMatch(
- "Param message needs to be of type: string. Instead, 'function' was provided",
+ 'Param message needs to be of type: string. Instead, \'function\' was provided',
)
})
})
diff --git a/src/utils/consoleMessage.ts b/src/utils/consoleMessage.ts
index 567fdd20..976888a2 100644
--- a/src/utils/consoleMessage.ts
+++ b/src/utils/consoleMessage.ts
@@ -1,6 +1,6 @@
/* eslint-disable no-console */
-import { InternalConfig } from "../../types"
+import { InternalConfig } from '../../types'
type MessageType = 'error' | 'info' | 'warn'
@@ -20,7 +20,11 @@ const logMessage = (messageType: MessageType, message: string) => {
}
}
-export const consoleMessage = (messageType: MessageType, message: string, config: InternalConfig): void => {
+export const consoleMessage = (
+ messageType: MessageType,
+ message: string,
+ config: InternalConfig
+): void => {
const { errorStackTraceLimit, strictMode } = config
@@ -38,20 +42,20 @@ export const consoleMessage = (messageType: MessageType, message: string, config
return
}
- /*
- Temporarily set the stacktrace to 0 or errorStackTraceLimit,
- in order to only display a message
- */
+ //
+ // Temporarily set the stacktrace to 0 or errorStackTraceLimit,
+ // in order to only display a message
+ //
Error.stackTraceLimit = errorStackTraceLimit
- /*
- Make room for new message
- */
+ //
+ // Make room for new message
+ //
console.log()
- /*
- Make sure the message is a string
- */
+ //
+ // Make sure the message is a string
+ //
if (typeof message !== 'string') {
const metaError = new Error()
metaError.name = 'Meta'
@@ -68,14 +72,14 @@ export const consoleMessage = (messageType: MessageType, message: string, config
return
}
- /*
- Log the message to console
- */
+ //
+ // Log the message to console
+ //
logMessage(messageType, message)
- /*
- Reset stack limit
- */
+ //
+ // Reset stack limit
+ //
Error.stackTraceLimit = prevStackLimit
}
diff --git a/types.d.ts b/types.d.ts
index 17fa445a..de66d87c 100644
--- a/types.d.ts
+++ b/types.d.ts
@@ -1,38 +1,36 @@
/* tslint:disable no-explicit-any */
-
-import * as React from 'react'
import {
I18nContext,
useTranslation,
Trans,
withTranslation,
- WithTranslation as ReactI18nextWithTranslation
+ WithTranslation as ReactI18nextWithTranslation,
} from 'react-i18next'
import { InitOptions, i18n, TFunction as I18NextTFunction } from 'i18next'
-import { appWithTranslation } from './src';
+import { appWithTranslation } from './src'
type NextJsI18NConfig = {
- defaultLocale: string;
- locales: string[];
+ defaultLocale: string
+ locales: string[]
}
export type UserConfig = {
- i18n: NextJsI18NConfig;
- localeExtension?: string;
- localePath?: string;
- localeStructure?: string;
- strictMode?: boolean;
- use?: any[];
+ i18n: NextJsI18NConfig
+ localeExtension?: string
+ localePath?: string
+ localeStructure?: string
+ strictMode?: boolean
+ use?: any[]
} & InitOptions
export type InternalConfig = Omit