UNPKG

@acuris/eslint-config

Version:
495 lines (412 loc) 13.5 kB
'use strict' const path = require('path') const nodeModules = require('../../core/node-modules') const { getRepositoryFromGitConfig, fileExists, findUp, runAsync } = require('./fs-utils') const { readTextFile } = require('./text-utils') const fs = require('fs') const referencePackageJson = require('../../package.json') const semver = require('semver') function addObjectKeysToSet(set, obj) { if (typeof obj === 'object' && obj !== null && !Array.isArray(obj)) { for (const key of Object.keys(obj)) { set.add(key) } } } function getNeededDependencies(manifest, cwd = process.cwd()) { const result = new Set() const allDeps = new Set() addObjectKeysToSet(allDeps, manifest.dependencies) addObjectKeysToSet(allDeps, manifest.devDependencies) addObjectKeysToSet(allDeps, manifest.peerDependencies) addObjectKeysToSet(allDeps, manifest.bundleDependencies) addObjectKeysToSet(allDeps, manifest.bundledDependencies) addObjectKeysToSet(allDeps, manifest.optionalDependencies) const hasDep = (name) => { if (allDeps.has(name)) { return true } if (isPackageInstalled(name)) { allDeps.add(name) return true } return false } if (hasDep('acuris-shared-component-tools')) { result.add('acuris-shared-component-tools') } else { if (manifest.name !== referencePackageJson.name) { result.add(referencePackageJson.name) } addObjectKeysToSet(result, referencePackageJson.peerDependencies) if (manifest.husky || hasDep('husky')) { result.add('husky') } if (manifest['lint-staged'] || hasDep('lint-staged')) { result.add('lint-staged') } if ( hasDep('typescript') || hasDep('@typescript-eslint/eslint-plugin') || hasDep('@typescript-eslint/parser') || fileExists(path.resolve(cwd, 'tsconfig.json')) || fileExists(path.resolve(cwd, 'index.ts')) || fileExists(path.resolve(cwd, 'index.d.ts')) || fileExists(path.resolve(cwd, 'src', 'index.ts')) ) { result.add('@types/node') result.add('@typescript-eslint/eslint-plugin') result.add('@typescript-eslint/parser') result.add('typescript') if (hasDep('mocha')) { result.add('@types/chai') } if (hasDep('chai')) { result.add('@types/chai') } if (hasDep('jest')) { result.add('@jest/types') } } if (hasDep('jest')) { result.add('eslint-plugin-jest') } if (hasDep('parcel')) { result.add('eslint-import-resolver-parcel') } if (hasDep('mocha')) { result.add('eslint-plugin-mocha') } if (hasDep('mocha') || hasDep('chai')) { result.add('eslint-plugin-chai-expect') } if (hasDep('react') || hasDep('react-scripts') || hasDep('webpack')) { result.add('eslint-plugin-jsx-a11y') result.add('eslint-plugin-react') result.add('eslint-plugin-css-modules') } } const ignoredPackages = nodeModules.projectConfig.ignoredPackages return new Set( Array.from(result) .filter((x) => !ignoredPackages.has(x)) .sort() ) } exports.getNeededDependencies = getNeededDependencies function sanitisePackageJson(manifest) { manifest = JSON.parse(JSON.stringify(manifest)) if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) { throw new Error(`package.json must be an object but is ${Array.isArray(manifest) ? 'Array' : typeof manifest}`) } if (typeof manifest.name !== 'string' || manifest.name.trim().length === 0) { throw new Error('package.json must contain a valid "name" property') } if (typeof manifest.version !== 'string' || manifest.version.trim().length === 0) { throw new Error('package.json must contain a valid "version" property') } if (!manifest.description) { manifest.description = manifest.name } if (!manifest.keywords) { manifest.keywords = [manifest.name] } if (!manifest.license) { manifest.license = 'UNLICENSED' } if (!manifest.repository) { const repository = getRepositoryFromGitConfig() if (repository) { manifest.repository = repository } } if (!manifest.homepage) { let repoUrl = manifest.repository && manifest.repository.url if (typeof repoUrl !== 'string' || !repoUrl.startsWith('http')) { repoUrl = getRepositoryFromGitConfig() } if (typeof repoUrl === 'string' && repoUrl.startsWith('http')) { if (repoUrl.endsWith('.git')) { repoUrl = repoUrl.slice(0, repoUrl.length - '.git'.length) } manifest.homepage = `${repoUrl}#readme` } } if (referencePackageJson.engines) { if (typeof manifest.engines !== 'object' || manifest.engines === null) { manifest.engines = {} } for (const key of Object.keys(referencePackageJson.engines)) { if (!manifest.engines[key]) { manifest.engines[key] = referencePackageJson.engines[key] } } } return manifest } exports.sanitisePackageJson = sanitisePackageJson function semverToVersion(version) { if (typeof version !== 'string') { return null } version = version.trim() if (version.length === 0) { return null } if (version.startsWith('file:') || version === 'latest') { return version } const indexOfLtEq = version.indexOf('<=') if (indexOfLtEq >= 0) { const found = semverToVersion(version.slice(indexOfLtEq + 2)) if (found) { return found } } const indexOfGtEq = version.indexOf('>=') if (indexOfGtEq >= 0) { let v = version.slice(indexOfGtEq + 2) const indexOfLt = v.indexOf('<') if (indexOfLt >= 0) { v = v.slice(0, indexOfLt) } const found = semver.parse(v, { loose: true, includePrerelease: true }) if (found && found.version) { return found.version } } let minVer try { minVer = semver.minVersion(version, { includePrerelease: true, loose: true }) if (minVer.raw !== version && minVer.raw === '0.0.0') { minVer = undefined } } catch (_error) {} const parsed = minVer || semver.parse(version, { loose: true, includePrerelease: true }) || semver.coerce(version) let v = parsed && parsed.version if (v.endsWith('-0')) { v = v.slice(0, v.length - 2).trim() } return v } exports.semverToVersion = semverToVersion function getMaxSemver(version, range) { if (typeof range !== 'string') { range = '' } else { range = range.trim() } version = semverToVersion(version) if (typeof version === 'string' && (version.startsWith('file:') || version === 'latest')) { return version } if (range) { if (range.startsWith('file:') || range === 'latest') { return range } const r = semverToVersion(range) || range if (typeof version === 'string') { try { if (semver.ltr(version, r, { includePrerelease: true, loose: true })) { version = r } } catch (_error) {} } else if (r) { return r } } return version || null } exports.getMaxSemver = getMaxSemver function inferPackageVersion(name, projectPackageJson, canUseReferencePackage = true) { let v if (name === referencePackageJson.name) { return referencePackageJson.version } if (projectPackageJson) { v = getMaxSemver(v, projectPackageJson.dependencies && projectPackageJson.dependencies[name]) v = getMaxSemver(v, projectPackageJson.devDependencies && projectPackageJson.devDependencies[name]) v = getMaxSemver(v, projectPackageJson.peerDependencies && projectPackageJson.peerDependencies[name]) v = getMaxSemver(v, projectPackageJson.optionalDependencies && projectPackageJson.optionalDependencies[name]) } if (canUseReferencePackage || !v) { v = getMaxSemver(v, referencePackageJson.dependencies && referencePackageJson.dependencies[name]) v = getMaxSemver(v, referencePackageJson.devDependencies && referencePackageJson.devDependencies[name]) v = getMaxSemver(v, referencePackageJson.peerDependencies && referencePackageJson.peerDependencies[name]) } if (!v) { return null } if (!v.startsWith('file:') && v !== 'latest' && nodeModules.hasLocalPackage(name)) { const pkgName = `${name}/package.json` let pkg try { pkg = require(pkgName) } catch (_error) {} if (pkg && pkg.version) { v = getMaxSemver(v, pkg.version) } } return v } exports.inferPackageVersion = inferPackageVersion function addDevDependencies(projectPackageJson, listOfDependenciesToAdd) { let result = false for (const name of listOfDependenciesToAdd) { let v = inferPackageVersion(name, projectPackageJson) if (!v) { continue } if (semver.parse(v, { includePrerelease: true })) { v = `^${v}` } if (projectPackageJson.dependencies && projectPackageJson.dependencies[name]) { if (projectPackageJson.dependencies[name] !== v) { result = true projectPackageJson.dependencies[name] = v } } else if (!projectPackageJson.devDependencies || projectPackageJson.devDependencies[name] !== v) { result = true if (!projectPackageJson.devDependencies) { projectPackageJson.devDependencies = {} } projectPackageJson.devDependencies[name] = v } } return result } exports.addDevDependencies = addDevDependencies function checkInstalledPackageVersion(version, expectedVersion) { if (typeof version !== 'string' || version.length === 0) { return false } expectedVersion = typeof expectedVersion === 'string' ? expectedVersion.trim() : '' if (expectedVersion === 'latest' || expectedVersion.startsWith('file:')) { return true } if (expectedVersion.length !== 0) { try { if (semver.ltr(version, expectedVersion, { includePrerelease: true })) { return false } } catch (_error) {} try { if (semver.ltr(semverToVersion(version), semverToVersion(expectedVersion), { includePrerelease: true })) { return false } } catch (_error) {} } return true } function isPackageInstalled(name, expectedVersion = null) { if (typeof name !== 'string' || name.length === 0) { return false } let pkg let resolved if (!resolved) { const found = path.resolve(process.cwd(), 'node_modules', name, 'package.json') if (fileExists(found)) { resolved = found } } if (!resolved) { const found = path.resolve(process.cwd(), 'acuris-shared-component-tools', 'node_modules', name, 'package.json') if (fileExists(found)) { resolved = found } } for (const nodeModulesFolder of nodeModules.legacyNodeModulePaths(process.cwd())) { if (!nodeModules.isGlobalPath(nodeModulesFolder)) { const found = path.resolve(nodeModulesFolder, name, 'package.json') if (fileExists(found)) { resolved = found break } } } if (resolved) { try { pkg = require(resolved) } catch (_error) {} } if (checkInstalledPackageVersion(pkg && pkg.version, expectedVersion)) { return true } return false } exports.isPackageInstalled = isPackageInstalled function getPackageJsonPath(cwd = process.cwd()) { return findUp('package.json', { directories: false, files: true, cwd }) || path.join(cwd, 'package.json') } exports.getPackageJsonPath = getPackageJsonPath function readProjectPackageJson(packageJsonPath = getPackageJsonPath()) { if (!packageJsonPath) { return false } let manifest try { manifest = readTextFile(packageJsonPath, 'json-stringify') } catch (_error) {} return typeof manifest === 'object' && manifest !== null && !Array.isArray(manifest) ? manifest : undefined } exports.readProjectPackageJson = readProjectPackageJson function getPackagesToInstall(manifest = readProjectPackageJson()) { const result = [] if (!manifest) { return result } const allDeps = new Map() for (const k of ['devDependencies', 'dependencies']) { const d = manifest[k] if (typeof d === 'object' && d !== null && !Array.isArray(d)) { for (const key of Object.keys(d)) { if (typeof d[key] === 'string') { allDeps.set(key, getMaxSemver(d[key], allDeps.get(key)) || d[key]) } } } } for (const [name, version] of allDeps) { const inferredVersion = inferPackageVersion(name, manifest, false) || version if (!isPackageInstalled(name, inferredVersion)) { result.push( `${name}@${ inferredVersion.startsWith('^') || inferredVersion.startsWith('~') ? inferredVersion.slice(1) : inferredVersion }` ) } } return result } exports.getPackagesToInstall = getPackagesToInstall function getPackageManager(cwd = path.dirname(getPackageJsonPath())) { let yarnDate let packageLockDate try { const stats = fs.statSync(path.resolve(cwd, 'yarn.lock')) yarnDate = stats.isFile() && stats.mtimeMs } catch (_error) {} try { const stats = fs.statSync(path.resolve(cwd, 'package-lock.json')) packageLockDate = stats.isFile() && stats.mtimeMs } catch (_error) {} if (packageLockDate > yarnDate) { return 'npm' } if (yarnDate > packageLockDate) { return 'yarn' } return undefined } exports.getPackageManager = getPackageManager async function getNpmRegistry() { let registry try { registry = await runAsync('npm', 'config', 'get', 'registry') } catch (_error) {} return registry || 'https://registry.npmjs.org/' } exports.getNpmRegistry = getNpmRegistry