@acuris/eslint-config
Version:
Acuris eslint shareable configuration
186 lines (153 loc) • 5.71 kB
JavaScript
/* eslint-disable node/no-missing-require */
/* eslint-disable global-require */
const { eslintRequire, hasLocalPackage, hasPackage, projectConfig } = require('./node-modules')
const fs = require('fs')
const { resolve: pathResolve, dirname: pathDirname } = require('path')
const { isArray } = Array
const { assign: objectAssign, keys: objectKeys } = Object
const defaultReactVersion = '16.13.1'
exports.projectConfig = projectConfig
/** Is running in a continous integration server? */
exports.isCI = projectConfig.isCI
/** @type {string} The react version supported by the project */
exports.reactVersion = projectConfig.reactVersion || getReactVersion()
exports.hasEslint = hasPackage('eslint')
exports.hasTypescript =
hasLocalPackage('@typescript-eslint/parser') &&
hasLocalPackage('@typescript-eslint/eslint-plugin') &&
hasLocalPackage('typescript')
exports.tsConfigPath = projectConfig.tsConfigPath || findFileUp('tsconfig.json') || undefined
exports.hasEslintImportResolverParcel = hasLocalPackage('eslint-import-resolver-parcel')
exports.hasEslintPluginCssModules = hasLocalPackage('eslint-plugin-css-modules')
exports.hasEslintPluginImport = hasLocalPackage('eslint-plugin-import')
exports.hasEslintPluginNode = hasLocalPackage('eslint-plugin-node')
exports.hasEslintPluginReact = hasLocalPackage('eslint-plugin-react')
exports.hasEslintPluginJsxA11y = hasLocalPackage('eslint-plugin-jsx-a11y')
exports.hasEslintPluginJest =
hasLocalPackage('eslint-plugin-jest') && (hasPackage('jest') || fs.existsSync('jest.config.js'))
exports.hasEslintPluginMocha =
hasLocalPackage('eslint-plugin-mocha') && (hasLocalPackage('mocha') || !hasPackage('jest'))
exports.hasEslintPluginChaiExpect =
hasLocalPackage('eslint-plugin-chai-expect') && (hasLocalPackage('chai') || !hasPackage('jest'))
exports.hasEslintPluginPromise = hasLocalPackage('eslint-plugin-promise')
exports.hasEslintPluginJson = hasLocalPackage('eslint-plugin-json')
/**
* Merges multiple eslint configurations together or clones the given one.
* @template T
* @param {...readonly T?} sources The sources to merge
* @returns {Required<T>} A new merged configuration
*/
function mergeEslintConfigs(...sources) {
let result = {}
for (let i = 0; i < sources.length; ++i) {
const source = sources[i]
if (source !== null && source !== undefined) {
if (typeof source !== 'object') {
throw new TypeError(`eslint configuration ${i} must be an object but is a ${typeof source}`)
}
result = isArray(source) ? mergeEslintConfigs(result, ...source) : eslintConfigsDeepMerge(result, source, true)
}
}
return result
}
exports.eslintRequire = eslintRequire
exports.mergeEslintConfigs = mergeEslintConfigs
exports.getMergedOverridesRules = getMergedOverridesRules
function getMergedOverridesRules(...configs) {
const result = {}
for (const config of configs) {
const overrides = config.overrides
if (isArray(overrides)) {
for (const override of overrides) {
const rules = override && override.rules
if (typeof rules === 'object') {
objectAssign(result, rules)
}
}
}
}
return result
}
function getReactVersion() {
let version = defaultReactVersion
if (hasLocalPackage('react')) {
try {
// eslint-disable-next-line import/no-unresolved
version = require('react/package.json').version
} catch (_error) {}
}
return version
}
function eslintConfigsDeepMerge(target, src, combine, isRule) {
/*
* This code is inspired by deepmerge and eslint
* (https://github.com/KyleAMathews/deepmerge)
*/
const array = isArray(src) || isArray(target)
let dst = (array && []) || {}
if (array) {
const resolvedTarget = target || []
// src could be a string, so check for array
if (isRule && isArray(src) && src.length > 1) {
dst = dst.concat(src)
} else {
dst = dst.concat(resolvedTarget)
}
const resolvedSrc = typeof src === 'object' ? src : [src]
const keys = objectKeys(resolvedSrc)
for (let i = 0, len = keys.length; i !== len; ++i) {
const e = resolvedSrc[i]
if (dst[i] === undefined) {
dst[i] = e
} else if (typeof e === 'object') {
if (isRule) {
dst[i] = e
} else {
dst[i] = eslintConfigsDeepMerge(resolvedTarget[i], e, combine, isRule)
}
} else if (!combine) {
dst[i] = e
} else if (dst.indexOf(e) === -1) {
dst.push(e)
}
}
} else {
if (target && typeof target === 'object') {
objectAssign(dst, target)
}
const keys = objectKeys(src)
for (let i = 0, len = keys.length; i !== len; ++i) {
const key = keys[i]
if (key === 'overrides') {
const overrides = (target[key] || []).concat(src[key] || [])
if (overrides.length !== 0) {
dst[key] = overrides
}
} else if (isArray(src[key]) || isArray(target[key])) {
dst[key] = eslintConfigsDeepMerge(target[key], src[key], key === 'plugins' || key === 'extends', isRule)
} else if (typeof src[key] !== 'object' || !src[key] || key === 'exported' || key === 'astGlobals') {
dst[key] = src[key]
} else {
dst[key] = eslintConfigsDeepMerge(target[key] || {}, src[key], combine, key === 'rules')
}
}
}
return dst
}
function findFileUp(filename) {
let result
let p = process.cwd()
for (;;) {
const resolvedPath = pathResolve(p, filename)
if (fs.existsSync(resolvedPath)) {
return resolvedPath
}
const parent = pathDirname(p) || ''
if (parent.length === p.length) {
break
}
p = parent
}
return result
}