Repository: rollup/rollup
File: src/ast/nodes/shared/Node.ts (TypeScript)

Code before:
		context: InclusionContext,
		includeChildrenRecursively: IncludeChildren,
		_deoptimizeAccess: boolean
	) {
		this.include(context, includeChildrenRecursively);
	}

	/**
	 * Override to perform special initialisation steps after the scope is
	 * initialised
	 */
	initialise(): void {}

	insertSemicolon(code: MagicString): void {
		if (code.original[this.end - 1] !== ';') {
			code.appendLeft(this.end, ';');
		}
	}

	parseNode(esTreeNode: GenericEsTreeNode, keepEsTreeNodeKeys?: string[]): void {
		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;
			if (key.charCodeAt(0) === 95 /* _ */) {
				if (key === ANNOTATION_KEY) {
					this.annotations = value;
					this.annotationNoSideEffects = this.annotations!.some(
						comment => comment.annotationType === 'noSideEffects'
					);
					this.annotationPure = this.annotations!.some(
						comment => comment.annotationType === 'pure'
					);
				} else if (key === INVALID_COMMENT_KEY) {
					for (const { start, end } of value as acorn.Comment[])
						this.context.magicString.remove(start, end);
				}
			} else if (typeof value !== 'object' || value === null) {
				(this as GenericEsTreeNode)[key] = value;
			} else if (Array.isArray(value)) {
				(this as GenericEsTreeNode)[key] = [];
				for (const child of value) {
					(this as GenericEsTreeNode)[key].push(
						child === null
							? null
							: new (this.context.getNodeConstructor(child.type))(
									child,
									this,
									this.scope,
									keepEsTreeNodeKeys?.includes(key)
							  )
					);

Review comment (suggestion):
If we only add `this.annotationNoSideEffects` and `this.annotationPure` if `treeshake.annotations` is enabled, we can avoid the `(this.context.options.treeshake as NormalizedTreeshakingOptions).annotations && ...` checks everywhere and just check e.g. for `annotationPure`. Also, it would make the parsing slightly faster if annotations are disabled. Note that we still need `this.annotations` for tree-shaking.

Code after:
	includeAsAssignmentTarget(
		context: InclusionContext,
		includeChildrenRecursively: IncludeChildren,
		_deoptimizeAccess: boolean
	) {
		this.include(context, includeChildrenRecursively);
	}

	/**
	 * Override to perform special initialisation steps after the scope is
	 * initialised
	 */
	initialise(): void {}

	insertSemicolon(code: MagicString): void {
		if (code.original[this.end - 1] !== ';') {
			code.appendLeft(this.end, ';');
		}
	}

	parseNode(esTreeNode: GenericEsTreeNode, keepEsTreeNodeKeys?: string[]): void {
		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;
			if (key.charCodeAt(0) === 95 /* _ */) {
				if (key === ANNOTATION_KEY) {
					const annotations = value as RollupAnnotation[];
					this.annotations = annotations;
					if ((this.context.options.treeshake as NormalizedTreeshakingOptions).annotations) {
						this.annotationNoSideEffects = annotations.some(
							comment => comment.annotationType === 'noSideEffects'
						);
						this.annotationPure = annotations.some(comment => comment.annotationType === 'pure');
					}
				} else if (key === INVALID_COMMENT_KEY) {
					for (const { start, end } of value as acorn.Comment[])
						this.context.magicString.remove(start, end);
				}
			} else if (typeof value !== 'object' || value === null) {
				(this as GenericEsTreeNode)[key] = value;
			} else if (Array.isArray(value)) {
				(this as GenericEsTreeNode)[key] = [];
				for (const child of value) {
					(this as GenericEsTreeNode)[key].push(
						child === null
							? null
							: new (this.context.getNodeConstructor(child.type))(
									child,
									this,
									this.scope,
									keepEsTreeNodeKeys?.includes(key)