From aa6c8fb569889f72b1fa0a718c20684fa9ef0b76 Mon Sep 17 00:00:00 2001 From: Kunal Kundu <51631122+tinfoil-knight@users.noreply.github.com> Date: Mon, 12 Jul 2021 22:23:57 +0530 Subject: [PATCH] fix: enable and fix fp/no-loops (#2852) --- .eslintrc.js | 4 +- src/commands/env/import.js | 4 +- src/commands/env/list.js | 4 +- src/commands/init.js | 2 +- src/commands/link.js | 2 +- src/detectors/utils/jsdetect.js | 18 ++--- .../runtimes/js/builders/netlify-lambda.js | 1 + src/lib/functions/synchronous.js | 20 ++++-- src/utils/detect-functions-builder.js | 1 + src/utils/detect-server.js | 7 +- src/utils/dev.js | 13 ++-- src/utils/get-global-config.js | 1 + src/utils/get-global-config.test.js | 1 - src/utils/gitignore.js | 70 +------------------ src/utils/headers.js | 1 + src/utils/state-config.js | 6 +- tests/utils/dev-server.js | 1 + tests/utils/site-builder.js | 1 + 18 files changed, 42 insertions(+), 115 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 240b67f5287..96674974ce3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,7 +18,7 @@ module.exports = { 'fp/no-delete': 0, 'fp/no-get-set': 0, 'fp/no-let': 0, - 'fp/no-loops': 0, + 'fp/no-loops': 'error', 'fp/no-mutating-assign': 0, 'fp/no-mutating-methods': 0, 'fp/no-mutation': 0, @@ -28,7 +28,6 @@ module.exports = { 'node/no-sync': 0, 'unicorn/prefer-spread': 0, 'unicorn/consistent-destructuring': 0, - // TODO: harmonize with filename snake_case in other Netlify Dev projects 'unicorn/filename-case': [2, { case: 'kebabCase' }], }, @@ -55,6 +54,7 @@ module.exports = { 'node/no-unsupported-features/es-syntax': 0, 'unicorn/consistent-destructuring': 0, 'max-lines': 0, + 'array-callback-return': ['error', { checkForEach: true }], }, }, // Example functions diff --git a/src/commands/env/import.js b/src/commands/env/import.js index 1edbf3f4c59..ccac475f69f 100644 --- a/src/commands/env/import.js +++ b/src/commands/env/import.js @@ -64,9 +64,7 @@ class EnvImportCommand extends Command { const table = new AsciiTable(`Imported environment variables`) table.setHeading('Key', 'Value') - for (const [key, value] of Object.entries(importedEnv)) { - table.addRow(key, value) - } + table.addRowMatrix(Object.entries(importedEnv)) this.log(table.toString()) } } diff --git a/src/commands/env/list.js b/src/commands/env/list.js index ffa813814ea..a1e42af3a9b 100644 --- a/src/commands/env/list.js +++ b/src/commands/env/list.js @@ -39,9 +39,7 @@ class EnvListCommand extends Command { const table = new AsciiTable(`Environment variables`) table.setHeading('Key', 'Value') - for (const [key, value] of Object.entries(environment)) { - table.addRow(key, value) - } + table.addRowMatrix(Object.entries(environment)) this.log(table.toString()) } } diff --git a/src/commands/init.js b/src/commands/init.js index e665ff68fbb..e73ffbcef11 100644 --- a/src/commands/init.js +++ b/src/commands/init.js @@ -6,7 +6,7 @@ const isEmpty = require('lodash/isEmpty') const Command = require('../utils/command') const { getRepoData } = require('../utils/get-repo-data') -const { ensureNetlifyIgnore } = require('../utils/gitignore') +const ensureNetlifyIgnore = require('../utils/gitignore') const { configureRepo } = require('../utils/init/config') const { track } = require('../utils/telemetry') diff --git a/src/commands/link.js b/src/commands/link.js index d3d17bfc37b..4c10a2fc74b 100644 --- a/src/commands/link.js +++ b/src/commands/link.js @@ -6,7 +6,7 @@ const chalk = require('chalk') const { listSites } = require('../lib/api') const Command = require('../utils/command') -const { ensureNetlifyIgnore } = require('../utils/gitignore') +const ensureNetlifyIgnore = require('../utils/gitignore') const linkPrompt = require('../utils/link/link-by-prompt') const { track } = require('../utils/telemetry') diff --git a/src/detectors/utils/jsdetect.js b/src/detectors/utils/jsdetect.js index 462abe1010f..a1cf0e968bf 100644 --- a/src/detectors/utils/jsdetect.js +++ b/src/detectors/utils/jsdetect.js @@ -33,22 +33,12 @@ const getYarnOrNPMCommand = function () { const hasRequiredDeps = function (requiredDepArray) { const { dependencies, devDependencies } = getPkgJSON() - for (const depName of requiredDepArray) { - const hasItInDeps = dependencies && dependencies[depName] - const hasItInDevDeps = devDependencies && devDependencies[depName] - if (!hasItInDeps && !hasItInDevDeps) { - return false - } - } - return true + const allDependencies = { ...dependencies, ...devDependencies } + return requiredDepArray.every((depName) => allDependencies[depName]) } + const hasRequiredFiles = function (filenameArr) { - for (const filename of filenameArr) { - if (!existsSync(filename)) { - return false - } - } - return true + return filenameArr.every((filename) => existsSync(filename)) } // preferredScriptsArr is in decreasing order of preference diff --git a/src/lib/functions/runtimes/js/builders/netlify-lambda.js b/src/lib/functions/runtimes/js/builders/netlify-lambda.js index cba9101b2ea..4d9b1959ae2 100644 --- a/src/lib/functions/runtimes/js/builders/netlify-lambda.js +++ b/src/lib/functions/runtimes/js/builders/netlify-lambda.js @@ -14,6 +14,7 @@ const detectNetlifyLambda = async function ({ packageJson } = {}) { const matchingScripts = Object.entries(scripts).filter(([, script]) => script.match(/netlify-lambda\s+build/)) + // eslint-disable-next-line fp/no-loops for (const [key, script] of matchingScripts) { // E.g. ["netlify-lambda", "build", "functions/folder"] const match = minimist(script.split(' ')) diff --git a/src/lib/functions/synchronous.js b/src/lib/functions/synchronous.js index 671b2482590..5ad5e240ff2 100644 --- a/src/lib/functions/synchronous.js +++ b/src/lib/functions/synchronous.js @@ -2,6 +2,16 @@ const { Buffer } = require('buffer') const { NETLIFYDEVERR } = require('../../utils/logo') +const addHeaders = (headers, response) => { + if (!headers) { + return + } + + Object.entries(headers).forEach(([key, value]) => { + response.setHeader(key, value) + }) +} + const handleSynchronousFunction = function (err, result, response) { if (err) { return handleErr(err, response) @@ -14,13 +24,9 @@ const handleSynchronousFunction = function (err, result, response) { } response.statusCode = result.statusCode - for (const key in result.headers) { - response.setHeader(key, result.headers[key]) - } - for (const key in result.multiValueHeaders) { - const items = result.multiValueHeaders[key] - response.setHeader(key, items) - } + addHeaders(result.headers, response) + addHeaders(result.multiValueHeaders, response) + if (result.body) { response.write(result.isBase64Encoded ? Buffer.from(result.body, 'base64') : result.body) } diff --git a/src/utils/detect-functions-builder.js b/src/utils/detect-functions-builder.js index 860f2c29aef..ea6558c978a 100644 --- a/src/utils/detect-functions-builder.js +++ b/src/utils/detect-functions-builder.js @@ -12,6 +12,7 @@ const detectFunctionsBuilder = async function (parameters) { // eslint-disable-next-line node/global-require, import/no-dynamic-require .map((det) => require(path.join(buildersPath, det))) + // eslint-disable-next-line fp/no-loops for (const detector of detectors) { // eslint-disable-next-line no-await-in-loop const settings = await detector(parameters) diff --git a/src/utils/detect-server.js b/src/utils/detect-server.js index 226c082b6f2..2893e866352 100644 --- a/src/utils/detect-server.js +++ b/src/utils/detect-server.js @@ -58,7 +58,6 @@ const serverSettings = async (devConfig, flags, projectDir, log) => { } }) } else if (devConfig.framework === '#auto' && !(devConfig.command && devConfig.targetPort)) { - const settingsArr = [] const detectors = detectorsFiles.map((det) => { try { return loadDetector(det) @@ -67,10 +66,8 @@ const serverSettings = async (devConfig, flags, projectDir, log) => { return null } }) - for (const detector of detectors) { - const detectorResult = detector(projectDir) - if (detectorResult) settingsArr.push(detectorResult) - } + + const settingsArr = detectors.map((detector) => detector(projectDir)).filter((el) => el) if (settingsArr.length === 1) { const [firstSettings] = settingsArr settings = firstSettings diff --git a/src/utils/dev.js b/src/utils/dev.js index d2b82f05761..d8e1c6183d7 100644 --- a/src/utils/dev.js +++ b/src/utils/dev.js @@ -135,8 +135,8 @@ const injectEnvVariables = async ({ env, log, site, warn }) => { const environment = new Map(Object.entries(env)) const dotEnvFiles = await loadDotEnvFiles({ projectDir: site.root, warn }) - for (const { file, env: fileEnv } of dotEnvFiles) { - for (const key in fileEnv) { + dotEnvFiles.forEach(({ file, env: fileEnv }) => { + Object.keys(fileEnv).forEach((key) => { const newSourceName = `${file} file` const sources = environment.has(key) ? [newSourceName, ...environment.get(key).sources] : [newSourceName] @@ -144,15 +144,16 @@ const injectEnvVariables = async ({ env, log, site, warn }) => { sources, value: fileEnv[key], }) - } - } + }) + }) + // eslint-disable-next-line fp/no-loops for (const [key, variable] of environment) { const existsInProcess = process.env[key] !== undefined const [usedSource, ...overriddenSources] = existsInProcess ? ['process', ...variable.sources] : variable.sources const usedSourceName = getEnvSourceName(usedSource) - for (const source of overriddenSources) { + overriddenSources.forEach((source) => { const sourceName = getEnvSourceName(source) log( @@ -162,7 +163,7 @@ const injectEnvVariables = async ({ env, log, site, warn }) => { )} (defined in ${usedSourceName})`, ), ) - } + }) if (!existsInProcess) { // Omitting `general` env vars to reduce noise in the logs. diff --git a/src/utils/get-global-config.js b/src/utils/get-global-config.js index da61f4ce243..58971df5e85 100644 --- a/src/utils/get-global-config.js +++ b/src/utils/get-global-config.js @@ -30,6 +30,7 @@ const getGlobalConfigOnce = async function () { const getGlobalConfig = async function () { const retries = 3 + // eslint-disable-next-line fp/no-loops for (let retry = 1; retry <= retries; retry++) { try { // eslint-disable-next-line no-await-in-loop diff --git a/src/utils/get-global-config.test.js b/src/utils/get-global-config.test.js index 3674a3458cc..9e35a3f8b6c 100644 --- a/src/utils/get-global-config.test.js +++ b/src/utils/get-global-config.test.js @@ -68,7 +68,6 @@ test.serial("should create config in netlify's config dir if none exists and sto // Remove config dirs await rmdirRecursiveAsync(getPathInHome([])) await rmdirRecursiveAsync(getLegacyPathInHome([])) - const globalConfig = await getGlobalConfig() globalConfig.set('newProp', 'newValue') const configFile = JSON.parse(await readFileAsync(configPath)) diff --git a/src/utils/gitignore.js b/src/utils/gitignore.js index 2943c1d8895..a4ff2ee8da3 100644 --- a/src/utils/gitignore.js +++ b/src/utils/gitignore.js @@ -10,69 +10,6 @@ const hasGitIgnore = async function (dir) { return hasIgnore } -const parser = function (input, fn = (line) => line) { - const lines = input.toString().split(/\r?\n/) - let section = { name: 'default', patterns: [] } - const state = { patterns: [], sections: [section] } - - for (const line of lines) { - if (line.charAt(0) === '#') { - section = { name: line.slice(1).trim(), patterns: [] } - state.sections.push(section) - continue - } - - if (line.trim() !== '') { - const pattern = fn(line, section, state) - section.patterns.push(pattern) - state.patterns.push(pattern) - } - } - return state -} - -const stringify = function (state) { - return parseIgnore.stringify(state.sections, (section) => { - if (section.patterns.length === 0) { - return '' - } - - return `# ${section.name}\n${section.patterns.join('\n')}\n\n` - }) -} - -const parse = function (input, fn) { - const state = parser(input, fn) - - state.concat = (stateInput) => { - const newState = parser(stateInput, fn) - - for (const s2 in newState.sections) { - const sec2 = newState.sections[s2] - - let sectionExists = false - for (const s1 in state.sections) { - const sec1 = state.sections[s1] - - // Join sections under common name - if (sec1.name === sec2.name) { - sectionExists = true - sec1.patterns = [...new Set(sec1.patterns.concat(sec2.patterns))] - } - } - - // Add new section - if (!sectionExists) { - state.sections.push(sec2) - } - } - - return state - } - - return state -} - const ensureNetlifyIgnore = async function (dir) { const gitIgnorePath = path.join(dir, '.gitignore') const ignoreContent = '# Local Netlify folder\n.netlify' @@ -98,9 +35,4 @@ const ensureNetlifyIgnore = async function (dir) { } } -module.exports = { - parse, - stringify, - format: parseIgnore.format, - ensureNetlifyIgnore, -} +module.exports = ensureNetlifyIgnore diff --git a/src/utils/headers.js b/src/utils/headers.js index 944764185a2..e1b9f3acfab 100644 --- a/src/utils/headers.js +++ b/src/utils/headers.js @@ -86,6 +86,7 @@ const parseHeadersFile = function (filePath) { let path let rules = {} + // eslint-disable-next-line fp/no-loops for (const { line, index } of lines) { if (line.startsWith(TOKEN_PATH)) { path = line diff --git a/src/utils/state-config.js b/src/utils/state-config.js index 0c0c1f7d22f..d750581f0c1 100644 --- a/src/utils/state-config.js +++ b/src/utils/state-config.js @@ -84,9 +84,9 @@ class StateConfig { const config = this.all if (args.length === 1) { - for (const keyPart of Object.keys(key)) { - dotProp.set(config, keyPart, key[keyPart]) - } + Object.entries(key).forEach(([keyPart, value]) => { + dotProp.set(config, keyPart, value) + }) } else { dotProp.set(config, key, val) } diff --git a/tests/utils/dev-server.js b/tests/utils/dev-server.js index 179f875e80d..ec2272f335f 100644 --- a/tests/utils/dev-server.js +++ b/tests/utils/dev-server.js @@ -71,6 +71,7 @@ const startServer = async ({ cwd, offline = true, env = {}, args = [] }) => { const startDevServer = async (options, expectFailure) => { const maxAttempts = 5 + // eslint-disable-next-line fp/no-loops for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { // eslint-disable-next-line no-await-in-loop diff --git a/tests/utils/site-builder.js b/tests/utils/site-builder.js index c22c6bfae6b..372d76a93ed 100644 --- a/tests/utils/site-builder.js +++ b/tests/utils/site-builder.js @@ -150,6 +150,7 @@ const createSiteBuilder = ({ siteName }) => { return builder }, buildAsync: async () => { + // eslint-disable-next-line fp/no-loops for (const task of tasks) { // eslint-disable-next-line no-await-in-loop await task()