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

build(awslint): include types from submodules during linting #27160

Merged
merged 23 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/aws-cdk-lib/aws-apigateway/lib/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ export interface ResourceProps extends ResourceOptions {
* A path name for the resource.
*/
readonly pathPart: string;

/**
* A name for the resource.
*/
readonly resourceName?: string;
mikewrighton marked this conversation as resolved.
Show resolved Hide resolved
}

export abstract class ResourceBase extends ResourceConstruct implements IResource {
Expand Down
2,699 changes: 2,698 additions & 1 deletion packages/aws-cdk-lib/package.json
mikewrighton marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions packages/awslint/lib/rules/cfn-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class CfnResourceReflection {
* Returns all CFN resource classes within an assembly.
*/
public static findAll(assembly: reflect.Assembly) {
return assembly.classes
return assembly.allClasses
.filter(c => CoreTypes.isCfnResource(c))
.map(c => new CfnResourceReflection(c));
}
Expand All @@ -54,10 +54,7 @@ export class CfnResourceReflection {

this.basename = cls.name.slice('Cfn'.length);

// HACK: extract full CFN name from initializer docs
const initializerDoc = (cls.initializer && cls.initializer.docs.docs.summary) || '';
const out = /a new `([^`]+)`/.exec(initializerDoc);
const fullname = out && out[1];
const fullname = cls.docs.customTag('cloudformationResource');
if (!fullname) {
throw new Error(`Unable to extract CloudFormation resource name from initializer documentation of ${cls}`);
}
Expand Down
12 changes: 8 additions & 4 deletions packages/awslint/lib/rules/construct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import * as reflect from 'jsii-reflect';
import { CoreTypes } from './core-types';
import { Linter, MethodSignatureParameterExpectation } from '../linter';

export const constructLinter = new Linter<ConstructReflection>(assembly => assembly.classes
export const constructLinter = new Linter<ConstructReflection>(assembly => assembly.allClasses
.filter(t => CoreTypes.isConstructClass(t))
.map(construct => new ConstructReflection(construct)));

export class ConstructReflection {

public static findAllConstructs(assembly: reflect.Assembly) {
return assembly.classes
return assembly.allClasses
.filter(c => CoreTypes.isConstructClass(c))
.map(c => new ConstructReflection(c));
}
Expand Down Expand Up @@ -44,14 +44,18 @@ export class ConstructReflection {
this.sys = classType.system;
this.core = new CoreTypes(this.sys);
this.ROOT_CLASS = this.sys.findClass(this.core.constructClass.fqn);
this.interfaceFqn = `${classType.assembly.name}.I${classType.name}`;
this.propsFqn = `${classType.assembly.name}.${classType.name}Props`;
this.interfaceFqn = `${this.typePrefix(classType)}.I${classType.name}`;
this.propsFqn = `${this.typePrefix(classType)}.${classType.name}Props`;
this.interfaceType = this.tryFindInterface();
this.propsType = this.tryFindProps();
this.initializer = classType.initializer;
this.hasPropsArgument = this.initializer != null && this.initializer.parameters.length >= 3;
}

private typePrefix(classType: reflect.ClassType) {
return classType.assembly.name + (classType.namespace ? `.${classType.namespace}` : '');
}

private tryFindInterface() {
const sys = this.classType.system;
const found = sys.tryFindFqn(this.interfaceFqn);
Expand Down
19 changes: 13 additions & 6 deletions packages/awslint/lib/rules/core-types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as reflect from 'jsii-reflect';
import { getDocTag } from './util';

const CORE_MODULE = '@aws-cdk/core';
const CORE_MODULE = 'aws-cdk-lib';
enum CoreTypesFqn {
CfnResource = '@aws-cdk/core.CfnResource',
Resource = '@aws-cdk/core.Resource',
ResourceInterface = '@aws-cdk/core.IResource',
ResolvableInterface = '@aws-cdk/core.IResolvable',
PhysicalName = '@aws-cdk/core.PhysicalName',
CfnResource = 'aws-cdk-lib.CfnResource',
Resource = 'aws-cdk-lib.Resource',
ResourceInterface = 'aws-cdk-lib.IResource',
ResolvableInterface = 'aws-cdk-lib.IResolvable',
PhysicalName = 'aws-cdk-lib.PhysicalName',

Construct = 'constructs.Construct',
ConstructInterface = 'constructs.IConstruct',
Expand Down Expand Up @@ -78,6 +78,13 @@ export class CoreTypes {
return classType.extends(baseResource) || getDocTag(classType, 'resource');
}

/**
* Return true if the nesting parent of the given interface is a CFN class
*/
public static isCfnNestedType(interfaceType: reflect.Type) {
return interfaceType.nestingParent && CoreTypes.isCfnType(interfaceType.nestingParent);
}

/**
* Return true if the given interface type is a CFN class or prop type
*/
Expand Down
10 changes: 6 additions & 4 deletions packages/awslint/lib/rules/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ type DocsLinterContext = {

export const docsLinter = new Linter<DocsLinterContext>(assembly => {
return [
...flatMap(assembly.classes, classType => [
...flatMap(assembly.allClasses, classType => [
{ assembly, kind: 'type', documentable: classType, errorKey: classType.fqn },
...classType.ownProperties.map(property => ({ assembly, kind: 'class-property', containingType: classType, documentable: property, errorKey: `${classType.fqn}.${property.name}` })),
...classType.ownMethods.map(method => ({ assembly, kind: 'method', containingType: classType, documentable: method, errorKey: `${classType.fqn}.${method.name}` })),
]),
...flatMap(assembly.interfaces, interfaceType => [
...flatMap(assembly.allInterfaces, interfaceType => [
{ assembly, kind: 'type', documentable: interfaceType, errorKey: interfaceType.fqn },
...interfaceType.ownProperties.map(property => ({ assembly, kind: 'interface-property', containingType: interfaceType, documentable: property, errorKey: `${interfaceType.fqn}.${property.name}` })),
...interfaceType.ownMethods.map(method => ({ assembly, kind: 'method', containingType: interfaceType, documentable: method, errorKey: `${interfaceType.fqn}.${method.name}` })),
]),
...flatMap(assembly.enums, enumType => [
...flatMap(assembly.allEnums, enumType => [
{ assembly, kind: 'type', documentable: enumType, errorKey: enumType.fqn },
...enumType.members.map(member => ({ assembly, kind: 'enum-member', containingType: enumType, documentable: member, errorKey: `${enumType.fqn}.${member.name}` })),
]),
Expand Down Expand Up @@ -53,7 +53,9 @@ docsLinter.add({
if (e.ctx.kind !== 'interface-property') { return; }
if (!e.ctx.containingType.isDataType()) { return; }
// this rule does not apply to L1 constructs
if (CoreTypes.isCfnType(e.ctx.containingType)) { return; }
if (CoreTypes.isCfnType(e.ctx.containingType) || CoreTypes.isCfnNestedType(e.ctx.containingType)) {
return;
}

const property = e.ctx.documentable;
e.assert(!property.optional || property.docs.docs.default !== undefined, e.ctx.errorKey);
Expand Down
2 changes: 1 addition & 1 deletion packages/awslint/lib/rules/integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as reflect from 'jsii-reflect';
import { memberFqn } from './util';
import { Linter } from '../linter';

export const integrationLinter = new Linter<IntegrationReflection>(assembly => assembly.interfaces
export const integrationLinter = new Linter<IntegrationReflection>(assembly => assembly.allInterfaces
.filter(IntegrationReflection.isIntegrationInterface)
.map(construct => new IntegrationReflection(construct)));

Expand Down
2 changes: 1 addition & 1 deletion packages/awslint/lib/rules/public-static-properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const UPPER_SNAKE_CASE_ALLOWED_PATTERN = new RegExp('^[A-Z0-9][A-Z0-9_]*[A-Z0-9]

export const publicStaticPropertiesLinter = new Linter(assembly => {
const result = new Array<Property>();
for (const c of assembly.classes) {
for (const c of assembly.allClasses) {
for (const property of c.allProperties) {
if (property.const && property.static) {
result.push(property);
Expand Down
7 changes: 6 additions & 1 deletion packages/awslint/lib/rules/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,12 @@ function tryResolveCfnResource(resourceClass: reflect.ClassType): CfnResourceRef
}

function guessResourceName(fqn: string) {
const match = /@aws-cdk\/([a-z]+)-([a-z0-9]+)\.([A-Z][a-zA-Z0-9]+)/.exec(fqn);
// Strip any version suffixes e.g. 'TableV2' becomes 'Table'
var match = /^(.+?)(V[0-9]+)?$/.exec(fqn);
if (!match) { return undefined; }
const [, versionless] = match;

match = /aws-cdk-lib\.([a-z]+)_([a-z0-9]+)\.([A-Z][a-zA-Z0-9]+)/.exec(versionless);
if (!match) { return undefined; }

const [, org, ns, rs] = match;
Expand Down
1 change: 1 addition & 0 deletions tools/@aws-cdk/spec2cdk/lib/cdk/resource-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export class ResourceClass extends ClassType {
docs: {
...splitDocumentation(resource.documentation),
stability: Stability.External,
cloudformationResource: resource.cloudFormationType,
see: cloudFormationDocLink({
resourceType: resource.cloudFormationType,
}),
Expand Down