extensions/ipynb/src/notebookAttachmentCleaner.ts/AttachmentCleaner/cleanNotebookAttachments
class AttachmentCleaner:	private cleanNotebookAttachments(e: AttachmentCleanRequest) {
		if (e.notebook.isClosed) {
			return;
		}
		const document = e.document;
		const cell = e.cell;

		const markdownAttachmentsInUse: { [key: string /** filename */]: IAttachmentData } = {};
		const cellFragment = cell.document.uri.fragment;
		const notebookUri = e.notebook.uri.toString();
		const diagnostics: IAttachmentDiagnostic[] = [];
		const markdownAttachmentsRefedInCell = this.getAttachmentNames(document);

		if (markdownAttachmentsRefedInCell.size === 0) {
			// no attachments used in this cell, cache all images from cell metadata
			this.saveAllAttachmentsToCache(cell.metadata, notebookUri, cellFragment);
		}

		if (this.checkMetadataHasAttachmentsField(cell.metadata)) {
			// the cell metadata contains attachments, check if any are used in the markdown source

			for (const [currFilename, attachment] of Object.entries(cell.metadata.attachments)) {
				// means markdown reference is present in the metadata, rendering will work properly
				// therefore, we don't need to check it in the next loop either
				if (markdownAttachmentsRefedInCell.has(currFilename)) {
					// attachment reference is present in the markdown source, no need to cache it
					markdownAttachmentsRefedInCell.get(currFilename)!.valid = true;
					markdownAttachmentsInUse[currFilename] = attachment as IAttachmentData;
				} else {
					// attachment reference is not present in the markdown source, cache it
					this.saveAttachmentToCache(notebookUri, cellFragment, currFilename, cell.metadata);
				}
			}
		}

		for (const [currFilename, attachment] of markdownAttachmentsRefedInCell) {
			if (attachment.valid) {
				// attachment reference is present in both the markdown source and the metadata, no op
				continue;
			}

			// if image is referenced in markdown source but not in metadata -> check if we have image in the cache
			const cachedImageAttachment = this._attachmentCache.get(notebookUri)?.get(cellFragment)?.get(currFilename);
			if (cachedImageAttachment) {
				markdownAttachmentsInUse[currFilename] = cachedImageAttachment;
				this._attachmentCache.get(notebookUri)?.get(cellFragment)?.delete(currFilename);
			} else {
				// if image is not in the cache, show warning
				diagnostics.push({ name: currFilename, ranges: attachment.ranges });
			}
		}

		if (cell.index > -1 && !objectEquals(markdownAttachmentsInUse, cell.metadata.attachments)) {
			const updateMetadata: { [key: string]: any } = deepClone(cell.metadata);
			updateMetadata.attachments = markdownAttachmentsInUse;
			const metadataEdit = vscode.NotebookEdit.updateCellMetadata(cell.index, updateMetadata);
			const workspaceEdit = new vscode.WorkspaceEdit();
			workspaceEdit.set(e.notebook.uri, [metadataEdit]);
			vscode.workspace.applyEdit(workspaceEdit);
		}

		this.updateDiagnostics(cell.document.uri, diagnostics);
	}