Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forbid explicit any, migrate to unknown or proper typing #16219

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 22 additions & 3 deletions .eslintrc.js
Expand Up @@ -31,7 +31,22 @@ module.exports = {
plugins: ['@typescript-eslint'],
overrides: [
{
files: ['packages/**/*.spec.ts', 'testutils/**/*.spec.ts'],
files: [
'buildutils/**/*.ts',
'builder/**/*.ts',
'examples/**/*.ts',
'packages/testing/**/*.ts'
],
rules: {
'@typescript-eslint/no-explicit-any': 'off'
}
},
{
files: [
'packages/**/*.spec.ts',
'packages/**/*.spec.tsx',
'testutils/**/*.spec.ts'
],
plugins: ['jest'],
extends: ['plugin:jest/recommended'],
rules: {
Expand All @@ -42,7 +57,8 @@ module.exports = {
{
additionalTestBlockFunctions: ['it']
}
]
],
'@typescript-eslint/no-explicit-any': 'off'
}
}
],
Expand All @@ -60,7 +76,10 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-explicit-any': [
'error',
{ fixToUnknown: true, ignoreRestArgs: true }
],
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/interface-name-prefix': 'off',
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,6 +2,7 @@
coverage/
.eslintcache
.stylelintcache
.mypy_cache

dev_mode/listings
dev_mode/schemas
Expand Down
3 changes: 2 additions & 1 deletion galata/.eslintrc.js
Expand Up @@ -4,6 +4,7 @@ module.exports = {
project: 'tsconfig.eslint.json'
},
rules: {
'jest/no-done-callback': 'off'
'jest/no-done-callback': 'off',
'@typescript-eslint/no-explicit-any': 'off'
}
};
30 changes: 21 additions & 9 deletions packages/application-extension/src/index.tsx
Expand Up @@ -52,6 +52,7 @@ import {
import { find, some } from '@lumino/algorithm';
import {
JSONExt,
PartialJSONValue,
PromiseDelegate,
ReadonlyPartialJSONValue
} from '@lumino/coreutils';
Expand Down Expand Up @@ -795,6 +796,7 @@ const dirty: JupyterFrontEndPlugin<void> = {
// https://developer.mozilla.org/en/docs/Web/Events/beforeunload
window.addEventListener('beforeunload', event => {
if (app.status.isDirty) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return ((event as any).returnValue = message);
}
});
Expand Down Expand Up @@ -831,6 +833,7 @@ const layout: JupyterFrontEndPlugin<ILayoutRestorer> = {
.load(shell.id)
.then(settings => {
// Add a layer of customization to support app shell mode
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const customizedLayout = settings.composite['layout'] as any;

// Restore the layout.
Expand Down Expand Up @@ -858,13 +861,15 @@ const layout: JupyterFrontEndPlugin<ILayoutRestorer> = {
async function onSettingsChanged(
settings: ISettingRegistry.ISettings
): Promise<void> {
const layout = {
single: labShell.userLayout['single-document'],
multiple: labShell.userLayout['multiple-document']
};
if (
!JSONExt.deepEqual(
settings.composite['layout'] as ReadonlyPartialJSONValue,
{
single: labShell.userLayout['single-document'],
multiple: labShell.userLayout['multiple-document']
} as any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
layout as any
)
) {
const result = await showDialog({
Expand Down Expand Up @@ -1273,7 +1278,7 @@ const modeSwitchPlugin: JupyterFrontEndPlugin<void> = {
/**
* Export the plugins as default.
*/
const plugins: JupyterFrontEndPlugin<any>[] = [
const plugins: JupyterFrontEndPlugin<unknown>[] = [
contextMenuPlugin,
dirty,
main,
Expand Down Expand Up @@ -1354,7 +1359,9 @@ namespace Private {
// to define their default value.
schema.properties!.contextMenu.default = SettingRegistry.reconcileItems(
pluginDefaults,
schema.properties!.contextMenu.default as any[],
schema.properties!.contextMenu.default as
| ISettingRegistry.IContextMenuItem[]
| undefined,
true
)!
// flatten one level
Expand Down Expand Up @@ -1410,7 +1417,9 @@ namespace Private {
const settings = await registry.load(pluginId);

const contextItems: ISettingRegistry.IContextMenuItem[] =
(settings.composite.contextMenu as any) ?? [];
(settings.composite.contextMenu as
| ISettingRegistry.IContextMenuItem[]
| undefined) ?? [];

// Create menu item for non-disabled element
SettingRegistry.filterDisabledItems(contextItems).forEach(item => {
Expand All @@ -1428,7 +1437,10 @@ namespace Private {
settings.changed.connect(() => {
// As extension may change the context menu through API,
// prompt the user to reload if the menu has been updated.
const newItems = (settings.composite.contextMenu as any) ?? [];
const newItems =
(settings.composite.contextMenu as
| ISettingRegistry.IContextMenuItem[]
| undefined) ?? [];
if (!JSONExt.deepEqual(contextItems, newItems)) {
void displayInformation(trans);
}
Expand Down Expand Up @@ -1519,7 +1531,7 @@ namespace Private {
.set('layout', {
single: newLayout['single-document'],
multiple: newLayout['multiple-document']
} as any)
} as unknown as PartialJSONValue)
.catch(reason => {
console.error(
'Failed to save user layout customization.',
Expand Down
1 change: 1 addition & 0 deletions packages/application/src/frontend.ts
Expand Up @@ -215,6 +215,7 @@ export namespace JupyterFrontEnd {
/**
* The options used to initialize a JupyterFrontEnd.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface IOptions<T extends IShell = IShell, U = any>
extends Application.IOptions<T> {
/**
Expand Down
3 changes: 2 additions & 1 deletion packages/application/src/lab.ts
@@ -1,5 +1,6 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/* eslint-disable @typescript-eslint/no-explicit-any */

import { PageConfig } from '@jupyterlab/coreutils';
import { Base64ModelFactory } from '@jupyterlab/docregistry';
Expand Down Expand Up @@ -373,7 +374,7 @@ export namespace JupyterLab {
* A read-only subset of the `Token`.
*/
export interface IToken
extends Readonly<Pick<Token<any>, 'name' | 'description'>> {
extends Readonly<Pick<Token<unknown>, 'name' | 'description'>> {
// no-op
}

Expand Down
18 changes: 9 additions & 9 deletions packages/application/src/layoutrestorer.ts
Expand Up @@ -51,7 +51,7 @@ export interface ILayoutRestorer extends IRestorer {
restore<T extends Widget>(
tracker: WidgetTracker<T>,
options: IRestorer.IOptions<T>
): Promise<any>;
): Promise<unknown>;
}

/**
Expand Down Expand Up @@ -219,7 +219,7 @@ export class LayoutRestorer implements ILayoutRestorer {
leftArea,
rightArea,
relativeSizes: relativeSizes || null,
topArea: (top as any) ?? null
topArea: (top as ILabShell.ITopArea) ?? null
};
} catch (error) {
return blank;
Expand All @@ -236,7 +236,7 @@ export class LayoutRestorer implements ILayoutRestorer {
async restore(
tracker: WidgetTracker,
options: IRestorer.IOptions<Widget>
): Promise<any> {
): Promise<unknown> {
if (this._firstDone) {
throw new Error('restore() must be called before `first` has resolved.');
}
Expand Down Expand Up @@ -535,10 +535,10 @@ export class LayoutRestorer implements ILayoutRestorer {
private _connector: IDataConnector<ReadonlyPartialJSONValue>;
private _deferred = new Array<WidgetTracker>();
private _deferredMainArea?: Private.IMainArea | null = null;
private _first: Promise<any>;
private _first: Promise<unknown>;
private _firstDone = false;
private _promisesDone = false;
private _promises: Promise<any>[] = [];
private _promises: Promise<unknown>[] = [];
private _restored = new PromiseDelegate<void>();
private _registry: CommandRegistry;
private _trackers = new Set<string>();
Expand All @@ -565,7 +565,7 @@ export namespace LayoutRestorer {
* #### Notes
* This promise should equal the JupyterLab application `started` notifier.
*/
first: Promise<any>;
first: Promise<unknown>;

/**
* The application command registry.
Expand Down Expand Up @@ -821,7 +821,7 @@ namespace Private {

// Because this data is saved to a foreign data source, its type safety is
// not guaranteed when it is retrieved, so exhaustive checks are necessary.
const type = ((area as any).type as string) || 'unknown';
const type = (area.type as string) || 'unknown';
if (type === 'unknown' || (type !== 'tab-area' && type !== 'split-area')) {
console.warn(`Attempted to deserialize unknown type: ${type}`);
return null;
Expand Down Expand Up @@ -881,8 +881,8 @@ namespace Private {
return null;
}

const name = (area as any).current || null;
const dock = (area as any).dock || null;
const name = (area.current as string) || null;
const dock = (area.dock as JSONObject) || null;

return {
currentWidget: (name && names.has(name) && names.get(name)) || null,
Expand Down
3 changes: 2 additions & 1 deletion packages/application/src/mimerenderers.ts
Expand Up @@ -34,7 +34,7 @@ export const IMimeDocumentTracker = new Token<IMimeDocumentTracker>(
*/
export function createRendermimePlugins(
extensions: IRenderMime.IExtensionModule[]
): JupyterFrontEndPlugin<void | IMimeDocumentTracker, any, any>[] {
): JupyterFrontEndPlugin<void | IMimeDocumentTracker>[] {
const plugins: JupyterFrontEndPlugin<void | IMimeDocumentTracker>[] = [];

const namespace = 'application-mimedocuments';
Expand All @@ -45,6 +45,7 @@ export function createRendermimePlugins(

// Handle CommonJS exports.
if (!mod.hasOwnProperty('__esModule')) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data = mod as any;
}
if (!Array.isArray(data)) {
Expand Down
5 changes: 3 additions & 2 deletions packages/application/src/shell.ts
Expand Up @@ -766,6 +766,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
'single-document': ILabShell.IUserLayout;
'multiple-document': ILabShell.IUserLayout;
} {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return JSONExt.deepCopy(this._userLayout as any);
}

Expand Down Expand Up @@ -1694,7 +1695,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
* Handle a change to the dock area active widget.
*/
private _onActiveChanged(
sender: any,
sender: unknown,
args: FocusTracker.IChangedArgs<Widget>
): void {
if (args.newValue) {
Expand All @@ -1713,7 +1714,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
* Handle a change to the dock area current widget.
*/
private _onCurrentChanged(
sender: any,
sender: unknown,
args: FocusTracker.IChangedArgs<Widget>
): void {
if (args.newValue) {
Expand Down
2 changes: 1 addition & 1 deletion packages/application/src/status.ts
Expand Up @@ -13,7 +13,7 @@ export class LabStatus implements ILabStatus {
/**
* Construct a new status object.
*/
constructor(app: JupyterFrontEnd<any, any>) {
constructor(app: JupyterFrontEnd) {
this._busySignal = new Signal(app);
this._dirtySignal = new Signal(app);
}
Expand Down
1 change: 1 addition & 0 deletions packages/application/src/tokens.ts
@@ -1,5 +1,6 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/* eslint-disable @typescript-eslint/no-explicit-any */

import { ServerConnection, ServiceManager } from '@jupyterlab/services';
import { ITranslator } from '@jupyterlab/translation';
Expand Down
4 changes: 2 additions & 2 deletions packages/application/src/utils.ts
Expand Up @@ -196,7 +196,7 @@ export function createSemanticCommand(
commandId => commandId !== null && commands.isEnabled(commandId)
);

let result: any = null;
let result: unknown = null;
if (toExecute.length > 0) {
for (const commandId of toExecute) {
result = await commands.execute(commandId!);
Expand All @@ -215,7 +215,7 @@ export function createSemanticCommand(

function reduceAttribute(
attribute: keyof CommandRegistry.ICommandOptions
): any[] {
): unknown[] {
const widget = shell.currentWidget;
const commandIds = commandList.map(cmd =>
widget !== null ? cmd.getActiveCommandId(widget) : null
Expand Down