diff --git a/cli/run/build.ts b/cli/run/build.ts index 38c55e2e05f..c5fab831470 100644 --- a/cli/run/build.ts +++ b/cli/run/build.ts @@ -24,9 +24,7 @@ export default async function build( } else if (inputOptions.input instanceof Array) { inputFiles = inputOptions.input.join(', '); } else if (typeof inputOptions.input === 'object' && inputOptions.input !== null) { - inputFiles = Object.keys(inputOptions.input) - .map(name => (inputOptions.input as Record)[name]) - .join(', '); + inputFiles = Object.values(inputOptions.input).join(', '); } stderr(cyan(`\n${bold(inputFiles!)} → ${bold(files.join(', '))}...`)); } diff --git a/cli/run/watch-cli.ts b/cli/run/watch-cli.ts index fb2ef95de75..f6d33fc4fd4 100644 --- a/cli/run/watch-cli.ts +++ b/cli/run/watch-cli.ts @@ -106,9 +106,7 @@ export async function watch(command: any) { if (typeof input !== 'string') { input = Array.isArray(input) ? input.join(', ') - : Object.keys(input as Record) - .map(key => (input as Record)[key]) - .join(', '); + : Object.values(input as Record).join(', '); } stderr( cyan(`bundles ${bold(input)} → ${bold(event.output.map(relativeId).join(', '))}...`) diff --git a/src/Bundle.ts b/src/Bundle.ts index 01e731fa2a7..84b506f037d 100644 --- a/src/Bundle.ts +++ b/src/Bundle.ts @@ -6,6 +6,7 @@ import { GetManualChunk, NormalizedInputOptions, NormalizedOutputOptions, + OutputAsset, OutputBundle, OutputBundleWithPlaceholders, OutputChunk, @@ -41,11 +42,7 @@ export default class Bundle { async generate(isWrite: boolean): Promise { timeStart('GENERATE', 1); const outputBundle: OutputBundleWithPlaceholders = Object.create(null); - this.pluginDriver.setOutputBundle( - outputBundle, - this.outputOptions, - this.facadeChunkByModule - ); + this.pluginDriver.setOutputBundle(outputBundle, this.outputOptions, this.facadeChunkByModule); try { await this.pluginDriver.hookParallel('renderStart', [this.outputOptions, this.inputOptions]); @@ -104,9 +101,9 @@ export default class Bundle { ): Promise> { const manualChunkAliasByEntry = new Map(); const chunkEntries = await Promise.all( - Object.keys(manualChunks).map(async alias => ({ + Object.entries(manualChunks).map(async ([alias, files]) => ({ alias, - entries: await this.graph.moduleLoader.addAdditionalModules(manualChunks[alias]) + entries: await this.graph.moduleLoader.addAdditionalModules(files) })) ); for (const { alias, entries } of chunkEntries) { @@ -169,24 +166,23 @@ export default class Bundle { } private finaliseAssets(outputBundle: OutputBundleWithPlaceholders): void { - for (const key of Object.keys(outputBundle)) { - const file = outputBundle[key] as any; + for (const file of Object.values(outputBundle)) { if (!file.type) { warnDeprecation( 'A plugin is directly adding properties to the bundle object in the "generateBundle" hook. This is deprecated and will be removed in a future Rollup version, please use "this.emitFile" instead.', true, this.inputOptions ); - file.type = 'asset'; + (file as OutputAsset).type = 'asset'; } - if (this.outputOptions.validate && typeof file.code == 'string') { + if (this.outputOptions.validate && typeof (file as OutputChunk).code == 'string') { try { - this.graph.contextParse(file.code, { + this.graph.contextParse((file as OutputChunk).code, { allowHashBang: true, ecmaVersion: 'latest' }); } catch (exception) { - this.inputOptions.onwarn(errChunkInvalid(file, exception)); + this.inputOptions.onwarn(errChunkInvalid(file as OutputChunk, exception)); } } } diff --git a/src/Chunk.ts b/src/Chunk.ts index f8258da7b0c..cc03a6e8086 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -1326,8 +1326,8 @@ export default class Chunk { if (!this.outputOptions.preserveModules) { if (this.includedNamespaces.has(module)) { const memberVariables = module.namespace.getMemberVariables(); - for (const name of Object.keys(memberVariables)) { - moduleImports.add(memberVariables[name]); + for (const variable of Object.values(memberVariables)) { + moduleImports.add(variable); } } } diff --git a/src/Graph.ts b/src/Graph.ts index 9afb0fdda66..e62703cb37a 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -34,9 +34,9 @@ function normalizeEntryModules( name: null })); } - return Object.keys(entryModules).map(name => ({ + return Object.entries(entryModules).map(([name, id]) => ({ fileName: null, - id: entryModules[name], + id, implicitlyLoadedAfter: [], importer: undefined, name @@ -74,13 +74,14 @@ export default class Graph { // increment access counter for (const name in this.pluginCache) { const cache = this.pluginCache[name]; - for (const key of Object.keys(cache)) cache[key][0]++; + for (const value of Object.values(cache)) value[0]++; } } if (watcher) { this.watchMode = true; - const handleChange: WatchChangeHook = (...args) => this.pluginDriver.hookSeqSync('watchChange', args); + const handleChange: WatchChangeHook = (...args) => + this.pluginDriver.hookSeqSync('watchChange', args); const handleClose = () => this.pluginDriver.hookSeqSync('closeWatcher', []); watcher.on('change', handleChange); watcher.on('close', handleClose); @@ -118,9 +119,9 @@ export default class Graph { if (onCommentOrig && typeof onCommentOrig == 'function') { options.onComment = (block, text, start, end, ...args) => { - comments.push({type: block ? "Block" : "Line", value: text, start, end}); + comments.push({ type: block ? 'Block' : 'Line', value: text, start, end }); return onCommentOrig.call(options, block, text, start, end, ...args); - } + }; } else { options.onComment = comments; } @@ -146,8 +147,8 @@ export default class Graph { for (const name in this.pluginCache) { const cache = this.pluginCache[name]; let allDeleted = true; - for (const key of Object.keys(cache)) { - if (cache[key][0] >= this.options.experimentalCacheExpiry) delete cache[key]; + for (const [key, value] of Object.entries(cache)) { + if (value[0] >= this.options.experimentalCacheExpiry) delete cache[key]; else allDeleted = false; } if (allDeleted) delete this.pluginCache[name]; @@ -238,8 +239,7 @@ export default class Graph { private warnForMissingExports() { for (const module of this.modules) { - for (const importName of Object.keys(module.importDescriptions)) { - const importDescription = module.importDescriptions[importName]; + for (const importDescription of Object.values(module.importDescriptions)) { if ( importDescription.name !== '*' && !(importDescription.module as Module).getVariableForExportName(importDescription.name) diff --git a/src/Module.ts b/src/Module.ts index 26d896a5901..db1f7eeb4d4 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -1002,8 +1002,7 @@ export default class Module { private addModulesToImportDescriptions(importDescription: { [name: string]: ImportDescription | ReexportDescription; }) { - for (const name of Object.keys(importDescription)) { - const specifier = importDescription[name]; + for (const specifier of Object.values(importDescription)) { const id = this.resolvedIds[specifier.source].id; specifier.module = this.graph.modulesById.get(id)!; } diff --git a/src/ast/keys.ts b/src/ast/keys.ts index 9434d9aae03..abd258e6e37 100644 --- a/src/ast/keys.ts +++ b/src/ast/keys.ts @@ -9,7 +9,7 @@ export const keys: { export function getAndCreateKeys(esTreeNode: GenericEsTreeNode) { keys[esTreeNode.type] = Object.keys(esTreeNode).filter( - key => key !== '_rollupAnnotations' && typeof esTreeNode[key] === 'object' + key => typeof esTreeNode[key] === 'object' && key !== '_rollupAnnotations' ); return keys[esTreeNode.type]; } diff --git a/src/ast/nodes/ArrowFunctionExpression.ts b/src/ast/nodes/ArrowFunctionExpression.ts index 81d920c7c5f..b9d1ba672f4 100644 --- a/src/ast/nodes/ArrowFunctionExpression.ts +++ b/src/ast/nodes/ArrowFunctionExpression.ts @@ -31,7 +31,6 @@ export default class ArrowFunctionExpression extends NodeBase { } } - // TODO Lukas handle nested paths and other event types // Arrow functions do not mutate their context deoptimizeThisOnEventAtPath() {} diff --git a/src/ast/nodes/AssignmentExpression.ts b/src/ast/nodes/AssignmentExpression.ts index 8517e48dacb..a515fc95009 100644 --- a/src/ast/nodes/AssignmentExpression.ts +++ b/src/ast/nodes/AssignmentExpression.ts @@ -122,7 +122,6 @@ export default class AssignmentExpression extends NodeBase { } } - // TODO Lukas is it time for propertyWriteSideEffects? protected applyDeoptimizations() { this.deoptimized = true; this.left.deoptimizePath(EMPTY_PATH); diff --git a/src/ast/nodes/CallExpression.ts b/src/ast/nodes/CallExpression.ts index ee6304f4396..c0d1087f1dc 100644 --- a/src/ast/nodes/CallExpression.ts +++ b/src/ast/nodes/CallExpression.ts @@ -122,7 +122,6 @@ export default class CallExpression extends NodeBase implements DeoptimizableEnt } } - // TODO Lukas allow "event" to be a CallOptions object and get rid of thisParameter deoptimizeThisOnEventAtPath( event: NodeEvent, path: ObjectPath, diff --git a/src/ast/nodes/NewExpression.ts b/src/ast/nodes/NewExpression.ts index 54626a493c1..acff4ce3630 100644 --- a/src/ast/nodes/NewExpression.ts +++ b/src/ast/nodes/NewExpression.ts @@ -35,7 +35,6 @@ export default class NewExpression extends NodeBase { initialise() { this.callOptions = { args: this.arguments, - // TODO Lukas does it make sense, to use a pre-made object expression here? Can we get rid of "withNew"? thisParam: null, withNew: true }; diff --git a/src/ast/nodes/TaggedTemplateExpression.ts b/src/ast/nodes/TaggedTemplateExpression.ts index ef830dcfd5f..90a18c81ee2 100644 --- a/src/ast/nodes/TaggedTemplateExpression.ts +++ b/src/ast/nodes/TaggedTemplateExpression.ts @@ -52,7 +52,6 @@ export default class TaggedTemplateExpression extends NodeBase { initialise() { this.callOptions = { args: NO_ARGS, - // TODO Lukas verify thisParam: null, withNew: false, }; diff --git a/src/ast/nodes/shared/ClassNode.ts b/src/ast/nodes/shared/ClassNode.ts index ef21c7159e4..7a930b94582 100644 --- a/src/ast/nodes/shared/ClassNode.ts +++ b/src/ast/nodes/shared/ClassNode.ts @@ -21,14 +21,10 @@ import { ObjectEntity, ObjectProperty } from './ObjectEntity'; import { ObjectMember } from './ObjectMember'; import { OBJECT_PROTOTYPE } from './ObjectPrototype'; -// TODO Lukas -// * __proto__ assignment handling might be possible solely via the object prototype? But it would need to deoptimize the entire prototype chain: Bad. Better we always replace the prototype with "unknown" on assigment -// * __proto__: foo handling however is an ObjectExpression feature export default class ClassNode extends NodeBase implements DeoptimizableEntity { body!: ClassBody; id!: Identifier | null; superClass!: ExpressionNode | null; - private classConstructor!: MethodDefinition | null; private objectEntity: ObjectEntity | null = null; diff --git a/src/ast/nodes/shared/FunctionNode.ts b/src/ast/nodes/shared/FunctionNode.ts index a61462f9ba1..11c89253099 100644 --- a/src/ast/nodes/shared/FunctionNode.ts +++ b/src/ast/nodes/shared/FunctionNode.ts @@ -13,7 +13,6 @@ import { ObjectEntity } from './ObjectEntity'; import { OBJECT_PROTOTYPE } from './ObjectPrototype'; import { PatternNode } from './Pattern'; -// TODO Lukas improve prototype handling to fix #2219 export default class FunctionNode extends NodeBase { async!: boolean; body!: BlockStatement; @@ -21,7 +20,6 @@ export default class FunctionNode extends NodeBase { params!: PatternNode[]; preventChildBlockScope!: true; scope!: FunctionScope; - private isPrototypeDeoptimized = false; createScope(parentScope: FunctionScope) { @@ -42,7 +40,6 @@ export default class FunctionNode extends NodeBase { } } - // TODO Lukas handle other event types as well deoptimizeThisOnEventAtPath(event: NodeEvent, path: ObjectPath, thisParameter: ExpressionEntity) { if (event === EVENT_CALLED) { if (path.length > 0 ) { diff --git a/src/ast/nodes/shared/MethodBase.ts b/src/ast/nodes/shared/MethodBase.ts index 8976dbcb115..1a425f7cce5 100644 --- a/src/ast/nodes/shared/MethodBase.ts +++ b/src/ast/nodes/shared/MethodBase.ts @@ -22,7 +22,6 @@ export default class MethodBase extends NodeBase implements DeoptimizableEntity private accessedValue: ExpressionEntity | null = null; private accessorCallOptions: CallOptions = { args: NO_ARGS, - // TODO Lukas in the end, handle this differently or get rid of the shared call options thisParam: null, withNew: false }; diff --git a/src/ast/nodes/shared/MethodTypes.ts b/src/ast/nodes/shared/MethodTypes.ts index a5c20c4dac9..d43f4324ceb 100644 --- a/src/ast/nodes/shared/MethodTypes.ts +++ b/src/ast/nodes/shared/MethodTypes.ts @@ -76,7 +76,6 @@ export class Method extends ExpressionEntity { EMPTY_PATH, { args: NO_ARGS, - // TODO Lukas check if we need something else here thisParam: null, withNew: false }, diff --git a/src/ast/nodes/shared/Node.ts b/src/ast/nodes/shared/Node.ts index 72ce839432b..ccb0e0aa873 100644 --- a/src/ast/nodes/shared/Node.ts +++ b/src/ast/nodes/shared/Node.ts @@ -195,10 +195,9 @@ export class NodeBase extends ExpressionEntity implements ExpressionNode { } parseNode(esTreeNode: GenericEsTreeNode) { - for (const key of Object.keys(esTreeNode)) { + for (const [key, value] of Object.entries(esTreeNode)) { // That way, we can override this function to add custom initialisation and then call super.parseNode if (this.hasOwnProperty(key)) continue; - const value = esTreeNode[key]; if (key === '_rollupAnnotations') { this.annotations = value; } else if (typeof value !== 'object' || value === null) { diff --git a/src/ast/nodes/shared/ObjectEntity.ts b/src/ast/nodes/shared/ObjectEntity.ts index 3ddea201473..53dfc4c3882 100644 --- a/src/ast/nodes/shared/ObjectEntity.ts +++ b/src/ast/nodes/shared/ObjectEntity.ts @@ -85,9 +85,9 @@ export class ObjectEntity extends ExpressionEntity { return; } this.hasUnknownDeoptimizedInteger = true; - for (const key of Object.keys(this.propertiesAndGettersByKey)) { + for (const [key, propertiesAndGetters] of Object.entries(this.propertiesAndGettersByKey)) { if (INTEGER_REG_EXP.test(key)) { - for (const property of this.propertiesAndGettersByKey[key]) { + for (const property of propertiesAndGetters) { property.deoptimizePath(UNKNOWN_PATH); } } @@ -421,7 +421,6 @@ export class ObjectEntity extends ExpressionEntity { } } - // TODO Lukas check everywhere if we can replace Object.keys with Object.entries/values private deoptimizeCachedIntegerEntities() { for (const [key, expressionsToBeDeoptimized] of Object.entries( this.expressionsToBeDeoptimizedByKey diff --git a/src/ast/variables/NamespaceVariable.ts b/src/ast/variables/NamespaceVariable.ts index c81cff49892..62bf7ac2b0e 100644 --- a/src/ast/variables/NamespaceVariable.ts +++ b/src/ast/variables/NamespaceVariable.ts @@ -66,9 +66,7 @@ export default class NamespaceVariable extends Variable { const t = options.indent; const memberVariables = this.getMemberVariables(); - const members = Object.keys(memberVariables).map(name => { - const original = memberVariables[name]; - + const members = Object.entries(memberVariables).map(([name, original]) => { if (this.referencedEarly || original.isReassigned) { return `${t}get ${name}${_}()${_}{${_}return ${original.getName()}${ options.compact ? '' : ';' diff --git a/src/rollup/rollup.ts b/src/rollup/rollup.ts index 86519eb5439..b013af1c84f 100644 --- a/src/rollup/rollup.ts +++ b/src/rollup/rollup.ts @@ -170,9 +170,7 @@ async function handleGenerateWrite( message: 'You must specify "output.file" or "output.dir" for the build.' }); } - await Promise.all( - Object.keys(generated).map(chunkId => writeOutputFile(generated[chunkId], outputOptions)) - ); + await Promise.all(Object.values(generated).map(chunk => writeOutputFile(chunk, outputOptions))); await outputPluginDriver.hookParallel('writeBundle', [outputOptions, generated]); } return createOutput(generated); @@ -228,12 +226,9 @@ function getOutputOptions( function createOutput(outputBundle: Record): RollupOutput { return { - output: (Object.keys(outputBundle) - .map(fileName => outputBundle[fileName]) - .filter(outputFile => Object.keys(outputFile).length > 0) as ( - | OutputChunk - | OutputAsset - )[]).sort((outputFileA, outputFileB) => { + output: (Object.values(outputBundle).filter( + outputFile => Object.keys(outputFile).length > 0 + ) as (OutputChunk | OutputAsset)[]).sort((outputFileA, outputFileB) => { const fileTypeA = getSortingFileType(outputFileA); const fileTypeB = getSortingFileType(outputFileB); if (fileTypeA === fileTypeB) return 0; diff --git a/src/utils/FileEmitter.ts b/src/utils/FileEmitter.ts index 65520b91fc3..8f0a3e1abd3 100644 --- a/src/utils/FileEmitter.ts +++ b/src/utils/FileEmitter.ts @@ -106,9 +106,12 @@ function hasValidType( ); } -function hasValidName(emittedFile: { type: 'asset' | 'chunk'; [key: string]: unknown; }): emittedFile is EmittedFile { +function hasValidName(emittedFile: { + type: 'asset' | 'chunk'; + [key: string]: unknown; +}): emittedFile is EmittedFile { const validatedName = emittedFile.fileName || emittedFile.name; - return !validatedName || typeof validatedName === 'string' && !isPathFragment(validatedName); + return !validatedName || (typeof validatedName === 'string' && !isPathFragment(validatedName)); } function getValidSource( @@ -351,8 +354,7 @@ function findExistingAssetFileNameWithSource( bundle: OutputBundleWithPlaceholders, source: string | Uint8Array ): string | null { - for (const fileName of Object.keys(bundle)) { - const outputFile = bundle[fileName]; + for (const [fileName, outputFile] of Object.entries(bundle)) { if (outputFile.type === 'asset' && areSourcesEqual(source, outputFile.source)) return fileName; } return null; diff --git a/src/utils/chunkAssignment.ts b/src/utils/chunkAssignment.ts index b4fb355377c..3490ddaf9ad 100644 --- a/src/utils/chunkAssignment.ts +++ b/src/utils/chunkAssignment.ts @@ -185,8 +185,8 @@ function createChunks( chunkModules[chunkSignature] = [module]; } } - return Object.keys(chunkModules).map(chunkSignature => ({ + return Object.values(chunkModules).map(modules => ({ alias: null, - modules: chunkModules[chunkSignature] + modules })); } diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 649a10c6ff0..52626aff142 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -187,8 +187,8 @@ const getModuleContext = ( } if (configModuleContext) { const contextByModuleId = Object.create(null); - for (const key of Object.keys(configModuleContext)) { - contextByModuleId[resolve(key)] = configModuleContext[key]; + for (const [key, moduleContext] of Object.entries(configModuleContext)) { + contextByModuleId[resolve(key)] = moduleContext; } return id => contextByModuleId[id] || context; } diff --git a/src/utils/timers.ts b/src/utils/timers.ts index 5f030bbfafb..5ef2f77ba8d 100644 --- a/src/utils/timers.ts +++ b/src/utils/timers.ts @@ -76,8 +76,8 @@ function timeEndImpl(label: string, level = 3) { export function getTimings(): SerializedTimings { const newTimings: SerializedTimings = {}; - for (const label of Object.keys(timers)) { - newTimings[label] = [timers[label].time, timers[label].memory, timers[label].totalMemory]; + for (const [label, { time, memory, totalMemory }] of Object.entries(timers)) { + newTimings[label] = [time, memory, totalMemory]; } return newTimings; } @@ -102,7 +102,7 @@ function getPluginWithTimers(plugin: any, index: number): Plugin { timerLabel += ` (${plugin.name})`; } timerLabel += ` - ${hook}`; - timedPlugin[hook] = function() { + timedPlugin[hook] = function () { timeStart(timerLabel, 4); let result = plugin[hook].apply(this === timedPlugin ? plugin : this, arguments); timeEnd(timerLabel, 4);