From 31ec095c8c5e23bebf52a458ca296074cd000edc Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Mon, 10 Aug 2020 16:52:00 +0200 Subject: [PATCH] chore(jsii): better errors around use of hidden types (#1861) When a hidden (that is, `@internal` or not exported) type is used in a visible (`public` or `protected` on an exported type) API, the error produced would refer to the unusable type, but would not give any indication of where it was being used from. This makes several enhancements to this process: - Qualify the kind of use for the type (return, parameter, ...) - Attach the error to the resolving node (usage location) - Provide a related message with the unusable type's declaration - Specifically message around "this" (used or inferred as a return type) This is going to particularly enhance the experience of folks extending internal base types, where those internal base types declare members that return hidden types (or "this"). Fixes #1860 --- packages/jsii/lib/assembler.ts | 251 ++++++-- .../test/__snapshots__/negatives.test.js.snap | 581 ++++++++++++++++++ packages/jsii/test/negatives.test.ts | 69 +-- .../neg.behavior-requires-iprefix.ts | 2 - .../jsii/test/negatives/neg.class-name.1.ts | 6 +- .../jsii/test/negatives/neg.class-name.ts | 6 +- .../test/negatives/neg.compilation-error.ts | 5 +- .../jsii/test/negatives/neg.const-enum.ts | 6 +- .../neg.double-interface-members-deeper.ts | 6 +- .../neg.double-interface-members-method.ts | 3 - .../negatives/neg.double-interface-members.ts | 2 - .../jsii/test/negatives/neg.enum-members.1.ts | 6 +- .../jsii/test/negatives/neg.enum-name.1.ts | 6 +- .../jsii/test/negatives/neg.enum-name.2.ts | 6 +- .../neg.expose-unexported-type-external.ts | 4 +- ...e-unexported-type-internal-in-namespace.ts | 7 +- .../neg.expose-unexported-type-internal.ts | 8 +- .../neg.expose-unexported-type-this.ts | 13 + .../jsii/test/negatives/neg.extend-struct.ts | 2 - .../test/negatives/neg.implement-struct.ts | 2 - .../neg.implementation-changes-types.1.ts | 10 +- .../neg.implementation-changes-types.2.ts | 10 +- .../neg.implementation-changes-types.3.ts | 10 +- .../neg.implementation-changes-types.4.ts | 6 +- .../neg.implementation-changes-types.5.ts | 10 +- ...plementing-method-changes-optionality.1.ts | 2 - ...plementing-method-changes-optionality.2.ts | 2 - ...implementing-method-changes-optionality.ts | 2 - ...ementing-property-changes-optionality.1.ts | 2 - ...ementing-property-changes-optionality.2.ts | 2 - ...plementing-property-changes-optionality.ts | 2 - .../test/negatives/neg.implements-class.ts | 14 +- .../neg.inheritance-changes-types.1.ts | 14 +- .../neg.inheritance-changes-types.2.ts | 14 +- .../neg.inheritance-changes-types.3.ts | 14 +- .../neg.inheritance-changes-types.4.ts | 6 +- .../neg.inheritance-changes-types.5.ts | 10 +- .../neg.internal-underscore-class.5.ts | 2 - .../neg.internal-underscore-class.6.ts | 2 - .../neg.internal-underscore-class.7.ts | 6 +- .../neg.internal-underscore-class.8.ts | 4 +- .../neg.internal-underscore-interface.1.ts | 2 - .../neg.internal-underscore-interface.2.ts | 2 - .../neg.internal-underscore-interface.3.ts | 2 - .../neg.internal-underscore-interface.4.ts | 2 - .../jsii/test/negatives/neg.method-name.1.ts | 8 +- .../jsii/test/negatives/neg.method-name.2.ts | 8 +- .../jsii/test/negatives/neg.method-name.3.ts | 8 +- .../jsii/test/negatives/neg.method-name.4.ts | 8 +- .../neg.mix-datatype-and-arg-name.ts | 8 +- .../test/negatives/neg.mutable-datatype.ts | 2 - .../neg.non-optional-after-optional-ctor.ts | 8 +- .../neg.non-optional-after-optional-method.ts | 8 +- packages/jsii/test/negatives/neg.omit.1.ts | 2 - packages/jsii/test/negatives/neg.omit.2.ts | 2 - packages/jsii/test/negatives/neg.omit.3.ts | 2 - packages/jsii/test/negatives/neg.omit.4.ts | 2 - .../test/negatives/neg.property-name.1.ts | 4 +- .../test/negatives/neg.property-name.2.ts | 4 +- .../test/negatives/neg.property-name.3.ts | 4 +- .../negatives/neg.reserved.emits-warning.ts | 7 +- .../test/negatives/neg.static-const-name.ts | 4 +- .../negatives/neg.static-member-mixing.1.ts | 4 +- .../negatives/neg.static-member-mixing.2.ts | 4 +- .../negatives/neg.static-method-name.1.ts | 8 +- .../test/negatives/neg.static-method-name.ts | 8 +- .../test/negatives/neg.static-prop-name.1.ts | 8 +- .../test/negatives/neg.static-prop-name.2.ts | 8 +- .../negatives/neg.struct-extends-interface.ts | 2 - ....submodules-cannot-have-colliding-names.ts | 4 +- .../neg.submodules-cannot-share-symbols.ts | 2 - .../neg.submodules-must-be-camel-cased.ts | 2 - 72 files changed, 927 insertions(+), 355 deletions(-) create mode 100644 packages/jsii/test/__snapshots__/negatives.test.js.snap create mode 100644 packages/jsii/test/negatives/neg.expose-unexported-type-this.ts diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index 08e816da90..fa8bed0f3b 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -376,11 +376,21 @@ export class Assembler implements Emitter { * computed for the type, a marker is returned instead, and an ``ts.DiagnosticCategory.Error`` diagnostic is * inserted in the assembler context. * - * @param type the type for which a JSII fully qualified name is neede. + * @param type the type for which a JSII fully qualified name is needed. + * @param typeAnnotationNode the type annotation for which this FQN is generated. This is used for attaching the error + * marker. When there is no explicit type annotation (e.g: inferred method return type), the + * preferred substitute is the "type-inferred" element's name. + * @param typeUse the reason why this type was resolved (e.g: "return type") + * @param isThisType whether this type was specified or inferred as "this" or not * * @returns the FQN of the type, or some "unknown" marker. */ - private async _getFQN(type: ts.Type): Promise { + private async _getFQN( + type: ts.Type, + typeAnnotationNode: ts.Node, + typeUse: TypeUseKind, + isThisType: boolean, + ): Promise { const singleValuedEnum = isSingleValuedEnum(type, this._typeChecker); const tsFullName = this._typeChecker.getFullyQualifiedName(type.symbol); @@ -389,31 +399,57 @@ export class Assembler implements Emitter { tsFullName.replace(/\.[^.]+$/, '') : tsFullName; - let node = singleValuedEnum + let typeDeclaration = singleValuedEnum ? // If it's a single-valued enum, we need to move to the parent to have the enum declaration type.symbol.valueDeclaration.parent : type.symbol.valueDeclaration; - if (!node && type.symbol.declarations.length > 0) { - node = type.symbol.declarations[0]; + if (!typeDeclaration && type.symbol.declarations.length > 0) { + typeDeclaration = type.symbol.declarations[0]; } - const groups = /^"([^"]+)"\.(.*)$/.exec(tsName); - if (!groups) { + // Set to true to prevent further adding of Error diagnostics for known-bad reference + let hasError = false; + + if (this._isPrivateOrInternal(type.symbol)) { + // Check if this type is "this" (explicit or inferred method return type). + const commonMessage = `cannot be used as the ${typeUse} because it is private or @internal`; this._diagnostic( - node, + typeAnnotationNode, ts.DiagnosticCategory.Error, - `Cannot use private type ${tsName} in exported declarations`, + isThisType + ? `Type "this" (aka: "${type.symbol.name}") ${commonMessage}` + : `Type "${type.symbol.name}" ${commonMessage}`, + makeCause(typeDeclaration), ); + + hasError = true; + } + + const groups = /^"([^"]+)"\.(.*)$/.exec(tsName); + if (!groups) { + if (!hasError) { + this._diagnostic( + typeAnnotationNode, + ts.DiagnosticCategory.Error, + `Cannot use internal type ${tsName} as a ${typeUse} in exported declarations`, + makeCause(typeDeclaration), + ); + hasError = true; + } return tsName; } const [, modulePath, typeName] = groups; const pkg = await findPackageInfo(modulePath); if (!pkg) { - this._diagnostic( - node, - ts.DiagnosticCategory.Error, - `Could not find module for ${modulePath}`, - ); + if (!hasError) { + this._diagnostic( + typeAnnotationNode, + ts.DiagnosticCategory.Error, + `Could not find module corresponding to ${modulePath}`, + makeCause(typeDeclaration), + ); + hasError = true; + } return `unknown.${typeName}`; } @@ -428,13 +464,38 @@ export class Assembler implements Emitter { pkg.name !== this.projectInfo.name && !this._dereference({ fqn }, type.symbol.valueDeclaration) ) { - this._diagnostic( - node, - ts.DiagnosticCategory.Error, - `Use of foreign type not present in the ${pkg.name}'s assembly: ${fqn}`, - ); + if (!hasError) { + this._diagnostic( + typeAnnotationNode, + ts.DiagnosticCategory.Error, + `Type "${fqn}" cannot be used as a ${typeUse} because it is not exported from ${pkg.name}`, + makeCause(typeDeclaration), + ); + hasError = true; + } } return fqn; + + function makeCause(node: ts.Node): ts.DiagnosticRelatedInformation[] { + const declNode = + ts.isClassDeclaration(node) || + ts.isEnumDeclaration(node) || + ts.isInterfaceDeclaration(node) || + ts.isTypeAliasDeclaration(node) + ? node.name ?? node + : node; + return [ + { + category: ts.DiagnosticCategory.Message, + code: JSII_DIAGNOSTICS_CODE, + file: declNode.getSourceFile(), + start: declNode.getStart(declNode.getSourceFile()), + length: + declNode.getEnd() - declNode.getStart(declNode.getSourceFile()), + messageText: `The referenced type is declared here`, + }, + ]; + } } /** @@ -560,7 +621,7 @@ export class Assembler implements Emitter { symbol.name !== Case.snake(symbol.name) ) { this._diagnostic( - declaration, + declaration.name, ts.DiagnosticCategory.Error, `Submodule namespaces must be camelCased or snake_cased. Consider renaming to "${Case.camel( symbol.name, @@ -645,25 +706,39 @@ export class Assembler implements Emitter { if (currNs.name !== ns.name) { const currNsDecl = currNs.valueDeclaration ?? currNs.declarations[0]; const nsDecl = ns.valueDeclaration ?? ns.declarations[0]; + + // Make sure the error message always lists causes in the same order + const refs = [ + [currNs.name, currNsDecl] as const, + [ns.name, nsDecl] as const, + ].sort(([l], [r]) => l.localeCompare(r)); + this._diagnostic( - symbol.valueDeclaration, + (symbol.valueDeclaration as { name?: ts.Node }).name ?? + symbol.valueDeclaration, ts.DiagnosticCategory.Error, - `Symbol is re-exported under two distinct submodules (${currNs.name} and ${ns.name})`, + `Symbol is re-exported under two distinct submodules (${refs + .map(([name]) => name) + .join(' and ')})`, [ { category: ts.DiagnosticCategory.Warning, - file: currNsDecl.getSourceFile(), - length: currNsDecl.getStart() - currNsDecl.getEnd(), - messageText: `Symbol is exported under the "${currNs.name}" submodule`, - start: currNsDecl.getStart(), + file: refs[0][1].getSourceFile(), + length: + refs[0][1].getEnd() - + refs[0][1].getStart(refs[0][1].getSourceFile()), + messageText: `Symbol is exported under the "${refs[0][0]}" submodule`, + start: refs[0][1].getStart(refs[0][1].getSourceFile()), code: JSII_DIAGNOSTICS_CODE, }, { category: ts.DiagnosticCategory.Warning, - file: nsDecl.getSourceFile(), - length: nsDecl.getStart() - nsDecl.getEnd(), - messageText: `Symbol is exported under the "${ns.name}" submodule`, - start: nsDecl.getStart(), + file: refs[1][1].getSourceFile(), + length: + refs[1][1].getEnd() - + refs[1][1].getStart(refs[1][1].getSourceFile()), + messageText: `Symbol is exported under the "${refs[1][0]}" submodule`, + start: refs[1][1].getStart(refs[1][1].getSourceFile()), code: JSII_DIAGNOSTICS_CODE, }, ], @@ -861,8 +936,10 @@ export class Assembler implements Emitter { if (colliding != null) { const submoduleDecl = submodule.valueDeclaration ?? submodule.declarations[0]; + const submoduleDeclName = + (submoduleDecl as { name?: ts.Node }).name ?? submoduleDecl; this._diagnostic( - node, + (node as { name?: ts.Node }).name ?? node, ts.DiagnosticCategory.Error, `Submodule "${submodule.name}" conflicts with "${ jsiiType.name @@ -871,10 +948,10 @@ export class Assembler implements Emitter { { category: ts.DiagnosticCategory.Warning, code: JSII_DIAGNOSTICS_CODE, - file: submoduleDecl.getSourceFile(), - length: submoduleDecl.getEnd() - submoduleDecl.getStart(), + file: submoduleDeclName.getSourceFile(), + length: submoduleDeclName.getEnd() - submoduleDeclName.getStart(), messageText: 'This is the conflicting submodule declaration.', - start: submoduleDecl.getStart(), + start: submoduleDeclName.getStart(), }, ], ); @@ -993,7 +1070,7 @@ export class Assembler implements Emitter { const typeRefs = Array.from(baseInterfaces).map(async (iface) => { const decl = iface.symbol.valueDeclaration; - const typeRef = await this._typeReference(iface, decl); + const typeRef = await this._typeReference(iface, decl, 'base interface'); return { decl, typeRef }; }); for (const { decl, typeRef } of await Promise.all(typeRefs)) { @@ -1096,7 +1173,11 @@ export class Assembler implements Emitter { } // eslint-disable-next-line no-await-in-loop - const ref = await this._typeReference(base, type.symbol.valueDeclaration); + const ref = await this._typeReference( + base, + type.symbol.valueDeclaration, + 'base class', + ); if (!spec.isNamedTypeReference(ref)) { this._diagnostic( @@ -1214,7 +1295,7 @@ export class Assembler implements Emitter { } for (const memberDecl of classDecl.members) { - // The "??" is to get to the __constructor symbol (getSymbolAtLocation wouldn't work there...) + // The "??" is to get to the __constructor symbol (getSymbolAtLocation wouldn't work there..) const member = this._typeChecker.getSymbolAtLocation(memberDecl.name!) ?? ((memberDecl as any).symbol as ts.Symbol); @@ -1227,7 +1308,7 @@ export class Assembler implements Emitter { continue; } - if (this._isPrivateOrInternal(member, memberDecl)) { + if (this._isPrivateOrInternal(member, memberDecl as ts.ClassElement)) { continue; } @@ -1463,7 +1544,7 @@ export class Assembler implements Emitter { */ private _isPrivateOrInternal( symbol: ts.Symbol, - validateDeclaration?: ts.Declaration, + validateDeclaration?: ts.Declaration & { name?: ts.Node }, ): boolean { const hasInternalJsDocTag = _hasInternalJsDocTag(symbol); const hasUnderscorePrefix = @@ -1486,7 +1567,7 @@ export class Assembler implements Emitter { if (validateDeclaration) { if (!hasUnderscorePrefix) { this._diagnostic( - validateDeclaration, + validateDeclaration.name ?? validateDeclaration, ts.DiagnosticCategory.Error, `${colors.cyan( symbol.name, @@ -1496,7 +1577,7 @@ export class Assembler implements Emitter { if (!hasInternalJsDocTag) { this._diagnostic( - validateDeclaration, + validateDeclaration.name ?? validateDeclaration, ts.DiagnosticCategory.Error, `${colors.cyan( symbol.name, @@ -1660,7 +1741,12 @@ export class Assembler implements Emitter { continue; } - if (this._isPrivateOrInternal(member, member.valueDeclaration)) { + if ( + this._isPrivateOrInternal( + member, + member.valueDeclaration as ts.PropertyDeclaration, + ) + ) { continue; } @@ -1699,10 +1785,12 @@ export class Assembler implements Emitter { // Calculate datatype based on the datatypeness of this interface and all of its parents // To keep the spec minimal the actual values of the attribute are "true" or "undefined" (to represent "false"). + const declaration = + type.symbol.valueDeclaration ?? type.symbol.declarations[0]; this._deferUntilTypesAvailable( fqn, jsiiType.interfaces ?? [], - type.symbol.valueDeclaration, + declaration, (...bases: spec.Type[]) => { if ((jsiiType.methods ?? []).length === 0) { jsiiType.datatype = true; @@ -1719,7 +1807,7 @@ export class Assembler implements Emitter { // If it's not a datatype the name must start with an "I". if (!jsiiType.datatype && !interfaceName) { this._diagnostic( - type.symbol.declarations[0], + (declaration as { name?: ts.Node }).name ?? declaration, ts.DiagnosticCategory.Error, `Interface contains behavior: name should be "I${jsiiType.name}"`, ); @@ -1727,7 +1815,7 @@ export class Assembler implements Emitter { // If the name starts with an "I" it is not intended as a datatype, so switch that off. if (jsiiType.datatype && interfaceName) { - jsiiType.datatype = undefined; + delete jsiiType.datatype; } // Okay, this is a data type, check that all properties are readonly @@ -1749,7 +1837,7 @@ export class Assembler implements Emitter { // This is *NOT* a data type, so it may not extend something that is one. for (const base of bases) { if (!spec.isInterfaceType(base)) { - // Invalid type we already warned about earlier, just ignoring it here... + // Invalid type we already warned about earlier, just ignoring it here.. continue; } if (base.datatype) { @@ -1851,7 +1939,11 @@ export class Assembler implements Emitter { protected: _isProtected(symbol) || undefined, returns: _isVoid(returnType) ? undefined - : await this._optionalValue(returnType, declaration), + : await this._optionalValue( + returnType, + declaration.name, + 'return type', + ), async: _isPromise(returnType) || undefined, static: _isStatic(symbol) || undefined, locationInModule: this.declarationLocation(declaration), @@ -1974,7 +2066,8 @@ export class Assembler implements Emitter { const property: spec.Property = { ...(await this._optionalValue( this._typeChecker.getTypeOfSymbolAtLocation(symbol, signature), - signature, + signature.name, + 'property type', )), abstract: _isAbstract(symbol, type) || undefined, name: symbol.name, @@ -2038,8 +2131,9 @@ export class Assembler implements Emitter { const parameter: spec.Parameter = { ...(await this._optionalValue( - this._typeChecker.getTypeAtLocation(paramSymbol.valueDeclaration), - paramSymbol.valueDeclaration, + this._typeChecker.getTypeAtLocation(paramDeclaration), + paramDeclaration.name, + 'parameter type', )), name: paramSymbol.name, variadic: paramDeclaration.dotDotDotToken && true, @@ -2063,9 +2157,10 @@ export class Assembler implements Emitter { private async _typeReference( type: ts.Type, - declaration: ts.Declaration, + declaration: ts.Node, + purpose: TypeUseKind, ): Promise { - const optionalValue = await this._optionalValue(type, declaration); + const optionalValue = await this._optionalValue(type, declaration, purpose); if (optionalValue.optional) { this._diagnostic( declaration, @@ -2078,8 +2173,11 @@ export class Assembler implements Emitter { private async _optionalValue( type: ts.Type, - declaration: ts.Declaration, + declaration: ts.Node, + purpose: TypeUseKind, ): Promise { + const isThisType = _isThisType(type, this._typeChecker); + if (type.isLiteral() && _isEnumLike(type)) { type = this._typeChecker.getBaseTypeOfLiteralType(type); } else { @@ -2123,11 +2221,17 @@ export class Assembler implements Emitter { return { type: spec.CANONICAL_ANY }; } return { - type: await this._typeReference(typeRef.typeArguments[0], declaration), + type: await this._typeReference( + typeRef.typeArguments[0], + declaration, + purpose, + ), }; } - return { type: { fqn: await this._getFQN(type) } }; + return { + type: { fqn: await this._getFQN(type, declaration, purpose, isThisType) }, + }; async function _arrayType( this: Assembler, @@ -2139,6 +2243,7 @@ export class Assembler implements Emitter { elementtype = await this._typeReference( typeRef.typeArguments[0], declaration, + 'list element type', ); } else { const count = typeRef.typeArguments @@ -2166,7 +2271,11 @@ export class Assembler implements Emitter { let elementtype: spec.TypeReference; const objectType = type.getStringIndexType(); if (objectType) { - elementtype = await this._typeReference(objectType, declaration); + elementtype = await this._typeReference( + objectType, + declaration, + 'map element type', + ); } else { this._diagnostic( declaration, @@ -2230,7 +2339,11 @@ export class Assembler implements Emitter { continue; } // eslint-disable-next-line no-await-in-loop - const resolvedType = await this._typeReference(subType, declaration); + const resolvedType = await this._typeReference( + subType, + declaration, + purpose, + ); if (types.find((ref) => deepEqual(ref, resolvedType)) != null) { continue; } @@ -2806,3 +2919,27 @@ async function findPackageInfo(fromDir: string): Promise { } return findPackageInfo(parent); } + +/** + * Checks is the provided type is "this" (as a type annotation). + * + * @param type the validated type. + * @param typeChecker the type checker. + * + * @returns `true` iif the type is `this` + */ +function _isThisType(type: ts.Type, typeChecker: ts.TypeChecker): boolean { + return typeChecker.typeToTypeNode(type)?.kind === ts.SyntaxKind.ThisKeyword; +} + +/** + * A location where a type can be used. + */ +type TypeUseKind = + | 'base class' + | 'base interface' + | 'list element type' + | 'map element type' + | 'parameter type' + | 'property type' + | 'return type'; diff --git a/packages/jsii/test/__snapshots__/negatives.test.js.snap b/packages/jsii/test/__snapshots__/negatives.test.js.snap new file mode 100644 index 0000000000..d42c6919fc --- /dev/null +++ b/packages/jsii/test/__snapshots__/negatives.test.js.snap @@ -0,0 +1,581 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`behavior-requires-iprefix 1`] = ` +"neg.behavior-requires-iprefix.ts:1:18 - error TS9999: JSII: Interface contains behavior: name should be \\"ISomething\\" + +1 export interface Something { + ~~~~~~~~~ +" +`; + +exports[`class-name 1`] = ` +"error TS0: Type names must use PascalCase: myclass +" +`; + +exports[`class-name.1 1`] = ` +"error TS0: Type names must use PascalCase: My_class +" +`; + +exports[`compilation-error 1`] = ` +"neg.compilation-error.ts:1:1 - error TS2304: Cannot find name 'boom'. + +1 boom! > CompilerErrorIsHere; + ~~~~ +neg.compilation-error.ts:1:9 - error TS2304: Cannot find name 'CompilerErrorIsHere'. + +1 boom! > CompilerErrorIsHere; + ~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`const-enum 1`] = ` +"neg.const-enum.ts:1:1 - error TS9999: JSII: Exported enum cannot be declared 'const' + + 1 export const enum NotAllowed { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2 ThisEnum, + ~~~~~~~~~~~ +... + 5 ForJsii, + ~~~~~~~~~~ + 6 } + ~ +" +`; + +exports[`double-interface-members 1`] = ` +"neg.double-interface-members.ts:2:3 - error TS9999: JSII: The property 'foo' in data type 'A' must be 'readonly' since data is passed by-value + +2 foo: number; + ~~~~~~~~~~~~ +neg.double-interface-members.ts:4:1 - error TS9999: JSII: Interface declares same member as inherited interface: foo + +4 export interface B extends A { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +5 foo: number; + ~~~~~~~~~~~~~~ +6 } + ~ +neg.double-interface-members.ts:5:3 - error TS9999: JSII: The property 'foo' in data type 'B' must be 'readonly' since data is passed by-value + +5 foo: number; + ~~~~~~~~~~~~ +" +`; + +exports[`double-interface-members-deeper 1`] = ` +"neg.double-interface-members-deeper.ts:9:1 - error TS9999: JSII: Interface declares same member as inherited interface: foo + + 9 export interface IC extends IB { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +10 foo(): void; + ~~~~~~~~~~~~~~ +11 } + ~ +" +`; + +exports[`double-interface-members-method 1`] = ` +"neg.double-interface-members-method.ts:4:1 - error TS9999: JSII: Interface declares same member as inherited interface: foo + +4 export interface IB extends IA { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +5 foo(): void; + ~~~~~~~~~~~~~~ +6 } + ~ +" +`; + +exports[`downgrade-to-readonly 1`] = ` +"error TS0: jsii.Implementation#property changes immutability of property when implementing jsii.IInterface +" +`; + +exports[`enum-members.1 1`] = ` +"error TS0: Enum members must use ALL_CAPS: Goo +" +`; + +exports[`enum-name.1 1`] = ` +"error TS0: Type names must use PascalCase: myEnum +" +`; + +exports[`enum-name.2 1`] = ` +"error TS0: Type names must use PascalCase: My_Enum +" +`; + +exports[`expose-unexported-type-external 1`] = ` +"error TS0: Exported APIs cannot use un-exported type jsii.UnexportedType +" +`; + +exports[`expose-unexported-type-internal 1`] = ` +"neg.expose-unexported-type-internal.ts:7:10 - error TS9999: JSII: Type \\"UnexportedType\\" cannot be used as the property type because it is private or @internal + +7 public p?: UnexportedType; + ~ + + neg.expose-unexported-type-internal.ts:4:7 + 4 class UnexportedType {} + ~~~~~~~~~~~~~~ + The referenced type is declared here +" +`; + +exports[`expose-unexported-type-internal-in-namespace 1`] = ` +"neg.expose-unexported-type-internal-in-namespace.ts:9:10 - error TS9999: JSII: Cannot use internal type MyNamespace.UnexportedType as a property type in exported declarations + +9 public p?: MyNamespace.UnexportedType; + ~ + + neg.expose-unexported-type-internal-in-namespace.ts:5:16 + 5 export class UnexportedType {} + ~~~~~~~~~~~~~~ + The referenced type is declared here +" +`; + +exports[`expose-unexported-type-this 1`] = ` +"neg.expose-unexported-type-this.ts:10:38 - warning TS9999: JSII: 'boolean' is a reserved word in Java. Using this name may cause problems when generating language bindings. Consider using a different name. + +10 public constructor(public readonly boolean = true) { + ~~~~~~~ +neg.expose-unexported-type-this.ts:10:38 - warning TS9999: JSII: 'boolean' is a reserved word in Java. Using this name may cause problems when generating language bindings. Consider using a different name. + +10 public constructor(public readonly boolean = true) { + ~~~~~~~ +neg.expose-unexported-type-this.ts:4:10 - error TS9999: JSII: Type \\"this\\" (aka: \\"HiddenBaseClass\\") cannot be used as the return type because it is private or @internal + +4 public returnsThis() { + ~~~~~~~~~~~ + + neg.expose-unexported-type-this.ts:3:16 + 3 abstract class HiddenBaseClass { + ~~~~~~~~~~~~~~~ + The referenced type is declared here +" +`; + +exports[`extend-struct 1`] = ` +"error TS9999: JSII: Attempted to extend struct jsii.Struct from regular interface jsii.IIllegal +" +`; + +exports[`implement-struct 1`] = ` +"neg.implement-struct.ts:6:1 - error TS9999: JSII: Attempted to implement struct jsii.Struct from class jsii.Illegal + + 6 export class Illegal implements Struct { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 7 public readonly field: string = 'foo'; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... + 11 } + ~~~ + 12 } + ~ +" +`; + +exports[`implementation-changes-types.1 1`] = ` +"error TS0: jsii.Something#returnSomething changes the return type when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`implementation-changes-types.2 1`] = ` +"error TS0: jsii.ISomethingElse#returnSomething changes the return type when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`implementation-changes-types.3 1`] = ` +"error TS0: jsii.Something#takeSomething changes type of argument _argument when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass +" +`; + +exports[`implementation-changes-types.4 1`] = ` +"error TS0: jsii.Something#something changes the type of property when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`implementation-changes-types.5 1`] = ` +"error TS0: jsii.ISomethingElse#something changes the type of property when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`implementing-method-changes-optionality 1`] = ` +"error TS0: jsii.Implementor#method changes the optionality of paramerter _optional when implementing jsii.IInterface (expected true, found false) +" +`; + +exports[`implementing-method-changes-optionality.1 1`] = ` +"error TS0: jsii.Implementor#method changes the optionality of paramerter _optional when overriding jsii.AbstractClass (expected true, found false) +" +`; + +exports[`implementing-method-changes-optionality.2 1`] = ` +"error TS0: jsii.Implementor#method changes the optionality of paramerter _optional when overriding jsii.ParentClass (expected true, found false) +" +`; + +exports[`implementing-property-changes-optionality 1`] = ` +"error TS0: jsii.Implementor#property changes optionality of property when implementing jsii.IInterface +" +`; + +exports[`implementing-property-changes-optionality.1 1`] = ` +"error TS0: jsii.Implementor#property changes optionality of property when overriding jsii.AbstractClass +" +`; + +exports[`implementing-property-changes-optionality.2 1`] = ` +"error TS0: jsii.Implementor#property changes optionality of property when overriding jsii.ParentClass +" +`; + +exports[`implements-class 1`] = ` +"neg.implements-class.ts:1:1 - error TS9999: JSII: Inheritance clause of jsii.TryingToImplementClass uses jsii.NotAnInterface as an interface + + 1 export class NotAnInterface { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2 public meaningOfTheUniverse() { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... + 4 } + ~~~ + 5 } + ~ +" +`; + +exports[`inheritance-changes-types.1 1`] = ` +"error TS0: jsii.SomethingSpecific#returnSomething changes the return type when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`inheritance-changes-types.2 1`] = ` +"error TS0: jsii.SomethingSpecific#returnSomething changes the return type when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`inheritance-changes-types.3 1`] = ` +"error TS0: jsii.SomethingSpecific#takeSomething changes type of argument _argument when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass +" +`; + +exports[`inheritance-changes-types.4 1`] = ` +"error TS0: jsii.SomethingSpecific#something changes the type of property when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`inheritance-changes-types.5 1`] = ` +"error TS0: jsii.SomethingElse#something changes the type of property when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) +" +`; + +exports[`internal-underscore-class.5 1`] = ` +"neg.internal-underscore-class.5.ts:3:10 - error TS9999: JSII: propertyWithInternalButNotUnderscorePrefix: the name of members marked as @internal must begin with an underscore + +3 public propertyWithInternalButNotUnderscorePrefix?: string; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`internal-underscore-class.6 1`] = ` +"neg.internal-underscore-class.6.ts:2:10 - error TS9999: JSII: _propertyWithUnderscoreButNoInternal: members with names that begin with an underscore must be marked as @internal via a JSDoc tag + +2 public _propertyWithUnderscoreButNoInternal?: string; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`internal-underscore-class.7 1`] = ` +"neg.internal-underscore-class.7.ts:3:10 - error TS9999: JSII: methodWithInternalButNoUnderscore: the name of members marked as @internal must begin with an underscore + +3 public methodWithInternalButNoUnderscore(): string { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`internal-underscore-class.8 1`] = ` +"neg.internal-underscore-class.8.ts:2:3 - error TS9999: JSII: _methodWithUnderscoreButNoInternal: members with names that begin with an underscore must be marked as @internal via a JSDoc tag + +2 _methodWithUnderscoreButNoInternal(): void; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`internal-underscore-interface.1 1`] = ` +"neg.internal-underscore-interface.1.ts:3:3 - error TS9999: JSII: propertyWithInternalButNotUnderscorePrefix: the name of members marked as @internal must begin with an underscore + +3 propertyWithInternalButNotUnderscorePrefix: string; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`internal-underscore-interface.2 1`] = ` +"neg.internal-underscore-interface.2.ts:2:3 - error TS9999: JSII: _propertyWithUnderscoreButNoInternal: members with names that begin with an underscore must be marked as @internal via a JSDoc tag + +2 _propertyWithUnderscoreButNoInternal: string; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`internal-underscore-interface.3 1`] = ` +"neg.internal-underscore-interface.3.ts:3:3 - error TS9999: JSII: methodWithInternalButNoUnderscore: the name of members marked as @internal must begin with an underscore + +3 methodWithInternalButNoUnderscore(): string; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`internal-underscore-interface.4 1`] = ` +"neg.internal-underscore-interface.4.ts:2:10 - error TS9999: JSII: _methodWithUnderscoreButNoInternal: members with names that begin with an underscore must be marked as @internal via a JSDoc tag + +2 public _methodWithUnderscoreButNoInternal() { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`method-name.1 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: METHOD +" +`; + +exports[`method-name.2 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: hello_world +" +`; + +exports[`method-name.3 1`] = ` +"error TS0: Methods and properties cannot have names like getXxx() - those conflict with Java property getters by the same name +" +`; + +exports[`method-name.4 1`] = ` +"error TS0: Methods and properties cannot have names like setXxx() - those conflict with Java property setters by the same name +" +`; + +exports[`mix-datatype-and-arg-name 1`] = ` +"neg.mix-datatype-and-arg-name.ts:10:3 - error TS9999: JSII: Name occurs in both function arguments and in datatype properties, rename one: dontWorry + +10 public dance(dontWorry: string, lyrics: Lyrics) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +11 return \`\${dontWorry}: \${lyrics.beHappy}\`; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +12 } + ~~~ +" +`; + +exports[`mutable-datatype 1`] = ` +"neg.mutable-datatype.ts:3:3 - error TS9999: JSII: The property 'notOkay' in data type 'DataType' must be 'readonly' since data is passed by-value + +3 notOkay: number; // properties should be \\"readonly\\" + ~~~~~~~~~~~~~~~~ +" +`; + +exports[`non-optional-after-optional-ctor 1`] = ` +"neg.non-optional-after-optional-ctor.ts:2:3 - error TS9999: JSII: Parameter _arg2 cannot be optional, as it precedes non-optional parameter _arg3 + +2 constructor(_arg1: string, _arg2 = 'hello', _arg3: string) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +3 return; + ~~~~~~~~~~~ +4 } + ~~~ +" +`; + +exports[`non-optional-after-optional-method 1`] = ` +"neg.non-optional-after-optional-method.ts:2:3 - error TS9999: JSII: Parameter _arg2 cannot be optional, as it precedes non-optional parameter _argX + +2 public foo(_arg1: string, _arg2 = 'hello', _argX: string, _arg4?: boolean) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +3 return; + ~~~~~~~~~~~ +4 } + ~~~ +" +`; + +exports[`omit.1 1`] = ` +"neg.omit.1.ts:7:33 - error TS9999: JSII: Illegal \\"extends\\" value for an exported API: MappedType + +7 export interface BarBaz extends Omit { + ~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`omit.2 1`] = ` +"neg.omit.2.ts:7:32 - error TS9999: JSII: Illegal \\"implements\\" value for an exported API: MappedType + +7 export class BarBaz implements Omit { + ~~~~~~~~~~~~~~~~~~~ +" +`; + +exports[`omit.3 1`] = ` +"neg.omit.3.ts:8:3 - error TS9999: JSII: Only string-indexed map types are supported + +8 bar(): Omit; + ~~~ +" +`; + +exports[`omit.4 1`] = ` +"neg.omit.4.ts:8:7 - error TS9999: JSII: Only string-indexed map types are supported + +8 bar(opts: Omit): void; + ~~~~ +" +`; + +exports[`prohibited-member-name 1`] = ` +"neg.prohibited-member-name.ts:4:3 - error TS9999: JSII: Prohibited member name: equals + +4 public equals(): boolean { + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +5 return true; + ~~~~~~~~~~~~~~~~ +6 } + ~~~ +" +`; + +exports[`property-name.1 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: PROP +" +`; + +exports[`property-name.2 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: my_Prop +" +`; + +exports[`property-name.3 1`] = ` +"error TS0: Methods and properties cannot have names like getXxx() - those conflict with Java property getters by the same name +" +`; + +exports[`reserved.emits-warning 1`] = ` +"neg.reserved.emits-warning.ts:2:14 - warning TS9999: JSII: 'None' is a reserved word in Python. Using this name may cause problems when generating language bindings. Consider using a different name. + +2 export class None { + ~~~~ +neg.reserved.emits-warning.ts:3:19 - warning TS9999: JSII: 'do' is a reserved word in C#, Java. Using this name may cause problems when generating language bindings. Consider using a different name. + +3 public readonly do: boolean = true; + ~~ +neg.reserved.emits-warning.ts:5:10 - warning TS9999: JSII: 'assert' is a reserved word in Java, Python. Using this name may cause problems when generating language bindings. Consider using a different name. + +5 public assert(_internal: boolean): void { + ~~~~~~ +" +`; + +exports[`static-const-name 1`] = ` +"error TS0: Static constant names must use TRUMP_CASE, PascalCase or camelCase: snake_case +" +`; + +exports[`static-member-mixing.1 1`] = ` +"neg.static-member-mixing.1.ts:11:1 - error TS9999: JSII: non-static member 'funFunction' of class 'Sub' conflicts with static member in ancestor 'SuperDuper' + + 11 export class Sub extends Super { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 12 public funFunction() { + ~~~~~~~~~~~~~~~~~~~~~~~~ +... + 14 } + ~~~ + 15 } + ~ +" +`; + +exports[`static-member-mixing.2 1`] = ` +"neg.static-member-mixing.2.ts:1:1 - error TS9999: JSII: member 'funFunction' of class 'TheClass' cannot be declared both statically and non-statically + + 1 export class TheClass { + ~~~~~~~~~~~~~~~~~~~~~~~ + 2 public static funFunction() { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... + 8 } + ~~~ + 9 } + ~ +" +`; + +exports[`static-method-name 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: METHOD +" +`; + +exports[`static-method-name.1 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: MethodIsNotCamelCase +" +`; + +exports[`static-prop-name.1 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: Prop +" +`; + +exports[`static-prop-name.2 1`] = ` +"error TS0: Method and non-static non-readonly property names must use camelCase: PROP +" +`; + +exports[`struct-extends-interface 1`] = ` +"neg.struct-extends-interface.ts:6:18 - error TS9999: JSII: Interface contains behavior: name should be \\"IStruct\\" + +6 export interface Struct extends IInterface { + ~~~~~~ +" +`; + +exports[`submodules-cannot-have-colliding-names 1`] = ` +"neg.submodules-cannot-have-colliding-names.ts:3:14 - error TS9999: JSII: Submodule \\"ns1\\" conflicts with \\"Ns1\\". Restricted names are: ns1, Ns1 + +3 export class Ns1 { + ~~~ + + neg.submodules-cannot-have-colliding-names.ts:1:13 + 1 export * as ns1 from './namespaced'; + ~~~ + This is the conflicting submodule declaration. +" +`; + +exports[`submodules-cannot-share-symbols 1`] = ` +"namespaced/index.ts:1:14 - error TS9999: JSII: Symbol is re-exported under two distinct submodules (ns1 and ns2) + +1 export class Declaration { + ~~~~~~~~~~~ + + neg.submodules-cannot-share-symbols.ts:1:8 + 1 export * as ns1 from './namespaced'; + ~~~~~~~~ + Symbol is exported under the \\"ns1\\" submodule + neg.submodules-cannot-share-symbols.ts:2:8 + 2 export * as ns2 from './namespaced'; + ~~~~~~~~ + Symbol is exported under the \\"ns2\\" submodule +" +`; + +exports[`submodules-must-be-camel-cased 1`] = ` +"neg.submodules-must-be-camel-cased.ts:1:13 - error TS9999: JSII: Submodule namespaces must be camelCased or snake_cased. Consider renaming to \\"ns1\\". + +1 export * as Ns1 from './namespaced'; + ~~~ +" +`; diff --git a/packages/jsii/test/negatives.test.ts b/packages/jsii/test/negatives.test.ts index 50d98f3442..a370b78e78 100644 --- a/packages/jsii/test/negatives.test.ts +++ b/packages/jsii/test/negatives.test.ts @@ -6,6 +6,12 @@ import { ProjectInfo } from '../lib/project-info'; const SOURCE_DIR = path.join(__dirname, 'negatives'); +const formatHost: ts.FormatDiagnosticsHost = { + getCanonicalFileName: ts.sys.realpath ?? ts.sys.resolvePath, + getCurrentDirectory: () => SOURCE_DIR, + getNewLine: () => '\n', +}; + for (const source of fs.readdirSync(SOURCE_DIR)) { if ( !source.startsWith('neg.') || @@ -18,30 +24,33 @@ for (const source of fs.readdirSync(SOURCE_DIR)) { test( source.replace(/neg\.(.+)\.ts/, '$1'), async () => { - const [expectations, strict] = await _getExpectedErrorMessage(filePath); - expect( - expectations.length, - `Expected error messages should be specified using ${MATCH_ERROR_MARKER}`, - ).toBeGreaterThan(0); + const { strict } = await _getPragmas(filePath); const compiler = new Compiler({ projectInfo: _makeProjectInfo(source), failOnWarnings: strict, }); const emitResult = await compiler.emit(path.join(SOURCE_DIR, source)); + expect(emitResult.emitSkipped).toBeTruthy(); - const errors = emitResult.diagnostics.filter( - (diag) => - diag.category === ts.DiagnosticCategory.Error || - (strict && diag.category === ts.DiagnosticCategory.Warning), - ); - for (const expectation of expectations) { - expect( - errors.find((e) => _messageText(e).includes(expectation)), - `No error contained: ${expectation}. Errors: \n${errors - .map((e, i) => `[${i}] ${e.messageText.toString()}`) - .join('\n')}`, - ).toBeDefined(); - } + + const diagnostics = emitResult.diagnostics + .filter( + // Remove suggestion diagnostics, we don't care much for those for now... + (diag) => diag.category !== ts.DiagnosticCategory.Suggestion, + ) + .map((diag) => + ts.formatDiagnosticsWithColorAndContext([diag], formatHost), + ) + .sort(); + + expect(diagnostics.length).toBeGreaterThan(0); + expect( + diagnostics + // Remove ANSI color codes from the message so it's nicer in the snapshots file + // eslint-disable-next-line no-control-regex + .map((diag) => diag.replace(/\x1B\[[0-9;]*[a-z]/gi, '')) + .join(''), + ).toMatchSnapshot(); // Cleaning up... return Promise.all( @@ -65,32 +74,12 @@ for (const source of fs.readdirSync(SOURCE_DIR)) { ); } -const MATCH_ERROR_MARKER = '///!MATCH_ERROR:'; const STRICT_MARKER = '///!STRICT!'; -async function _getExpectedErrorMessage( - file: string, -): Promise<[string[], boolean]> { +async function _getPragmas(file: string): Promise<{ strict: boolean }> { const data = await fs.readFile(file, { encoding: 'utf8' }); const lines = data.split('\n'); - const matches = lines - .filter((line) => line.startsWith(MATCH_ERROR_MARKER)) - .map((line) => line.substr(MATCH_ERROR_MARKER.length).trim()); const strict = lines.some((line) => line.startsWith(STRICT_MARKER)); - return [matches, strict]; -} - -function _messageText( - diagnostic: ts.Diagnostic | ts.DiagnosticMessageChain, -): string { - if (typeof diagnostic.messageText === 'string') { - return diagnostic.messageText; - } - if (diagnostic.messageText.next) { - return `${diagnostic.messageText.messageText}|${_messageText( - diagnostic.messageText.next[0], - )}`; - } - return diagnostic.messageText.messageText; + return { strict }; } function _makeProjectInfo(types: string): ProjectInfo { diff --git a/packages/jsii/test/negatives/neg.behavior-requires-iprefix.ts b/packages/jsii/test/negatives/neg.behavior-requires-iprefix.ts index 031db1b155..faaa251d7b 100644 --- a/packages/jsii/test/negatives/neg.behavior-requires-iprefix.ts +++ b/packages/jsii/test/negatives/neg.behavior-requires-iprefix.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Interface contains behavior: name should be "ISomething" - export interface Something { // The presence of this method requires an I prefix on the interface doSomething(): void; diff --git a/packages/jsii/test/negatives/neg.class-name.1.ts b/packages/jsii/test/negatives/neg.class-name.1.ts index b22415587a..692f1c0dc5 100644 --- a/packages/jsii/test/negatives/neg.class-name.1.ts +++ b/packages/jsii/test/negatives/neg.class-name.1.ts @@ -1,5 +1 @@ -///!MATCH_ERROR: Type names must use PascalCase: My_class - -export class My_class { - -} +export class My_class {} diff --git a/packages/jsii/test/negatives/neg.class-name.ts b/packages/jsii/test/negatives/neg.class-name.ts index 8f43e7ef2f..8b09276b97 100644 --- a/packages/jsii/test/negatives/neg.class-name.ts +++ b/packages/jsii/test/negatives/neg.class-name.ts @@ -1,5 +1 @@ -///!MATCH_ERROR: Type names must use PascalCase: myclass - -export class myclass { - -} +export class myclass {} diff --git a/packages/jsii/test/negatives/neg.compilation-error.ts b/packages/jsii/test/negatives/neg.compilation-error.ts index fd5f792fb2..b60962138a 100644 --- a/packages/jsii/test/negatives/neg.compilation-error.ts +++ b/packages/jsii/test/negatives/neg.compilation-error.ts @@ -1,4 +1 @@ -///!MATCH_ERROR: Cannot find name 'boom'. -///!MATCH_ERROR: Cannot find name 'CompilerErrorIsHere'. - -boom! >CompilerErrorIsHere +boom! > CompilerErrorIsHere; diff --git a/packages/jsii/test/negatives/neg.const-enum.ts b/packages/jsii/test/negatives/neg.const-enum.ts index bc3a792ba4..c1137e7ae5 100644 --- a/packages/jsii/test/negatives/neg.const-enum.ts +++ b/packages/jsii/test/negatives/neg.const-enum.ts @@ -1,8 +1,6 @@ -///!MATCH_ERROR: Exported enum cannot be declared 'const' - export const enum NotAllowed { ThisEnum, GetsInlined, AndSoItGetsLost, - ForJsii -} \ No newline at end of file + ForJsii, +} diff --git a/packages/jsii/test/negatives/neg.double-interface-members-deeper.ts b/packages/jsii/test/negatives/neg.double-interface-members-deeper.ts index bfebb2015f..7190be0a71 100644 --- a/packages/jsii/test/negatives/neg.double-interface-members-deeper.ts +++ b/packages/jsii/test/negatives/neg.double-interface-members-deeper.ts @@ -1,15 +1,11 @@ -///!MATCH_ERROR: Interface declares same member as inherited interface: foo - export interface IA { foo(): void; } export interface IB extends IA { - bar(): void; + bar(): void; } export interface IC extends IB { foo(): void; } - - diff --git a/packages/jsii/test/negatives/neg.double-interface-members-method.ts b/packages/jsii/test/negatives/neg.double-interface-members-method.ts index 2d0dee3c44..90b33cc817 100644 --- a/packages/jsii/test/negatives/neg.double-interface-members-method.ts +++ b/packages/jsii/test/negatives/neg.double-interface-members-method.ts @@ -1,9 +1,6 @@ -///!MATCH_ERROR: Interface declares same member as inherited interface: foo - export interface IA { foo(): void; } export interface IB extends IA { foo(): void; } - diff --git a/packages/jsii/test/negatives/neg.double-interface-members.ts b/packages/jsii/test/negatives/neg.double-interface-members.ts index d15eedaabb..6862bded37 100644 --- a/packages/jsii/test/negatives/neg.double-interface-members.ts +++ b/packages/jsii/test/negatives/neg.double-interface-members.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Interface declares same member as inherited interface: foo - export interface A { foo: number; } diff --git a/packages/jsii/test/negatives/neg.enum-members.1.ts b/packages/jsii/test/negatives/neg.enum-members.1.ts index 5e3eae81a0..c303f93d8b 100644 --- a/packages/jsii/test/negatives/neg.enum-members.1.ts +++ b/packages/jsii/test/negatives/neg.enum-members.1.ts @@ -1,6 +1,4 @@ -///!MATCH_ERROR: Enum members must use ALL_CAPS: Goo - export enum MyEnum { - FOO, - Goo + FOO, + Goo, } diff --git a/packages/jsii/test/negatives/neg.enum-name.1.ts b/packages/jsii/test/negatives/neg.enum-name.1.ts index 6b7732ee76..4fb81db58f 100644 --- a/packages/jsii/test/negatives/neg.enum-name.1.ts +++ b/packages/jsii/test/negatives/neg.enum-name.1.ts @@ -1,6 +1,4 @@ -///!MATCH_ERROR: Type names must use PascalCase: myEnum - export enum myEnum { - FOO, - GOO + FOO, + GOO, } diff --git a/packages/jsii/test/negatives/neg.enum-name.2.ts b/packages/jsii/test/negatives/neg.enum-name.2.ts index 096cf4b267..e6ac3be88b 100644 --- a/packages/jsii/test/negatives/neg.enum-name.2.ts +++ b/packages/jsii/test/negatives/neg.enum-name.2.ts @@ -1,6 +1,4 @@ -///!MATCH_ERROR: Type names must use PascalCase: My_Enum - export enum My_Enum { - FOO, - GOO + FOO, + GOO, } diff --git a/packages/jsii/test/negatives/neg.expose-unexported-type-external.ts b/packages/jsii/test/negatives/neg.expose-unexported-type-external.ts index 00da931f53..6187a30c64 100644 --- a/packages/jsii/test/negatives/neg.expose-unexported-type-external.ts +++ b/packages/jsii/test/negatives/neg.expose-unexported-type-external.ts @@ -1,10 +1,8 @@ -///!MATCH_ERROR: Exported APIs cannot use un-exported type jsii.UnexportedType - // Attempt to expose an unexported type defined in another file should fial // because that type will not be available in the module spec. import { UnexportedType } from './mylib'; export class ExportedType { - public p?: UnexportedType; + public p?: UnexportedType; } diff --git a/packages/jsii/test/negatives/neg.expose-unexported-type-internal-in-namespace.ts b/packages/jsii/test/negatives/neg.expose-unexported-type-internal-in-namespace.ts index 4f35f327d7..825ee4268b 100644 --- a/packages/jsii/test/negatives/neg.expose-unexported-type-internal-in-namespace.ts +++ b/packages/jsii/test/negatives/neg.expose-unexported-type-internal-in-namespace.ts @@ -1,13 +1,10 @@ -///!MATCH_ERROR: Cannot use private type MyNamespace.UnexportedType in exported declarations - // Attempt to expose an unexported type defined in this file should fail // because that type will not be available in the module spec. namespace MyNamespace { - export class UnexportedType { - } + export class UnexportedType {} } export class ExportedType { - public p?: MyNamespace.UnexportedType; + public p?: MyNamespace.UnexportedType; } diff --git a/packages/jsii/test/negatives/neg.expose-unexported-type-internal.ts b/packages/jsii/test/negatives/neg.expose-unexported-type-internal.ts index eadab9e429..57270a153f 100644 --- a/packages/jsii/test/negatives/neg.expose-unexported-type-internal.ts +++ b/packages/jsii/test/negatives/neg.expose-unexported-type-internal.ts @@ -1,12 +1,8 @@ -///!MATCH_ERROR: Cannot use private type UnexportedType in exported declarations - // Attempt to expose an unexported type defined in this file should fail // because that type will not be available in the module spec. -class UnexportedType { - -} +class UnexportedType {} export class ExportedType { - public p?: UnexportedType; + public p?: UnexportedType; } diff --git a/packages/jsii/test/negatives/neg.expose-unexported-type-this.ts b/packages/jsii/test/negatives/neg.expose-unexported-type-this.ts new file mode 100644 index 0000000000..84cbd5db4f --- /dev/null +++ b/packages/jsii/test/negatives/neg.expose-unexported-type-this.ts @@ -0,0 +1,13 @@ +// Attempt to return "this" from a hidden base class + +abstract class HiddenBaseClass { + public returnsThis() { + return this; + } +} + +export class PublicClass extends HiddenBaseClass { + public constructor(public readonly boolean = true) { + super(); + } +} diff --git a/packages/jsii/test/negatives/neg.extend-struct.ts b/packages/jsii/test/negatives/neg.extend-struct.ts index 0dcb43b9a0..6c307ddcea 100644 --- a/packages/jsii/test/negatives/neg.extend-struct.ts +++ b/packages/jsii/test/negatives/neg.extend-struct.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Attempted to extend struct jsii.Struct from regular interface jsii.IIllegal - // Attempt to extend a Struct (aka data type) from a regular interface will fail. export interface Struct { readonly field: string; diff --git a/packages/jsii/test/negatives/neg.implement-struct.ts b/packages/jsii/test/negatives/neg.implement-struct.ts index 7276beca8c..f50b71174c 100644 --- a/packages/jsii/test/negatives/neg.implement-struct.ts +++ b/packages/jsii/test/negatives/neg.implement-struct.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Attempted to implement struct jsii.Struct from class jsii.Illegal - // Attempt to implement a Struct (aka data type) will fail. export interface Struct { readonly field: string; diff --git a/packages/jsii/test/negatives/neg.implementation-changes-types.1.ts b/packages/jsii/test/negatives/neg.implementation-changes-types.1.ts index 08bb19794f..65b5fe96b1 100644 --- a/packages/jsii/test/negatives/neg.implementation-changes-types.1.ts +++ b/packages/jsii/test/negatives/neg.implementation-changes-types.1.ts @@ -1,14 +1,12 @@ -///!MATCH_ERROR: jsii.Something#returnSomething changes the return type when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export interface ISomething { - returnSomething(): Superclass; + returnSomething(): Superclass; } export class Something implements ISomething { - public returnSomething(): Subclass { - return 5; - } + public returnSomething(): Subclass { + return 5; + } } diff --git a/packages/jsii/test/negatives/neg.implementation-changes-types.2.ts b/packages/jsii/test/negatives/neg.implementation-changes-types.2.ts index eb82aaa4bc..947e53dddd 100644 --- a/packages/jsii/test/negatives/neg.implementation-changes-types.2.ts +++ b/packages/jsii/test/negatives/neg.implementation-changes-types.2.ts @@ -1,14 +1,12 @@ -///!MATCH_ERROR: jsii.ISomethingElse#returnSomething changes the return type when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export interface ISomething { - returnSomething(): Superclass; + returnSomething(): Superclass; } export class ISomethingElse implements ISomething { - public returnSomething(): Subclass { - return new Subclass(); - } + public returnSomething(): Subclass { + return new Subclass(); + } } diff --git a/packages/jsii/test/negatives/neg.implementation-changes-types.3.ts b/packages/jsii/test/negatives/neg.implementation-changes-types.3.ts index 5902488f74..ab1e2dd32d 100644 --- a/packages/jsii/test/negatives/neg.implementation-changes-types.3.ts +++ b/packages/jsii/test/negatives/neg.implementation-changes-types.3.ts @@ -1,14 +1,12 @@ -///!MATCH_ERROR: jsii.Something#takeSomething changes type of argument _argument when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass - export class Superclass {} export class Subclass extends Superclass {} export interface ISomething { - takeSomething(argument: Superclass): void; + takeSomething(argument: Superclass): void; } export class Something implements ISomething { - public takeSomething(_argument: Subclass): void { - // Nothing - } + public takeSomething(_argument: Subclass): void { + // Nothing + } } diff --git a/packages/jsii/test/negatives/neg.implementation-changes-types.4.ts b/packages/jsii/test/negatives/neg.implementation-changes-types.4.ts index 6e1b25470f..0d3c9ad79e 100644 --- a/packages/jsii/test/negatives/neg.implementation-changes-types.4.ts +++ b/packages/jsii/test/negatives/neg.implementation-changes-types.4.ts @@ -1,12 +1,10 @@ -///!MATCH_ERROR: jsii.Something#something changes the type of property when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export interface ISomething { - something: Superclass; + something: Superclass; } export class Something implements ISomething { - public something: Subclass = new Subclass(); + public something: Subclass = new Subclass(); } diff --git a/packages/jsii/test/negatives/neg.implementation-changes-types.5.ts b/packages/jsii/test/negatives/neg.implementation-changes-types.5.ts index bd249d7c77..395d364a9b 100644 --- a/packages/jsii/test/negatives/neg.implementation-changes-types.5.ts +++ b/packages/jsii/test/negatives/neg.implementation-changes-types.5.ts @@ -1,18 +1,16 @@ -///!MATCH_ERROR: jsii.ISomethingElse#something changes the type of property when implementing jsii.ISomething (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export interface ISomething { - something: Superclass; + something: Superclass; } export interface ISomethingElse extends ISomething { - addUnrelatedMember: number; + addUnrelatedMember: number; } // Should still fail even though 2-level inheritance export class Something implements ISomethingElse { - public something: Subclass = new Subclass(); - public addUnrelatedMember: number = 1; + public something: Subclass = new Subclass(); + public addUnrelatedMember: number = 1; } diff --git a/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.1.ts b/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.1.ts index 074f252d80..8371bf6a10 100644 --- a/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.1.ts +++ b/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.1.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: jsii.Implementor#method changes the optionality of paramerter _optional when overriding jsii.AbstractClass (expected true, found false) - // Attempt to change optionality of method parameter export abstract class AbstractClass { public abstract method(required: string, optional?: number): void; diff --git a/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.2.ts b/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.2.ts index 339e2af13a..7e756b2926 100644 --- a/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.2.ts +++ b/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.2.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: jsii.Implementor#method changes the optionality of paramerter _optional when overriding jsii.ParentClass (expected true, found false) - // Attempt to change optionality of method parameter export class ParentClass { public method(_required: string, _optional?: number): void { diff --git a/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.ts b/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.ts index a74446855f..ce03d1a737 100644 --- a/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.ts +++ b/packages/jsii/test/negatives/neg.implementing-method-changes-optionality.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: jsii.Implementor#method changes the optionality of paramerter _optional when implementing jsii.IInterface (expected true, found false) - // Attempt to change optionality of method parameter export interface IInterface { method(required: string, optional?: number): void; diff --git a/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.1.ts b/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.1.ts index 2ec19a1b65..7e599c7409 100644 --- a/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.1.ts +++ b/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.1.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: jsii.Implementor#property changes optionality of property when overriding jsii.AbstractClass - // Attempt to change optionality of method parameter export abstract class AbstractClass { public abstract property?: string; diff --git a/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.2.ts b/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.2.ts index 6ff5c4ec36..6610056884 100644 --- a/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.2.ts +++ b/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.2.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: jsii.Implementor#property changes optionality of property when overriding jsii.ParentClass - // Attempt to change optionality of method parameter export class ParentClass { public property?: string = undefined; diff --git a/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.ts b/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.ts index 469ab2cd69..20c04d7370 100644 --- a/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.ts +++ b/packages/jsii/test/negatives/neg.implementing-property-changes-optionality.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: jsii.Implementor#property changes optionality of property when implementing jsii.IInterface - // Attempt to change optionality of method parameter export interface IInterface { property?: string; diff --git a/packages/jsii/test/negatives/neg.implements-class.ts b/packages/jsii/test/negatives/neg.implements-class.ts index 225708a81b..ca6ce620b6 100644 --- a/packages/jsii/test/negatives/neg.implements-class.ts +++ b/packages/jsii/test/negatives/neg.implements-class.ts @@ -1,14 +1,12 @@ -///!MATCH_ERROR: Inheritance clause of jsii.TryingToImplementClass uses jsii.NotAnInterface as an interface - export class NotAnInterface { - public meaningOfTheUniverse() { - return 42; - } + public meaningOfTheUniverse() { + return 42; + } } // While valid typescript, this is illegal in the vast majority of languages export class TryingToImplementClass implements NotAnInterface { - public meaningOfTheUniverse() { - return 1337; - } + public meaningOfTheUniverse() { + return 1337; + } } diff --git a/packages/jsii/test/negatives/neg.inheritance-changes-types.1.ts b/packages/jsii/test/negatives/neg.inheritance-changes-types.1.ts index 87e6757ed2..34e4c438b2 100644 --- a/packages/jsii/test/negatives/neg.inheritance-changes-types.1.ts +++ b/packages/jsii/test/negatives/neg.inheritance-changes-types.1.ts @@ -1,16 +1,14 @@ -///!MATCH_ERROR: jsii.SomethingSpecific#returnSomething changes the return type when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export class Something { - public returnSomething(): Superclass { - return new Superclass(); - } + public returnSomething(): Superclass { + return new Superclass(); + } } export class SomethingSpecific extends Something { - public returnSomething(): Subclass { - return 5; - } + public returnSomething(): Subclass { + return 5; + } } diff --git a/packages/jsii/test/negatives/neg.inheritance-changes-types.2.ts b/packages/jsii/test/negatives/neg.inheritance-changes-types.2.ts index 94ad417df5..5c8cc2660d 100644 --- a/packages/jsii/test/negatives/neg.inheritance-changes-types.2.ts +++ b/packages/jsii/test/negatives/neg.inheritance-changes-types.2.ts @@ -1,16 +1,14 @@ -///!MATCH_ERROR: jsii.SomethingSpecific#returnSomething changes the return type when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export class Something { - public returnSomething(): Superclass { - return new Superclass(); - } + public returnSomething(): Superclass { + return new Superclass(); + } } export class SomethingSpecific extends Something { - public returnSomething(): Subclass { - return new Subclass(); - } + public returnSomething(): Subclass { + return new Subclass(); + } } diff --git a/packages/jsii/test/negatives/neg.inheritance-changes-types.3.ts b/packages/jsii/test/negatives/neg.inheritance-changes-types.3.ts index c03ef34ae7..49168b1266 100644 --- a/packages/jsii/test/negatives/neg.inheritance-changes-types.3.ts +++ b/packages/jsii/test/negatives/neg.inheritance-changes-types.3.ts @@ -1,16 +1,14 @@ -///!MATCH_ERROR: jsii.SomethingSpecific#takeSomething changes type of argument _argument when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass - export class Superclass {} export class Subclass extends Superclass {} export class Something { - public takeSomething(_argument: Superclass): void { - // Nothing - } + public takeSomething(_argument: Superclass): void { + // Nothing + } } export class SomethingSpecific extends Something { - public takeSomething(_argument: Subclass): void { - // Nothing - } + public takeSomething(_argument: Subclass): void { + // Nothing + } } diff --git a/packages/jsii/test/negatives/neg.inheritance-changes-types.4.ts b/packages/jsii/test/negatives/neg.inheritance-changes-types.4.ts index 0fa29aa081..ecad08428a 100644 --- a/packages/jsii/test/negatives/neg.inheritance-changes-types.4.ts +++ b/packages/jsii/test/negatives/neg.inheritance-changes-types.4.ts @@ -1,12 +1,10 @@ -///!MATCH_ERROR: jsii.SomethingSpecific#something changes the type of property when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export class Something { - public something: Superclass; + public something = new Superclass(); } export class SomethingSpecific extends Something { - public something: Subclass = new Subclass(); + public something: Subclass = new Subclass(); } diff --git a/packages/jsii/test/negatives/neg.inheritance-changes-types.5.ts b/packages/jsii/test/negatives/neg.inheritance-changes-types.5.ts index 5b55e4d00a..2ace670740 100644 --- a/packages/jsii/test/negatives/neg.inheritance-changes-types.5.ts +++ b/packages/jsii/test/negatives/neg.inheritance-changes-types.5.ts @@ -1,18 +1,16 @@ -///!MATCH_ERROR: jsii.SomethingElse#something changes the type of property when overriding jsii.Something (expected jsii.Superclass, found jsii.Subclass) - export class Superclass {} export class Subclass extends Superclass {} export class Something { - public something: Superclass; + public something: Superclass = new Superclass(); } export class SomethingElse extends Something { - public addUnrelatedMember: number; + public addUnrelatedMember: number = 3; } // Should still fail even though 2-level inheritance export class SomethingDifferent extends SomethingElse { - public something: Subclass = new Subclass(); - public addUnrelatedMember: number = 1; + public something: Subclass = new Subclass(); + public addUnrelatedMember: number = 1; } diff --git a/packages/jsii/test/negatives/neg.internal-underscore-class.5.ts b/packages/jsii/test/negatives/neg.internal-underscore-class.5.ts index f6e220556c..9524f29799 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-class.5.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-class.5.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: the name of members marked as @internal must begin with an underscore - export class MyClass { /** @internal */ public propertyWithInternalButNotUnderscorePrefix?: string; diff --git a/packages/jsii/test/negatives/neg.internal-underscore-class.6.ts b/packages/jsii/test/negatives/neg.internal-underscore-class.6.ts index 0f96a89f5e..3b59e3922a 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-class.6.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-class.6.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: members with names that begin with an underscore must be marked as @internal via a JSDoc tag - export class MyClass { public _propertyWithUnderscoreButNoInternal?: string; } diff --git a/packages/jsii/test/negatives/neg.internal-underscore-class.7.ts b/packages/jsii/test/negatives/neg.internal-underscore-class.7.ts index 43f4ecb8eb..a92955307b 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-class.7.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-class.7.ts @@ -1,6 +1,6 @@ -///!MATCH_ERROR: the name of members marked as @internal must begin with an underscore - export class MyClass { /** @internal */ - public methodWithInternalButNoUnderscore(): string { return 'hi'; } + public methodWithInternalButNoUnderscore(): string { + return 'hi'; + } } diff --git a/packages/jsii/test/negatives/neg.internal-underscore-class.8.ts b/packages/jsii/test/negatives/neg.internal-underscore-class.8.ts index e7b5afd433..4582d4b585 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-class.8.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-class.8.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: members with names that begin with an underscore must be marked as @internal via a JSDoc tag - export interface IMyInterface { - _methodWithUnderscoreButNoInternal(); + _methodWithUnderscoreButNoInternal(): void; } diff --git a/packages/jsii/test/negatives/neg.internal-underscore-interface.1.ts b/packages/jsii/test/negatives/neg.internal-underscore-interface.1.ts index 9edd58ae90..aaa6036003 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-interface.1.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-interface.1.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: the name of members marked as @internal must begin with an underscore - export interface IMyInterface { /** @internal */ propertyWithInternalButNotUnderscorePrefix: string; diff --git a/packages/jsii/test/negatives/neg.internal-underscore-interface.2.ts b/packages/jsii/test/negatives/neg.internal-underscore-interface.2.ts index f025d1d9b1..792a0c4e64 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-interface.2.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-interface.2.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: members with names that begin with an underscore must be marked as @internal via a JSDoc tag - export interface IMyInterface { _propertyWithUnderscoreButNoInternal: string; } diff --git a/packages/jsii/test/negatives/neg.internal-underscore-interface.3.ts b/packages/jsii/test/negatives/neg.internal-underscore-interface.3.ts index 62a744501c..2ec5c13221 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-interface.3.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-interface.3.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: the name of members marked as @internal must begin with an underscore - export interface IMyInterface { /** @internal */ methodWithInternalButNoUnderscore(): string; diff --git a/packages/jsii/test/negatives/neg.internal-underscore-interface.4.ts b/packages/jsii/test/negatives/neg.internal-underscore-interface.4.ts index 8d33518242..cef0748026 100644 --- a/packages/jsii/test/negatives/neg.internal-underscore-interface.4.ts +++ b/packages/jsii/test/negatives/neg.internal-underscore-interface.4.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: members with names that begin with an underscore must be marked as @internal via a JSDoc tag - export class MyClass { public _methodWithUnderscoreButNoInternal() { return; diff --git a/packages/jsii/test/negatives/neg.method-name.1.ts b/packages/jsii/test/negatives/neg.method-name.1.ts index 904d6afed6..ac2a4b1e8e 100644 --- a/packages/jsii/test/negatives/neg.method-name.1.ts +++ b/packages/jsii/test/negatives/neg.method-name.1.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: METHOD - export class MyClass { - public METHOD() { - return "hi"; - } + public METHOD() { + return 'hi'; + } } diff --git a/packages/jsii/test/negatives/neg.method-name.2.ts b/packages/jsii/test/negatives/neg.method-name.2.ts index 1afff6517d..ed97c29bdd 100644 --- a/packages/jsii/test/negatives/neg.method-name.2.ts +++ b/packages/jsii/test/negatives/neg.method-name.2.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: hello_world - export class MyClass { - public hello_world() { - return "hi"; - } + public hello_world() { + return 'hi'; + } } diff --git a/packages/jsii/test/negatives/neg.method-name.3.ts b/packages/jsii/test/negatives/neg.method-name.3.ts index 280f233b81..2bfcee43f6 100644 --- a/packages/jsii/test/negatives/neg.method-name.3.ts +++ b/packages/jsii/test/negatives/neg.method-name.3.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Methods and properties cannot have names like getXxx() - those conflict with Java property getters by the same name - export class MyClass { - public getFoo() { - return "hi"; - } + public getFoo() { + return 'hi'; + } } diff --git a/packages/jsii/test/negatives/neg.method-name.4.ts b/packages/jsii/test/negatives/neg.method-name.4.ts index b0334729fc..7135900a04 100644 --- a/packages/jsii/test/negatives/neg.method-name.4.ts +++ b/packages/jsii/test/negatives/neg.method-name.4.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Methods and properties cannot have names like setXxx() - those conflict with Java property setters by the same name - export class MyClass { - public setFoo(_value: string) { - return "hi"; - } + public setFoo(_value: string) { + return 'hi'; + } } diff --git a/packages/jsii/test/negatives/neg.mix-datatype-and-arg-name.ts b/packages/jsii/test/negatives/neg.mix-datatype-and-arg-name.ts index 243ebd5a69..ed35dc8269 100644 --- a/packages/jsii/test/negatives/neg.mix-datatype-and-arg-name.ts +++ b/packages/jsii/test/negatives/neg.mix-datatype-and-arg-name.ts @@ -1,8 +1,6 @@ -///!MATCH_ERROR: Name occurs in both function arguments and in datatype properties, rename one: dontWorry - export interface Lyrics { - dontWorry: string; - beHappy: string; + readonly dontWorry: string; + readonly beHappy: string; } export class MyClass { @@ -12,4 +10,4 @@ export class MyClass { public dance(dontWorry: string, lyrics: Lyrics) { return `${dontWorry}: ${lyrics.beHappy}`; } -} \ No newline at end of file +} diff --git a/packages/jsii/test/negatives/neg.mutable-datatype.ts b/packages/jsii/test/negatives/neg.mutable-datatype.ts index 58bdb689f9..17e7a9b227 100644 --- a/packages/jsii/test/negatives/neg.mutable-datatype.ts +++ b/packages/jsii/test/negatives/neg.mutable-datatype.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: The property 'notOkay' in data type 'DataType' must be 'readonly' since data is passed by-value - export interface DataType { readonly okay: string; notOkay: number; // properties should be "readonly" diff --git a/packages/jsii/test/negatives/neg.non-optional-after-optional-ctor.ts b/packages/jsii/test/negatives/neg.non-optional-after-optional-ctor.ts index bb320ef620..8bcd05c7f6 100644 --- a/packages/jsii/test/negatives/neg.non-optional-after-optional-ctor.ts +++ b/packages/jsii/test/negatives/neg.non-optional-after-optional-ctor.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Parameter _arg2 cannot be optional, as it precedes non-optional parameter _arg3 - export class NonOptionalAfterOptional { - constructor(_arg1: string, _arg2 = 'hello', _arg3: string) { - return; - } + constructor(_arg1: string, _arg2 = 'hello', _arg3: string) { + return; + } } diff --git a/packages/jsii/test/negatives/neg.non-optional-after-optional-method.ts b/packages/jsii/test/negatives/neg.non-optional-after-optional-method.ts index 25e8f0bb7d..222a1370e5 100644 --- a/packages/jsii/test/negatives/neg.non-optional-after-optional-method.ts +++ b/packages/jsii/test/negatives/neg.non-optional-after-optional-method.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Parameter _arg2 cannot be optional, as it precedes non-optional parameter _argX - export class NonOptionalAfterOptional { - public foo(_arg1: string, _arg2 = 'hello', _argX: string, _arg4?: boolean) { - return; - } + public foo(_arg1: string, _arg2 = 'hello', _argX: string, _arg4?: boolean) { + return; + } } diff --git a/packages/jsii/test/negatives/neg.omit.1.ts b/packages/jsii/test/negatives/neg.omit.1.ts index 694b3416a7..4627ca8dad 100644 --- a/packages/jsii/test/negatives/neg.omit.1.ts +++ b/packages/jsii/test/negatives/neg.omit.1.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Illegal "extends" value for an exported API - export interface FooBar { readonly foo: string; readonly bar: string; diff --git a/packages/jsii/test/negatives/neg.omit.2.ts b/packages/jsii/test/negatives/neg.omit.2.ts index 9ac411f164..20fe33b89f 100644 --- a/packages/jsii/test/negatives/neg.omit.2.ts +++ b/packages/jsii/test/negatives/neg.omit.2.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Illegal "implements" value for an exported API - export interface FooBar { readonly foo: string; readonly bar: string; diff --git a/packages/jsii/test/negatives/neg.omit.3.ts b/packages/jsii/test/negatives/neg.omit.3.ts index 80da33d44c..a9dc0e21a5 100644 --- a/packages/jsii/test/negatives/neg.omit.3.ts +++ b/packages/jsii/test/negatives/neg.omit.3.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Only string-indexed map types are supported - export interface FooBar { readonly foo: string; readonly bar: string; diff --git a/packages/jsii/test/negatives/neg.omit.4.ts b/packages/jsii/test/negatives/neg.omit.4.ts index b8365c48a8..1051cbc64e 100644 --- a/packages/jsii/test/negatives/neg.omit.4.ts +++ b/packages/jsii/test/negatives/neg.omit.4.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Only string-indexed map types are supported - export interface FooBar { readonly foo: string; readonly bar: string; diff --git a/packages/jsii/test/negatives/neg.property-name.1.ts b/packages/jsii/test/negatives/neg.property-name.1.ts index 97bb30e64a..2c78658577 100644 --- a/packages/jsii/test/negatives/neg.property-name.1.ts +++ b/packages/jsii/test/negatives/neg.property-name.1.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: PROP - export class MyClass { - public PROP?: number; + public PROP?: number; } diff --git a/packages/jsii/test/negatives/neg.property-name.2.ts b/packages/jsii/test/negatives/neg.property-name.2.ts index 43e07eeec0..8bf905b004 100644 --- a/packages/jsii/test/negatives/neg.property-name.2.ts +++ b/packages/jsii/test/negatives/neg.property-name.2.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: my_Prop - export class MyClass { - public my_Prop?: number; + public my_Prop?: number; } diff --git a/packages/jsii/test/negatives/neg.property-name.3.ts b/packages/jsii/test/negatives/neg.property-name.3.ts index 94f4fb0fd1..1b979db1e1 100644 --- a/packages/jsii/test/negatives/neg.property-name.3.ts +++ b/packages/jsii/test/negatives/neg.property-name.3.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Methods and properties cannot have names like getXxx() - those conflict with Java property getters by the same name - export class MyClass { - public getFoo?: number; + public getFoo?: number; } diff --git a/packages/jsii/test/negatives/neg.reserved.emits-warning.ts b/packages/jsii/test/negatives/neg.reserved.emits-warning.ts index f85a874575..1e84a02292 100644 --- a/packages/jsii/test/negatives/neg.reserved.emits-warning.ts +++ b/packages/jsii/test/negatives/neg.reserved.emits-warning.ts @@ -1,13 +1,8 @@ ///!STRICT! -///!MATCH_ERROR: 'None' is a reserved word in Python. -///!MATCH_ERROR: 'assert' is a reserved word in Java, Python. -///!MATCH_ERROR: 'do' is a reserved word in C#, Java. -///!MATCH_ERROR: 'internal' is a reserved word in C#. - export class None { public readonly do: boolean = true; - public assert(internal: boolean): void { + public assert(_internal: boolean): void { throw new Error(); } } diff --git a/packages/jsii/test/negatives/neg.static-const-name.ts b/packages/jsii/test/negatives/neg.static-const-name.ts index 31fa921f16..5dd63e1c2e 100644 --- a/packages/jsii/test/negatives/neg.static-const-name.ts +++ b/packages/jsii/test/negatives/neg.static-const-name.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Static constant names must use TRUMP_CASE, PascalCase or camelCase: snake_case - export class MyClass { - static readonly snake_case = 123; + static readonly snake_case = 123; } diff --git a/packages/jsii/test/negatives/neg.static-member-mixing.1.ts b/packages/jsii/test/negatives/neg.static-member-mixing.1.ts index 3116d61a04..373112595a 100644 --- a/packages/jsii/test/negatives/neg.static-member-mixing.1.ts +++ b/packages/jsii/test/negatives/neg.static-member-mixing.1.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: non-static member 'funFunction' of class 'Sub' conflicts with static member in ancestor 'SuperDuper' - export class SuperDuper { public static funFunction() { // Empty @@ -14,4 +12,4 @@ export class Sub extends Super { public funFunction() { // Oops } -} \ No newline at end of file +} diff --git a/packages/jsii/test/negatives/neg.static-member-mixing.2.ts b/packages/jsii/test/negatives/neg.static-member-mixing.2.ts index 82370197d3..f31bcc850d 100644 --- a/packages/jsii/test/negatives/neg.static-member-mixing.2.ts +++ b/packages/jsii/test/negatives/neg.static-member-mixing.2.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: member 'funFunction' of class 'TheClass' cannot be declared both statically and non-statically - export class TheClass { public static funFunction() { // Empty @@ -8,4 +6,4 @@ export class TheClass { public funFunction() { // Empty } -} \ No newline at end of file +} diff --git a/packages/jsii/test/negatives/neg.static-method-name.1.ts b/packages/jsii/test/negatives/neg.static-method-name.1.ts index 4e90570bac..a6a77d1dcb 100644 --- a/packages/jsii/test/negatives/neg.static-method-name.1.ts +++ b/packages/jsii/test/negatives/neg.static-method-name.1.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: MethodIsNotCamelCase - export class MyClass { - MethodIsNotCamelCase() { - return "hi"; - } + MethodIsNotCamelCase() { + return 'hi'; + } } diff --git a/packages/jsii/test/negatives/neg.static-method-name.ts b/packages/jsii/test/negatives/neg.static-method-name.ts index 2d07c4eeee..f3237f9302 100644 --- a/packages/jsii/test/negatives/neg.static-method-name.ts +++ b/packages/jsii/test/negatives/neg.static-method-name.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: METHOD - export class MyClass { - METHOD() { - return "hi"; - } + METHOD() { + return 'hi'; + } } diff --git a/packages/jsii/test/negatives/neg.static-prop-name.1.ts b/packages/jsii/test/negatives/neg.static-prop-name.1.ts index a576492047..9ad726d104 100644 --- a/packages/jsii/test/negatives/neg.static-prop-name.1.ts +++ b/packages/jsii/test/negatives/neg.static-prop-name.1.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: Prop - export class MyClass { - static get Prop() { - return 123; - } + static get Prop() { + return 123; + } } diff --git a/packages/jsii/test/negatives/neg.static-prop-name.2.ts b/packages/jsii/test/negatives/neg.static-prop-name.2.ts index b22b20a14a..2d51f9f9ee 100644 --- a/packages/jsii/test/negatives/neg.static-prop-name.2.ts +++ b/packages/jsii/test/negatives/neg.static-prop-name.2.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Method and non-static non-readonly property names must use camelCase: PROP - export class MyClass { - static get PROP() { - return 123; - } + static get PROP() { + return 123; + } } diff --git a/packages/jsii/test/negatives/neg.struct-extends-interface.ts b/packages/jsii/test/negatives/neg.struct-extends-interface.ts index 04e152eba9..d1c99342bb 100644 --- a/packages/jsii/test/negatives/neg.struct-extends-interface.ts +++ b/packages/jsii/test/negatives/neg.struct-extends-interface.ts @@ -1,5 +1,3 @@ -///!MATCH_ERROR: Interface contains behavior: name should be "IStruct" - // Attempt to extend an interface from a struct (aka data type) export interface IInterface { readonly field: string; diff --git a/packages/jsii/test/negatives/neg.submodules-cannot-have-colliding-names.ts b/packages/jsii/test/negatives/neg.submodules-cannot-have-colliding-names.ts index b92063f8e3..48427628aa 100644 --- a/packages/jsii/test/negatives/neg.submodules-cannot-have-colliding-names.ts +++ b/packages/jsii/test/negatives/neg.submodules-cannot-have-colliding-names.ts @@ -1,7 +1,5 @@ -///!MATCH_ERROR: Submodule "ns1" conflicts with "Ns1". - export * as ns1 from './namespaced'; export class Ns1 { - private constructor() { } + private constructor() {} } diff --git a/packages/jsii/test/negatives/neg.submodules-cannot-share-symbols.ts b/packages/jsii/test/negatives/neg.submodules-cannot-share-symbols.ts index 61b34bd37c..807d747553 100644 --- a/packages/jsii/test/negatives/neg.submodules-cannot-share-symbols.ts +++ b/packages/jsii/test/negatives/neg.submodules-cannot-share-symbols.ts @@ -1,4 +1,2 @@ -///!MATCH_ERROR: Symbol is re-exported under two distinct submodules - export * as ns1 from './namespaced'; export * as ns2 from './namespaced'; diff --git a/packages/jsii/test/negatives/neg.submodules-must-be-camel-cased.ts b/packages/jsii/test/negatives/neg.submodules-must-be-camel-cased.ts index 0b2d93899c..6cda27662c 100644 --- a/packages/jsii/test/negatives/neg.submodules-must-be-camel-cased.ts +++ b/packages/jsii/test/negatives/neg.submodules-must-be-camel-cased.ts @@ -1,3 +1 @@ -///!MATCH_ERROR: Submodule namespaces must be camelCased or snake_cased. Consider renaming to "ns1" - export * as Ns1 from './namespaced';