Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions src/rules/plugin-activation-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,22 @@ function extractFunctionInfo(
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionExpression
| TSESTree.FunctionDeclaration
): ActivateFunctionInfo {
const params = fn.params.filter(
(param): param is TSESTree.Identifier => param.type === 'Identifier'
);

const paramNames = params.map(param => param.name);

const paramTypes = params.map(param =>
param.type === 'Identifier' ? extractParameterType(param) : null
);

const paramNodes = params.map(param =>
param.type === 'Identifier' ? param : null
);
): ActivateFunctionInfo | null {
const paramNames: string[] = [];
const paramTypes: (string | null)[] = [];
const paramNodes: (TSESTree.Identifier | null)[] = [];

for (const param of fn.params) {
const id = param.type === 'AssignmentPattern' ? param.left : param;
if (id.type !== 'Identifier') {
// A destructured parameter has no name to check, and a rest parameter
// has no fixed position, so leave those functions alone.
return null;
}
paramNames.push(id.name);
paramTypes.push(extractParameterType(id));
paramNodes.push(id);
}

return {
node,
Expand Down
177 changes: 176 additions & 1 deletion tests/jupyter-plugin-activation-args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,33 @@ nonTypeAwareTester.run(
'plugin-activation-args (non-type-aware)',
pluginActivationArgs,
{
valid: [],
valid: [
{
code: `
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
optional: [ITranslator],
activate: (app: JupyterFrontEnd, translator: ITranslator | null = null) => {}
};
`
},
{
code: `
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
activate: ({ commands }: JupyterFrontEnd) => {}
};
`
},
{
code: `
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
activate: (app: JupyterFrontEnd, ...rest: unknown[]) => {}
};
`
}
],
invalid: [
// This same case is in valid cases for the type-aware tester
{
Expand Down Expand Up @@ -650,6 +676,105 @@ ruleTester.run('plugin-activation-args', pluginActivationArgs, {
activate: (app: JupyterFrontEnd) => {}
};
`
},
{
// Optional token with default null value
filename: 'tests/type-aware-fixture.ts',
code: `
import { ITranslator } from './fixtures/types';
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
optional: [ITranslator],
activate: (
app: JupyterFrontEnd,
translator: ITranslator | null = null
) => {}
};
`
},
{
// Optional and required tokens with default values
filename: 'tests/type-aware-fixture.ts',
code: `
import { INotebookTracker, ITranslator } from './fixtures/types';
declare const defaultTracker: INotebookTracker;
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
requires: [INotebookTracker],
optional: [ITranslator],
activate: (
app: JupyterFrontEnd,
tracker: INotebookTracker = defaultTracker,
translator: ITranslator | null = null
) => {}
};
`
},
{
// Method shorthand with default parameter
filename: 'tests/type-aware-fixture.ts',
code: `
import { ITranslator } from './fixtures/types';
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
optional: [ITranslator],
activate(
app: JupyterFrontEnd,
translator: ITranslator | null = null
) {}
};
`
},
{
// Referenced activate function with default parameter
filename: 'tests/type-aware-fixture.ts',
code: `
import { ITranslator } from './fixtures/types';
function activate(
app: JupyterFrontEnd,
translator: ITranslator | null = null
): void {}
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
optional: [ITranslator],
activate
};
`
},
{
// Destructured parameter in activate function is skipped
filename: 'tests/type-aware-fixture.ts',
code: `
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
activate: ({ commands }: JupyterFrontEnd) => {}
};
`
},
{
// Rest parameter in activate function is skipped
filename: 'tests/type-aware-fixture.ts',
code: `
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
activate: (app: JupyterFrontEnd, ...rest: unknown[]) => {}
};
`
},
{
// Destructured token parameter in activate function is skipped
filename: 'tests/type-aware-fixture.ts',
code: `
import { INotebookTracker } from './fixtures/types';
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
requires: [INotebookTracker],
activate: (
app: JupyterFrontEnd,
{ currentWidget }: INotebookTracker
) => {}
};
`
}
],

Expand Down Expand Up @@ -1273,6 +1398,56 @@ ruleTester.run('plugin-activation-args', pluginActivationArgs, {
data: { arg: 'invalidApp', allowedNames: '"app", "_app", "_"' }
}
]
},
{
// Optional token with non-nullable default value
filename: 'tests/type-aware-fixture.ts',
code: `
import { ITranslator } from './fixtures/types';
declare const fallbackTranslator: ITranslator;
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
optional: [ITranslator],
activate: (
app: JupyterFrontEnd,
translator: ITranslator = fallbackTranslator
) => {}
};
`,
errors: [
{
messageId: 'optionalNotNullable',
data: { arg: 'translator', type: 'ITranslator' }
}
]
},
{
// Tokens in wrong order with default parameters
filename: 'tests/type-aware-fixture.ts',
code: `
import { INotebookTracker, IRenderMimeRegistry } from './fixtures/types';
declare const defaultTracker: INotebookTracker;
declare const defaultRenderMime: IRenderMimeRegistry;
const plugin: JupyterFrontEndPlugin<void> = {
id: 'test-plugin',
requires: [INotebookTracker, IRenderMimeRegistry],
activate: (
app: JupyterFrontEnd,
rendermime: IRenderMimeRegistry = defaultRenderMime,
tracker: INotebookTracker = defaultTracker
) => {}
};
`,
errors: [
{
messageId: 'mismatchedOrder',
data: { arg: 'rendermime' }
},
{
messageId: 'mismatchedOrder',
data: { arg: 'tracker' }
}
]
}
]
});
Loading