Skip to content

Commit

Permalink
feat: always use root signature parameter names
Browse files Browse the repository at this point in the history
In languages such as Python (<3.8) and Ruby, positional parameters can
be referred to using their names, making these names part of the
function signature. In order to avoid enforing parameter name
consistency on the TypeScript source, the `jsii` compiler will always
use the root declaration's parameter names when emitting the `.jsii`
assembly file.

Related #2927
  • Loading branch information
RomainMuller committed Aug 9, 2021
1 parent a996fe6 commit c665b7e
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/jsii/lib/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,10 @@ function _defaultValidations(): ValidationFunction[] {
),
);
}
// Standardize to the root method's argument signature, because in
// Python and Ruby, positional parameters can also be referred to by
// name, which makes their names be a part of the function's signature.
actParam.name = expParam.name;
}
}

Expand Down
107 changes: 107 additions & 0 deletions packages/jsii/test/compat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { sourceToAssemblyHelper } from '../lib';

////////////////////////////////////////////////////////////////////////////////
// In Python and Ruby, positional parameters can be referred to by name, making
// them part of a function's signature. Always using the root implementation
// parameter names makes no difference in the undelying runtime, as JS
// positional arguments are... positional, but it reduces friction for Python
// and Ruby developers.
test('overriding methods use the overriden parameter names', async () => {
const assembly = await sourceToAssemblyHelper(`
export abstract class AbstractClass {
public abstract method(param: number): void;
}
export class ConcreteClass extends AbstractClass {
private constructor() { super(); }
public method(_arg: number): void {
// Nothing to do...
}
}
`);

expect(assembly.types!['testpkg.AbstractClass']).toEqual({
abstract: true,
assembly: 'testpkg',
fqn: 'testpkg.AbstractClass',
kind: 'class',
methods: [
{
abstract: true,
locationInModule: { filename: 'index.ts', line: 3 },
name: 'method',
parameters: [{ name: 'param', type: { primitive: 'number' } }],
},
],
initializer: {},
locationInModule: { filename: 'index.ts', line: 2 },
name: 'AbstractClass',
});

expect(assembly.types!['testpkg.ConcreteClass']).toEqual({
assembly: 'testpkg',
base: 'testpkg.AbstractClass',
fqn: 'testpkg.ConcreteClass',
kind: 'class',
methods: [
{
locationInModule: { filename: 'index.ts', line: 9 },
name: 'method',
overrides: 'testpkg.AbstractClass',
parameters: [{ name: 'param', type: { primitive: 'number' } }],
},
],
locationInModule: { filename: 'index.ts', line: 6 },
name: 'ConcreteClass',
});
});

test('implementing methods use the interface parameter names', async () => {
const assembly = await sourceToAssemblyHelper(`
export interface IInterface {
method(param: number): void;
}
export class ConcreteClass implements IInterface {
private constructor() {}
public method(_arg: number): void {
// Nothing to do...
}
}
`);

expect(assembly.types!['testpkg.IInterface']).toEqual({
assembly: 'testpkg',
fqn: 'testpkg.IInterface',
kind: 'interface',
methods: [
{
abstract: true,
locationInModule: { filename: 'index.ts', line: 3 },
name: 'method',
parameters: [{ name: 'param', type: { primitive: 'number' } }],
},
],
locationInModule: { filename: 'index.ts', line: 2 },
name: 'IInterface',
});

expect(assembly.types!['testpkg.ConcreteClass']).toEqual({
assembly: 'testpkg',
interfaces: ['testpkg.IInterface'],
fqn: 'testpkg.ConcreteClass',
kind: 'class',
methods: [
{
locationInModule: { filename: 'index.ts', line: 9 },
name: 'method',
overrides: 'testpkg.IInterface',
parameters: [{ name: 'param', type: { primitive: 'number' } }],
},
],
locationInModule: { filename: 'index.ts', line: 6 },
name: 'ConcreteClass',
});
});

0 comments on commit c665b7e

Please sign in to comment.