Remove usages of in (#276333)

* Remove usages of in

* Update extensions/ipynb/src/serializers.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Don Jayamanne
2025-11-09 07:07:11 +00:00
committed by GitHub
parent 2fac2d47c7
commit b282eee40c
12 changed files with 62 additions and 36 deletions

View File

@@ -193,10 +193,6 @@ export default tseslint.config(
'extensions/git/src/blame.ts', 'extensions/git/src/blame.ts',
'extensions/github/src/links.ts', 'extensions/github/src/links.ts',
'extensions/github-authentication/src/node/fetch.ts', 'extensions/github-authentication/src/node/fetch.ts',
'extensions/ipynb/src/deserializers.ts',
'extensions/ipynb/src/notebookImagePaste.ts',
'extensions/ipynb/src/serializers.ts',
'extensions/notebook-renderers/src/index.ts',
'extensions/terminal-suggest/src/fig/figInterface.ts', 'extensions/terminal-suggest/src/fig/figInterface.ts',
'extensions/terminal-suggest/src/fig/fig-autocomplete-shared/mixins.ts', 'extensions/terminal-suggest/src/fig/fig-autocomplete-shared/mixins.ts',
'extensions/terminal-suggest/src/fig/fig-autocomplete-shared/specMetadata.ts', 'extensions/terminal-suggest/src/fig/fig-autocomplete-shared/specMetadata.ts',
@@ -314,17 +310,11 @@ export default tseslint.config(
'src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts', 'src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts',
'src/vs/workbench/contrib/mcp/test/common/mcpRegistryTypes.ts', 'src/vs/workbench/contrib/mcp/test/common/mcpRegistryTypes.ts',
'src/vs/workbench/contrib/mcp/test/common/mcpServerRequestHandler.test.ts', 'src/vs/workbench/contrib/mcp/test/common/mcpServerRequestHandler.test.ts',
'src/vs/workbench/contrib/notebook/browser/contrib/debug/notebookBreakpoints.ts',
'src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts',
'src/vs/workbench/contrib/notebook/browser/controller/cellOutputActions.ts', 'src/vs/workbench/contrib/notebook/browser/controller/cellOutputActions.ts',
'src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts', 'src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts',
'src/vs/workbench/contrib/notebook/browser/controller/coreActions.ts', 'src/vs/workbench/contrib/notebook/browser/controller/coreActions.ts',
'src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts',
'src/vs/workbench/contrib/notebook/browser/view/cellParts/cellExecution.ts',
'src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts', 'src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts',
'src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelView.ts', 'src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelView.ts',
'src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts',
'src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts',
'src/vs/workbench/contrib/output/browser/outputView.ts', 'src/vs/workbench/contrib/output/browser/outputView.ts',
'src/vs/workbench/contrib/preferences/browser/settingsTree.ts', 'src/vs/workbench/contrib/preferences/browser/settingsTree.ts',
'src/vs/workbench/contrib/remoteTunnel/electron-browser/remoteTunnel.contribution.ts', 'src/vs/workbench/contrib/remoteTunnel/electron-browser/remoteTunnel.contribution.ts',

View File

@@ -65,3 +65,36 @@ export interface CellMetadata {
execution_count?: number | null; execution_count?: number | null;
} }
type KeysOfUnionType<T> = T extends T ? keyof T : never;
type FilterType<T, TTest> = T extends TTest ? T : never;
type MakeOptionalAndBool<T extends object> = { [K in keyof T]?: boolean };
/**
* Type guard that checks if an object has specific keys and narrows the type accordingly.
*
* @param x - The object to check
* @param key - An object with boolean values indicating which keys to check for
* @returns true if all specified keys exist in the object, false otherwise
*
* @example
* ```typescript
* type A = { a: string };
* type B = { b: number };
* const obj: A | B = getObject();
*
* if (hasKey(obj, { a: true })) {
* // obj is now narrowed to type A
* console.log(obj.a);
* }
* ```
*/
export function hasKey<T extends object, TKeys>(x: T, key: TKeys & MakeOptionalAndBool<T>): x is FilterType<T, { [K in KeysOfUnionType<T> & keyof TKeys]: unknown }> {
for (const k in key) {
if (!(k in x)) {
return false;
}
}
return true;
}

View File

@@ -151,7 +151,7 @@ function convertJupyterOutputToBuffer(mime: string, value: unknown): NotebookCel
} }
} }
function getNotebookCellMetadata(cell: nbformat.IBaseCell): { function getNotebookCellMetadata(cell: nbformat.ICell): {
[key: string]: any; [key: string]: any;
} { } {
// We put this only for VSC to display in diff view. // We put this only for VSC to display in diff view.
@@ -169,7 +169,7 @@ function getNotebookCellMetadata(cell: nbformat.IBaseCell): {
cellMetadata['metadata'] = JSON.parse(JSON.stringify(cell['metadata'])); cellMetadata['metadata'] = JSON.parse(JSON.stringify(cell['metadata']));
} }
if ('id' in cell && typeof cell.id === 'string') { if (typeof cell.id === 'string') {
cellMetadata.id = cell.id; cellMetadata.id = cell.id;
} }

View File

@@ -274,7 +274,7 @@ function buildAttachment(
const filenameWithoutExt = basename(attachment.fileName, fileExt); const filenameWithoutExt = basename(attachment.fileName, fileExt);
let tempFilename = filenameWithoutExt + fileExt; let tempFilename = filenameWithoutExt + fileExt;
for (let appendValue = 2; tempFilename in cellMetadata.attachments; appendValue++) { for (let appendValue = 2; cellMetadata.attachments[tempFilename]; appendValue++) {
const objEntries = Object.entries(cellMetadata.attachments[tempFilename]); const objEntries = Object.entries(cellMetadata.attachments[tempFilename]);
if (objEntries.length) { // check that mime:b64 are present if (objEntries.length) { // check that mime:b64 are present
const [mime, attachmentb64] = objEntries[0]; const [mime, attachmentb64] = objEntries[0];

View File

@@ -5,7 +5,7 @@
import type * as nbformat from '@jupyterlab/nbformat'; import type * as nbformat from '@jupyterlab/nbformat';
import type { NotebookCell, NotebookCellData, NotebookCellOutput, NotebookData, NotebookDocument } from 'vscode'; import type { NotebookCell, NotebookCellData, NotebookCellOutput, NotebookData, NotebookDocument } from 'vscode';
import { CellOutputMetadata, type CellMetadata } from './common'; import { CellOutputMetadata, hasKey, type CellMetadata } from './common';
import { textMimeTypes, NotebookCellKindMarkup, CellOutputMimeTypes, defaultNotebookFormat } from './constants'; import { textMimeTypes, NotebookCellKindMarkup, CellOutputMimeTypes, defaultNotebookFormat } from './constants';
const textDecoder = new TextDecoder(); const textDecoder = new TextDecoder();
@@ -50,7 +50,7 @@ export function sortObjectPropertiesRecursively(obj: any): any {
} }
export function getCellMetadata(options: { cell: NotebookCell | NotebookCellData } | { metadata?: { [key: string]: any } }): CellMetadata { export function getCellMetadata(options: { cell: NotebookCell | NotebookCellData } | { metadata?: { [key: string]: any } }): CellMetadata {
if ('cell' in options) { if (hasKey(options, { cell: true })) {
const cell = options.cell; const cell = options.cell;
const metadata = { const metadata = {
execution_count: null, execution_count: null,
@@ -472,7 +472,7 @@ export function serializeNotebookToString(data: NotebookData): string {
.map(cell => createJupyterCellFromNotebookCell(cell, preferredCellLanguage)) .map(cell => createJupyterCellFromNotebookCell(cell, preferredCellLanguage))
.map(pruneCell); .map(pruneCell);
const indentAmount = data.metadata && 'indentAmount' in data.metadata && typeof data.metadata.indentAmount === 'string' ? const indentAmount = data.metadata && typeof data.metadata.indentAmount === 'string' ?
data.metadata.indentAmount : data.metadata.indentAmount :
' '; ' ';

View File

@@ -76,8 +76,8 @@ const domEval = (container: Element) => {
}; };
function getAltText(outputInfo: OutputItem) { function getAltText(outputInfo: OutputItem) {
const metadata = outputInfo.metadata; const metadata = outputInfo.metadata as Record<string, unknown> | undefined;
if (typeof metadata === 'object' && metadata && 'vscode_altText' in metadata && typeof metadata.vscode_altText === 'string') { if (typeof metadata === 'object' && metadata && typeof metadata.vscode_altText === 'string') {
return metadata.vscode_altText; return metadata.vscode_altText;
} }
return undefined; return undefined;
@@ -337,9 +337,9 @@ function findScrolledHeight(container: HTMLElement): number | undefined {
} }
function scrollingEnabled(output: OutputItem, options: RenderOptions) { function scrollingEnabled(output: OutputItem, options: RenderOptions) {
const metadata = output.metadata; const metadata = output.metadata as Record<string, unknown> | undefined;
return (typeof metadata === 'object' && metadata return (typeof metadata === 'object' && metadata
&& 'scrollable' in metadata && typeof metadata.scrollable === 'boolean') ? && typeof metadata.scrollable === 'boolean') ?
metadata.scrollable : options.outputScrolling; metadata.scrollable : options.outputScrolling;
} }

View File

@@ -16,6 +16,7 @@ import { CellUri, NotebookCellsChangeType } from '../../../common/notebookCommon
import { INotebookService } from '../../../common/notebookService.js'; import { INotebookService } from '../../../common/notebookService.js';
import { IEditorService } from '../../../../../services/editor/common/editorService.js'; import { IEditorService } from '../../../../../services/editor/common/editorService.js';
import { LifecyclePhase } from '../../../../../services/lifecycle/common/lifecycle.js'; import { LifecyclePhase } from '../../../../../services/lifecycle/common/lifecycle.js';
import { hasKey } from '../../../../../../base/common/types.js';
class NotebookBreakpoints extends Disposable implements IWorkbenchContribution { class NotebookBreakpoints extends Disposable implements IWorkbenchContribution {
constructor( constructor(
@@ -58,7 +59,7 @@ class NotebookBreakpoints extends Disposable implements IWorkbenchContribution {
})); }));
this._register(this._debugService.getModel().onDidChangeBreakpoints(e => { this._register(this._debugService.getModel().onDidChangeBreakpoints(e => {
const newCellBp = e?.added?.find(bp => 'uri' in bp && bp.uri.scheme === Schemas.vscodeNotebookCell) as IBreakpoint | undefined; const newCellBp = e?.added?.find(bp => hasKey(bp, { uri: true }) && bp.uri.scheme === Schemas.vscodeNotebookCell) as IBreakpoint | undefined;
if (newCellBp) { if (newCellBp) {
const parsed = CellUri.parse(newCellBp.uri); const parsed = CellUri.parse(newCellBp.uri);
if (!parsed) { if (!parsed) {

View File

@@ -18,6 +18,7 @@ import { CellEditState, CellFindMatchWithIndex, CellWebviewFindMatch, ICellViewM
import { NotebookViewModel } from '../../viewModel/notebookViewModelImpl.js'; import { NotebookViewModel } from '../../viewModel/notebookViewModelImpl.js';
import { NotebookTextModel } from '../../../common/model/notebookTextModel.js'; import { NotebookTextModel } from '../../../common/model/notebookTextModel.js';
import { CellKind, INotebookFindOptions, NotebookCellsChangeType } from '../../../common/notebookCommon.js'; import { CellKind, INotebookFindOptions, NotebookCellsChangeType } from '../../../common/notebookCommon.js';
import { hasKey } from '../../../../../../base/common/types.js';
export class CellFindMatchModel implements CellFindMatchWithIndex { export class CellFindMatchModel implements CellFindMatchWithIndex {
readonly cell: ICellViewModel; readonly cell: ICellViewModel;
@@ -239,14 +240,14 @@ export class FindModel extends Disposable {
// let currCell; // let currCell;
if (!this._findMatchesStarts) { if (!this._findMatchesStarts) {
this.set(this._findMatches, true); this.set(this._findMatches, true);
if ('index' in option) { if (hasKey(option, { index: true })) {
this._currentMatch = option.index; this._currentMatch = option.index;
} }
} else { } else {
// const currIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); // const currIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch);
// currCell = this._findMatches[currIndex.index].cell; // currCell = this._findMatches[currIndex.index].cell;
const totalVal = this._findMatchesStarts.getTotalSum(); const totalVal = this._findMatchesStarts.getTotalSum();
if ('index' in option) { if (hasKey(option, { index: true })) {
this._currentMatch = option.index; this._currentMatch = option.index;
} }
else if (this._currentMatch === -1) { else if (this._currentMatch === -1) {

View File

@@ -745,7 +745,7 @@ export class SideBySideDiffElementViewModel extends DiffElementCellViewModelBase
const modifiedMedataRaw = Object.assign({}, this.modified.metadata); const modifiedMedataRaw = Object.assign({}, this.modified.metadata);
const originalCellMetadata = this.original.metadata; const originalCellMetadata = this.original.metadata;
for (const key of cellMetadataKeys) { for (const key of cellMetadataKeys) {
if (key in originalCellMetadata) { if (Object.hasOwn(originalCellMetadata, key)) {
modifiedMedataRaw[key] = originalCellMetadata[key]; modifiedMedataRaw[key] = originalCellMetadata[key];
} }
} }

View File

@@ -16,6 +16,7 @@ import { INotebookExecutionStateService } from '../../../common/notebookExecutio
import { executingStateIcon } from '../../notebookIcons.js'; import { executingStateIcon } from '../../notebookIcons.js';
import { renderLabelWithIcons } from '../../../../../../base/browser/ui/iconLabel/iconLabels.js'; import { renderLabelWithIcons } from '../../../../../../base/browser/ui/iconLabel/iconLabels.js';
import { CellViewModelStateChangeEvent } from '../../notebookViewEvents.js'; import { CellViewModelStateChangeEvent } from '../../notebookViewEvents.js';
import { hasKey } from '../../../../../../base/common/types.js';
const UPDATE_EXECUTION_ORDER_GRACE_PERIOD = 200; const UPDATE_EXECUTION_ORDER_GRACE_PERIOD = 200;
@@ -38,7 +39,7 @@ export class CellExecutionPart extends CellContentPart {
// Add a method to watch for cell execution state changes // Add a method to watch for cell execution state changes
this._register(this._notebookExecutionStateService.onDidChangeExecution(e => { this._register(this._notebookExecutionStateService.onDidChangeExecution(e => {
if (this.currentCell && 'affectsCell' in e && e.affectsCell(this.currentCell.uri)) { if (this.currentCell && hasKey(e, { affectsCell: true }) && e.affectsCell(this.currentCell.uri)) {
this._updatePosition(); this._updatePosition();
} }
})); }));

View File

@@ -10,7 +10,7 @@ import { Disposable, dispose, IDisposable } from '../../../../../base/common/lif
import { Schemas } from '../../../../../base/common/network.js'; import { Schemas } from '../../../../../base/common/network.js';
import { filter } from '../../../../../base/common/objects.js'; import { filter } from '../../../../../base/common/objects.js';
import { isEqual } from '../../../../../base/common/resources.js'; import { isEqual } from '../../../../../base/common/resources.js';
import { isDefined } from '../../../../../base/common/types.js'; import { hasKey, isDefined } from '../../../../../base/common/types.js';
import { URI } from '../../../../../base/common/uri.js'; import { URI } from '../../../../../base/common/uri.js';
import { Position } from '../../../../../editor/common/core/position.js'; import { Position } from '../../../../../editor/common/core/position.js';
import { Range } from '../../../../../editor/common/core/range.js'; import { Range } from '../../../../../editor/common/core/range.js';
@@ -436,11 +436,11 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
} }
private _getCellIndexWithOutputIdHandleFromEdits(outputId: string, rawEdits: ICellEditOperation[]) { private _getCellIndexWithOutputIdHandleFromEdits(outputId: string, rawEdits: ICellEditOperation[]) {
const edit = rawEdits.find(e => 'outputs' in e && e.outputs.some(o => o.outputId === outputId)); const edit = rawEdits.find(e => hasKey(e, { outputs: true }) && e.outputs.some(o => o.outputId === outputId));
if (edit) { if (edit) {
if ('index' in edit) { if (hasKey(edit, { index: true })) {
return edit.index; return edit.index;
} else if ('handle' in edit) { } else if (hasKey(edit, { handle: true })) {
const cellIndex = this._getCellIndexByHandle(edit.handle); const cellIndex = this._getCellIndexByHandle(edit.handle);
this._assertIndex(cellIndex); this._assertIndex(cellIndex);
return cellIndex; return cellIndex;
@@ -621,10 +621,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
return false; return false;
} }
if (('index' in edit) && !this.newCellsFromLastEdit.has(this.cells[edit.index].handle)) { if (hasKey(edit, { index: true }) && !this.newCellsFromLastEdit.has(this.cells[edit.index].handle)) {
return false; return false;
} }
if ('handle' in edit && !this.newCellsFromLastEdit.has(edit.handle)) { if (hasKey(edit, { handle: true }) && !this.newCellsFromLastEdit.has(edit.handle)) {
return false; return false;
} }
} }
@@ -675,12 +675,12 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
private _doApplyEdits(rawEdits: ICellEditOperation[], synchronous: boolean, computeUndoRedo: boolean, beginSelectionState: ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined): void { private _doApplyEdits(rawEdits: ICellEditOperation[], synchronous: boolean, computeUndoRedo: boolean, beginSelectionState: ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined): void {
const editsWithDetails = rawEdits.map((edit, index) => { const editsWithDetails = rawEdits.map((edit, index) => {
let cellIndex: number = -1; let cellIndex: number = -1;
if ('index' in edit) { if (hasKey(edit, { index: true })) {
cellIndex = edit.index; cellIndex = edit.index;
} else if ('handle' in edit) { } else if (hasKey(edit, { handle: true })) {
cellIndex = this._getCellIndexByHandle(edit.handle); cellIndex = this._getCellIndexByHandle(edit.handle);
this._assertIndex(cellIndex); this._assertIndex(cellIndex);
} else if ('outputId' in edit) { } else if (hasKey(edit, { outputId: true })) {
cellIndex = this._getCellIndexWithOutputIdHandle(edit.outputId); cellIndex = this._getCellIndexWithOutputIdHandle(edit.outputId);
if (this._indexIsInvalid(cellIndex)) { if (this._indexIsInvalid(cellIndex)) {
// The referenced output may have been created in this batch of edits // The referenced output may have been created in this batch of edits

View File

@@ -10,7 +10,7 @@ import { Emitter, Event } from '../../../../base/common/event.js';
import { IMarkdownString } from '../../../../base/common/htmlContent.js'; import { IMarkdownString } from '../../../../base/common/htmlContent.js';
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js'; import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { Schemas } from '../../../../base/common/network.js'; import { Schemas } from '../../../../base/common/network.js';
import { assertType } from '../../../../base/common/types.js'; import { assertType, hasKey } from '../../../../base/common/types.js';
import { URI } from '../../../../base/common/uri.js'; import { URI } from '../../../../base/common/uri.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
import { IWriteFileOptions, IFileStatWithMetadata, FileOperationError, FileOperationResult } from '../../../../platform/files/common/files.js'; import { IWriteFileOptions, IFileStatWithMetadata, FileOperationError, FileOperationResult } from '../../../../platform/files/common/files.js';
@@ -111,7 +111,7 @@ export class SimpleNotebookEditorModel extends EditorModel implements INotebookE
} }
get hasErrorState(): boolean { get hasErrorState(): boolean {
if (this._workingCopy && 'hasState' in this._workingCopy) { if (this._workingCopy && hasKey(this._workingCopy, { hasState: true })) {
return this._workingCopy.hasState(StoredFileWorkingCopyState.ERROR); return this._workingCopy.hasState(StoredFileWorkingCopyState.ERROR);
} }