diff --git a/eslint.config.js b/eslint.config.js index 35ca84007..a2177834e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -231,6 +231,7 @@ const configs = antfu( }], 'unicorn/explicit-length-check': 'error', 'unicorn/new-for-builtins': 'error', + 'unicorn/no-array-reduce': 'error', 'unicorn/no-for-loop': 'error', 'unicorn/no-invalid-remove-event-listener': 'error', 'unicorn/no-lonely-if': 'error', @@ -267,7 +268,6 @@ const configs = antfu( 'unicorn/require-number-to-fixed-digits-argument': 'error', // Might want to enable these - 'unicorn/no-array-reduce': 'off', 'unicorn/no-array-for-each': 'off', 'unicorn/no-await-expression-member': 'off', 'unicorn/no-negated-condition': 'off', diff --git a/src/authentication/UnionCredentialsExtractor.ts b/src/authentication/UnionCredentialsExtractor.ts index e1ed4c925..1452929e5 100644 --- a/src/authentication/UnionCredentialsExtractor.ts +++ b/src/authentication/UnionCredentialsExtractor.ts @@ -14,12 +14,13 @@ export class UnionCredentialsExtractor extends UnionHandler { // Combine all the results into a single object - return results.reduce((result, credentials): Credentials => { - for (const key of Object.keys(credentials) as (keyof Credentials)[]) { - this.setValue(result, key, credentials[key]); + const credentials: Credentials = {}; + for (const result of results) { + for (const key of Object.keys(result) as (keyof Credentials)[]) { + this.setValue(credentials, key, result[key]); } - return result; - }, {}); + } + return credentials; } /** diff --git a/src/http/input/preferences/UnionPreferenceParser.ts b/src/http/input/preferences/UnionPreferenceParser.ts index 32a23f84c..5a5684d75 100644 --- a/src/http/input/preferences/UnionPreferenceParser.ts +++ b/src/http/input/preferences/UnionPreferenceParser.ts @@ -18,15 +18,16 @@ export class UnionPreferenceParser extends UnionHandler { throw new InternalServerError('Found multiple range values. This implies a misconfiguration.'); } - return results.reduce((acc, val): RepresentationPreferences => { - for (const key of Object.keys(val) as (keyof RepresentationPreferences)[]) { + const preferences: RepresentationPreferences = {}; + for (const result of results) { + for (const key of Object.keys(result) as (keyof RepresentationPreferences)[]) { if (key === 'range') { - acc[key] = val[key]; + preferences[key] = result[key]; } else { - acc[key] = { ...acc[key], ...val[key] }; + preferences[key] = { ...preferences[key], ...result[key] }; } } - return acc; - }, {}); + } + return preferences; } } diff --git a/src/server/util/RedirectingHttpHandler.ts b/src/server/util/RedirectingHttpHandler.ts index 4b1c4c09e..2cf766dd5 100644 --- a/src/server/util/RedirectingHttpHandler.ts +++ b/src/server/util/RedirectingHttpHandler.ts @@ -97,10 +97,10 @@ export class RedirectingHttpHandler extends HttpHandler { // Build redirect URL from regexp result const { match, redirectPattern } = result; - const redirect = match.reduce( - (prev, param, index): string => prev.replace(`$${index}`, param), - redirectPattern, - ); + let redirect = redirectPattern; + for (const [ i, element ] of match.entries()) { + redirect = redirect.replace(`$${i}`, element); + } // Don't redirect if target is already correct if (redirect === target) { diff --git a/src/storage/conversion/ChainedConverter.ts b/src/storage/conversion/ChainedConverter.ts index afa04be5d..5bcc8c4cc 100644 --- a/src/storage/conversion/ChainedConverter.ts +++ b/src/storage/conversion/ChainedConverter.ts @@ -188,13 +188,13 @@ export class ChainedConverter extends RepresentationConverter { * Will return undefined if there are no matches. */ private findBest(paths: ConversionPath[]): ConversionPath | undefined { - // Need to use null instead of undefined so `reduce` doesn't take the first element of the array as `best` - return paths.reduce((best: ConversionPath | null, path): ConversionPath | null => { + let best: ConversionPath | undefined; + for (const path of paths) { if (path.weight > 0 && !(best && best.weight >= path.weight)) { - return path; + best = path; } - return best; - }, null) ?? undefined; + } + return best; } /** diff --git a/src/storage/conversion/ConversionUtil.ts b/src/storage/conversion/ConversionUtil.ts index 247e60783..ac282a8c0 100644 --- a/src/storage/conversion/ConversionUtil.ts +++ b/src/storage/conversion/ConversionUtil.ts @@ -113,20 +113,20 @@ export function getWeightedPreferences(types: ValuePreferences, preferred: Value * Undefined if there is no match. */ export function getBestPreference(types: ValuePreferences, preferred: ValuePreferences): ValuePreference | undefined { - // Could also return the first entry of the above function but this is more efficient - const result = Object.entries(types).reduce((best, [ value, quality ]): ValuePreference => { + // Could also return the first entry of `getWeightedPreferences` but this is more efficient + let best: ValuePreference = { value: '', weight: 0 }; + for (const [ value, quality ] of Object.entries(types)) { if (best.weight >= quality) { - return best; + continue; } const weight = quality * getTypeWeight(value, preferred); if (weight > best.weight) { - return { value, weight }; + best = { value, weight }; } - return best; - }, { value: '', weight: 0 }); + } - if (result.weight > 0) { - return result; + if (best.weight > 0) { + return best; } } diff --git a/src/storage/keyvalue/WrappedIndexedStorage.ts b/src/storage/keyvalue/WrappedIndexedStorage.ts index 5b95866c8..52c18a91f 100644 --- a/src/storage/keyvalue/WrappedIndexedStorage.ts +++ b/src/storage/keyvalue/WrappedIndexedStorage.ts @@ -526,7 +526,11 @@ export class WrappedIndexedStorage> implements indexResults.push(rootIds); } - return indexResults.reduce((acc, ids): string[] => acc.filter((id): boolean => ids.includes(id))); + let indexedRoots: string[] = indexResults[0]; + for (const ids of indexResults.slice(1)) { + indexedRoots = indexedRoots.filter((id): boolean => ids.includes(id)); + } + return indexedRoots; } /** @@ -581,9 +585,13 @@ export class WrappedIndexedStorage> implements } // For all keys that were not handled recursively: make sure that it matches the found objects - const remainingKeys = Object.keys(query).filter((key): boolean => - key !== relation?.child.key || typeof query[key] === 'string'); - return remainingKeys.reduce((acc, key): any[] => acc.filter((obj): boolean => obj[key] === query[key]), objs); + const remainingKeys = Object.keys(query).filter( + (key): boolean => key !== relation?.child.key || typeof query[key] === 'string', + ); + for (const key of remainingKeys) { + objs = objs.filter((obj): boolean => obj[key] === query[key]); + } + return objs; } // --------------------------------- INDEX HELPERS --------------------------------- diff --git a/src/storage/size-reporter/FileSizeReporter.ts b/src/storage/size-reporter/FileSizeReporter.ts index 3137a980d..78f120f28 100644 --- a/src/storage/size-reporter/FileSizeReporter.ts +++ b/src/storage/size-reporter/FileSizeReporter.ts @@ -71,17 +71,16 @@ export class FileSizeReporter implements SizeReporter { const childFiles = await fsPromises.readdir(fileLocation); const rootFilePathLength = trimTrailingSlashes(this.rootFilePath).length; - return await childFiles.reduce(async(acc: Promise, current): Promise => { + let totalSize = stat.size; + for (const current of childFiles) { const childFileLocation = normalizeFilePath(joinFilePath(fileLocation, current)); - let result = await acc; // Exclude internal files if (!this.ignoreFolders.some((folder: RegExp): boolean => folder.test(childFileLocation.slice(rootFilePathLength)))) { - result += await this.getTotalSize(childFileLocation); + totalSize += await this.getTotalSize(childFileLocation); } - - return result; - }, Promise.resolve(stat.size)); + } + return totalSize; } } diff --git a/src/util/Header.ts b/src/util/Header.ts index aee5ae6f3..06f43b259 100644 --- a/src/util/Header.ts +++ b/src/util/Header.ts @@ -58,9 +58,10 @@ export class ContentType { * @returns The value string, including parameters, if present. */ public toHeaderValueString(): string { - return Object.entries(this.parameters) + const parameterStrings = Object.entries(this.parameters) .sort((entry1, entry2): number => entry1[0].localeCompare(entry2[0])) - .reduce((acc, entry): string => `${acc}; ${entry[0]}=${entry[1]}`, this.value); + .map(([ key, value ]): string => `${key}=${value}`); + return [ this.value, ...parameterStrings ].join('; '); } } diff --git a/src/util/HeaderUtil.ts b/src/util/HeaderUtil.ts index 567c67be6..ea4d8c481 100644 --- a/src/util/HeaderUtil.ts +++ b/src/util/HeaderUtil.ts @@ -111,7 +111,8 @@ function handleInvalidValue(message: string, strict: boolean): void | never { */ export function parseParameters(parameters: string[], replacements: Record, strict = false): { name: string; value: string }[] { - return parameters.reduce<{ name: string; value: string }[]>((acc, param): { name: string; value: string }[] => { + const parsed: { name: string; value: string }[] = []; + for (const param of parameters) { const [ name, rawValue ] = param.split('=').map((str): string => str.trim()); // Test replaced string for easier check @@ -120,7 +121,7 @@ export function parseParameters(parameters: string[], replacements: Record( - (prev, cur): ContentType => { - prev.parameters[cur.name] = cur.value; - return prev; - }, - new ContentType(value), - ); + const contentType = new ContentType(value); + for (const param of parseParameters(params, replacements)) { + contentType.parameters[param.name] = param.value; + } + return contentType; } /** diff --git a/src/util/QuadUtil.ts b/src/util/QuadUtil.ts index 26ef3d636..0d86c777d 100644 --- a/src/util/QuadUtil.ts +++ b/src/util/QuadUtil.ts @@ -37,12 +37,13 @@ export async function parseQuads(readable: Guarded, options: ParserOpt * @returns A new array containing the unique quads. */ export function uniqueQuads(quads: Quad[]): Quad[] { - return quads.reduce((result, quad): Quad[] => { - if (!result.some((item): boolean => quad.equals(item))) { - result.push(quad); + const uniques: Quad[] = []; + for (const quad of quads) { + if (!uniques.some((item): boolean => quad.equals(item))) { + uniques.push(quad); } - return result; - }, []); + } + return uniques; } /** diff --git a/src/util/errors/HttpErrorUtil.ts b/src/util/errors/HttpErrorUtil.ts index 215ecc43b..fc04a66a8 100644 --- a/src/util/errors/HttpErrorUtil.ts +++ b/src/util/errors/HttpErrorUtil.ts @@ -34,12 +34,14 @@ export function errorTermsToMetadata(terms: Dict, metadata?: Representat * @param metadata - Metadata to extract the terms from. */ export function extractErrorTerms(metadata: RepresentationMetadata): Dict { - return metadata.quads() - .filter((quad): boolean => quad.predicate.value.startsWith(SOLID_ERROR_TERM.namespace)) - .reduce>((acc, quad): Dict => { - acc[quad.predicate.value.slice(SOLID_ERROR_TERM.namespace.length)] = quad.object.value; - return acc; - }, {}); + const errorQuads = metadata.quads() + .filter((quad): boolean => quad.predicate.value.startsWith(SOLID_ERROR_TERM.namespace)); + + const errorTerms: Dict = {}; + for (const quad of errorQuads) { + errorTerms[quad.predicate.value.slice(SOLID_ERROR_TERM.namespace.length)] = quad.object.value; + } + return errorTerms; } /**