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

fix: Missing types in JSII assembly, invalid Java code, confusing docs #208

Merged
merged 10 commits into from
Sep 5, 2018
Merged
32 changes: 32 additions & 0 deletions packages/jsii-calc/lib/compliance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -782,3 +782,35 @@ export class ReferenceEnumFromScopedPackage {
this.foo = value;
}
}

/**
* awslabs/jsii#208
* Interface within a namespace
*/
export namespace InterfaceInNamespaceOnlyInterface {

// it's a special case when only an interface is exported from a namespace
export interface Hello {
foo: number
}

}

export namespace InterfaceInNamespaceIncludesClasses {

export class Foo {
public bar?: string;
}

export interface Hello {
foo: number
}
}

/**
* awslabs/jsii#175
* Interface proxies (and builders) do not respect optional arguments in methods
*/
export interface InterfaceWithOptionalMethodArguments {
hello(arg1: string, arg2?: number): void
}
82 changes: 81 additions & 1 deletion packages/jsii-calc/test/assembly.jsii
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,86 @@
}
]
},
"jsii-calc.InterfaceInNamespaceIncludesClasses.Foo": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.InterfaceInNamespaceIncludesClasses.Foo",
"initializer": {
"initializer": true
},
"kind": "class",
"name": "Foo",
"namespace": "InterfaceInNamespaceIncludesClasses",
"properties": [
{
"name": "bar",
"type": {
"optional": true,
"primitive": "string"
}
}
]
},
"jsii-calc.InterfaceInNamespaceIncludesClasses.Hello": {
"assembly": "jsii-calc",
"datatype": true,
"fqn": "jsii-calc.InterfaceInNamespaceIncludesClasses.Hello",
"kind": "interface",
"name": "Hello",
"namespace": "InterfaceInNamespaceIncludesClasses",
"properties": [
{
"name": "foo",
"type": {
"primitive": "number"
}
}
]
},
"jsii-calc.InterfaceInNamespaceOnlyInterface.Hello": {
"assembly": "jsii-calc",
"datatype": true,
"fqn": "jsii-calc.InterfaceInNamespaceOnlyInterface.Hello",
"kind": "interface",
"name": "Hello",
"namespace": "InterfaceInNamespaceOnlyInterface",
"properties": [
{
"name": "foo",
"type": {
"primitive": "number"
}
}
]
},
"jsii-calc.InterfaceWithOptionalMethodArguments": {
"assembly": "jsii-calc",
"docs": {
"comment": "awslabs/jsii#175\nInterface proxies (and builders) do not respect optional arguments in methods"
},
"fqn": "jsii-calc.InterfaceWithOptionalMethodArguments",
"kind": "interface",
"methods": [
{
"name": "hello",
"parameters": [
{
"name": "arg1",
"type": {
"primitive": "string"
}
},
{
"name": "arg2",
"type": {
"optional": true,
"primitive": "number"
}
}
]
}
],
"name": "InterfaceWithOptionalMethodArguments"
},
"jsii-calc.JSObjectLiteralForInterface": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.JSObjectLiteralForInterface",
Expand Down Expand Up @@ -2844,5 +2924,5 @@
}
},
"version": "0.7.1",
"fingerprint": "xRKsZzmRl0yM7EYcHnUbf691eFzAupWFIvCbEqWcUuA="
"fingerprint": "3uROoDToOcKIpYs9haAGnS37Iebz1/+ldcknrh37qDQ="
}
11 changes: 10 additions & 1 deletion packages/jsii-pacmak/lib/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,16 @@ export abstract class Generator implements IGenerator {
return this.excludeTypes.includes(name);
}

private createOverloadsForOptionals(method: spec.Method) {
/**
* Returns all the method overloads needed to satisfy optional arguments.
* For example, for the method `foo(bar: string, hello?: number, world?: number)`
* this method will return:
* - foo(bar: string)
* - foo(bar: string, hello: number)
*
* Notice that the method that contains all the arguments will not be returned.
*/
protected createOverloadsForOptionals(method: spec.Method) {
const methods = new Array<spec.Method>();

// if option disabled, just return the empty array.
Expand Down
10 changes: 7 additions & 3 deletions packages/jsii-pacmak/lib/targets/java.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,10 @@ class JavaGenerator extends Generator {
for (const methodName of Object.keys(methods)) {
const method = methods[methodName];
this.emitMethod(ifc, method, /* overrides: */ true);

for (const overloadedMethod of this.createOverloadsForOptionals(method)) {
this.emitMethod(ifc, overloadedMethod, /* overrides: */ true);
}
}

this.code.closeBlock();
Expand Down Expand Up @@ -754,20 +758,20 @@ class JavaGenerator extends Generator {
for (const prop of props) {
if (prop.optional) { this.code.line(JSR305_NULLABLE); }
// tslint:disable-next-line:max-line-length
this.code.line(`private${prop.immutable ? ' final' : ''} ${prop.fieldJavaType} ${prop.fieldName} = ${_validateIfNonOptional(`_${prop.fieldName}`, prop)};`);
this.code.line(`private${prop.immutable ? ' final' : ''} ${prop.fieldJavaType} $${prop.fieldName} = ${_validateIfNonOptional(`_${prop.fieldName}`, prop)};`);
eladb marked this conversation as resolved.
Show resolved Hide resolved
}
for (const prop of props) {
this.code.line();
this.code.line('@Override');
this.code.openBlock(`public ${prop.fieldJavaType} get${prop.propName}()`);
this.code.line(`return this.${prop.fieldName};`);
this.code.line(`return this.$${prop.fieldName};`);
this.code.closeBlock();
if (!prop.immutable) {
for (const type of prop.javaTypes) {
this.code.line();
this.code.line('@Override');
this.code.openBlock(`public void set${prop.propName}(${prop.optional ? `${JSR305_NULLABLE} ` : ''}final ${type} value)`);
this.code.line(`this.${prop.fieldName} = ${_validateIfNonOptional('value', prop)};`);
this.code.line(`this.$${prop.fieldName} = ${_validateIfNonOptional('value', prop)};`);
this.code.closeBlock();
}
}
Expand Down
21 changes: 15 additions & 6 deletions packages/jsii-pacmak/lib/targets/sphinx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,33 +517,42 @@ class SphinxDocsGenerator extends Generator {
};
} else if (spec.isCollectionTypeReference(type)) {
const elementType = this.renderTypeRef(type.collection.elementtype);
const ref = wrap(elementType.ref);
const display = wrap(elementType.display);

switch (type.collection.kind) {
case spec.CollectionKind.Array:
result = {
ref: elementType.ref,
display: `${elementType.display}[]`
ref: `${ref}[]`,
display: `${display}[]`
};
break;
case spec.CollectionKind.Map:
result = {
ref: elementType.ref,
display: `string => ${elementType.display}`
ref: `string => ${ref}`,
display: `string => ${display}`
};
break;
default:
throw new Error(`Unexpected collection kind: ${type.collection.kind}`);
}
} else if (spec.isUnionTypeReference(type)) {
const mappedTypes = type.union.types.map(t => this.renderTypeRef(t));
result = {
display: type.union.types.map(t => this.renderTypeRef(t).display).join(' or '),
ref: type.union.types.map(t => this.renderTypeRef(t).ref).join(' or '),
display: mappedTypes.map(t => t.display).join(' or '),
ref: mappedTypes.map(t => t.ref).join(' or '),
};
} else {
throw new Error('Unexpected type ref');
}
if (type.optional) { result.ref = `${result.ref} or undefined`; }
return result;

// Wrap a string between parenthesis if it contains " or "
function wrap(str: string): string {
if (str.indexOf(' or ') === -1) { return str; }
return `(${str})`;
}
}

private renderProperty(prop: spec.Property) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,27 @@ public Builder withFoo(final software.amazon.jsii.tests.calculator.baseofbase.Ve
*/
public BaseProps build() {
return new BaseProps() {
private java.lang.String bar = java.util.Objects.requireNonNull(_bar, "bar is required");
private software.amazon.jsii.tests.calculator.baseofbase.Very foo = java.util.Objects.requireNonNull(_foo, "foo is required");
private java.lang.String $bar = java.util.Objects.requireNonNull(_bar, "bar is required");
private software.amazon.jsii.tests.calculator.baseofbase.Very $foo = java.util.Objects.requireNonNull(_foo, "foo is required");

@Override
public java.lang.String getBar() {
return this.bar;
return this.$bar;
}

@Override
public void setBar(final java.lang.String value) {
this.bar = java.util.Objects.requireNonNull(value, "bar is required");
this.$bar = java.util.Objects.requireNonNull(value, "bar is required");
}

@Override
public software.amazon.jsii.tests.calculator.baseofbase.Very getFoo() {
return this.foo;
return this.$foo;
}

@Override
public void setFoo(final software.amazon.jsii.tests.calculator.baseofbase.Very value) {
this.foo = java.util.Objects.requireNonNull(value, "foo is required");
this.$foo = java.util.Objects.requireNonNull(value, "foo is required");
}

};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,39 +75,39 @@ public Builder withFirstOptional(@javax.annotation.Nullable final java.util.List
*/
public MyFirstStruct build() {
return new MyFirstStruct() {
private java.lang.Number anumber = java.util.Objects.requireNonNull(_anumber, "anumber is required");
private java.lang.String astring = java.util.Objects.requireNonNull(_astring, "astring is required");
private java.lang.Number $anumber = java.util.Objects.requireNonNull(_anumber, "anumber is required");
private java.lang.String $astring = java.util.Objects.requireNonNull(_astring, "astring is required");
@javax.annotation.Nullable
private java.util.List<java.lang.String> firstOptional = _firstOptional;
private java.util.List<java.lang.String> $firstOptional = _firstOptional;

@Override
public java.lang.Number getAnumber() {
return this.anumber;
return this.$anumber;
}

@Override
public void setAnumber(final java.lang.Number value) {
this.anumber = java.util.Objects.requireNonNull(value, "anumber is required");
this.$anumber = java.util.Objects.requireNonNull(value, "anumber is required");
}

@Override
public java.lang.String getAstring() {
return this.astring;
return this.$astring;
}

@Override
public void setAstring(final java.lang.String value) {
this.astring = java.util.Objects.requireNonNull(value, "astring is required");
this.$astring = java.util.Objects.requireNonNull(value, "astring is required");
}

@Override
public java.util.List<java.lang.String> getFirstOptional() {
return this.firstOptional;
return this.$firstOptional;
}

@Override
public void setFirstOptional(@javax.annotation.Nullable final java.util.List<java.lang.String> value) {
this.firstOptional = value;
this.$firstOptional = value;
}

};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,40 +72,40 @@ public Builder withOptional3(@javax.annotation.Nullable final java.lang.Boolean
public StructWithOnlyOptionals build() {
return new StructWithOnlyOptionals() {
@javax.annotation.Nullable
private java.lang.String optional1 = _optional1;
private java.lang.String $optional1 = _optional1;
@javax.annotation.Nullable
private java.lang.Number optional2 = _optional2;
private java.lang.Number $optional2 = _optional2;
@javax.annotation.Nullable
private java.lang.Boolean optional3 = _optional3;
private java.lang.Boolean $optional3 = _optional3;

@Override
public java.lang.String getOptional1() {
return this.optional1;
return this.$optional1;
}

@Override
public void setOptional1(@javax.annotation.Nullable final java.lang.String value) {
this.optional1 = value;
this.$optional1 = value;
}

@Override
public java.lang.Number getOptional2() {
return this.optional2;
return this.$optional2;
}

@Override
public void setOptional2(@javax.annotation.Nullable final java.lang.Number value) {
this.optional2 = value;
this.$optional2 = value;
}

@Override
public java.lang.Boolean getOptional3() {
return this.optional3;
return this.$optional3;
}

@Override
public void setOptional3(@javax.annotation.Nullable final java.lang.Boolean value) {
this.optional3 = value;
this.$optional3 = value;
}

};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ MyFirstStruct (interface)

.. py:attribute:: firstOptional
:type: string or undefined
:type: string[] or undefined


Number
Expand Down
Loading