diff --git a/packages/awslint/.eslintrc.js b/packages/awslint/.eslintrc.js index 02a7bc56bbb04..0f4db45f2ba91 100644 --- a/packages/awslint/.eslintrc.js +++ b/packages/awslint/.eslintrc.js @@ -35,7 +35,6 @@ module.exports = { ignorePatterns: ['*.js', '*.d.ts', 'node_modules/', '*.generated.ts'], rules: { '@aws-cdk/no-core-construct': ['error'], - '@aws-cdk/no-qualified-construct': ['error'], '@aws-cdk/invalid-cfn-imports': ['error'], // Require use of the `import { foo } from 'bar';` form instead of `import foo = require('bar');` '@typescript-eslint/no-require-imports': ['error'], diff --git a/tools/@aws-cdk/cdk-build-tools/config/eslintrc.js b/tools/@aws-cdk/cdk-build-tools/config/eslintrc.js index 96606baae2b0f..3eb417a86a437 100644 --- a/tools/@aws-cdk/cdk-build-tools/config/eslintrc.js +++ b/tools/@aws-cdk/cdk-build-tools/config/eslintrc.js @@ -42,7 +42,6 @@ module.exports = { ignorePatterns: ['*.js', '*.d.ts', 'node_modules/', '*.generated.ts'], rules: { '@aws-cdk/no-core-construct': ['error'], - '@aws-cdk/no-qualified-construct': ['error'], '@aws-cdk/invalid-cfn-imports': ['error'], '@aws-cdk/no-literal-partition': ['error'], // Require use of the `import { foo } from 'bar';` form instead of `import foo = require('bar');` diff --git a/tools/@aws-cdk/eslint-plugin/README.md b/tools/@aws-cdk/eslint-plugin/README.md index 558b929f253af..386c1c0f2040c 100644 --- a/tools/@aws-cdk/eslint-plugin/README.md +++ b/tools/@aws-cdk/eslint-plugin/README.md @@ -4,10 +4,16 @@ Eslint plugin for the CDK repository. Contains rules that need to be applied spe ## Rules +* `invalid-cfn-imports`: Ensures that imports of `Cfn` L1 resources come from the stable + `aws-cdk-lib` package and not the alpha packages. Rule only applies to alpha modules. + * `no-core-construct`: Forbid the use of `Construct` and `IConstruct` from the "@aws-cdk/core" module. Instead use `Construct` and `IConstruct` from the "constructs" module. Rule only applies to typescript files under the `test/` folder. +* `no-literal-partition`: Forbids the use of literal partitions (usually `aws`). Instead, use + `Aws.PARTITION` to ensure that the code works for other partitions too. + ## How to add new rules * Make a new file in `lib/rules`. It should export one function called `create`. The diff --git a/tools/@aws-cdk/eslint-plugin/lib/index.ts b/tools/@aws-cdk/eslint-plugin/lib/index.ts index c6991c061e486..e25149d1b615a 100644 --- a/tools/@aws-cdk/eslint-plugin/lib/index.ts +++ b/tools/@aws-cdk/eslint-plugin/lib/index.ts @@ -1,6 +1,5 @@ export const rules = { 'no-core-construct': require('./rules/no-core-construct'), - 'no-qualified-construct': require('./rules/no-qualified-construct'), 'invalid-cfn-imports': require('./rules/invalid-cfn-imports'), 'no-literal-partition': require('./rules/no-literal-partition'), }; diff --git a/tools/@aws-cdk/eslint-plugin/lib/rules/no-qualified-construct.ts b/tools/@aws-cdk/eslint-plugin/lib/rules/no-qualified-construct.ts deleted file mode 100644 index eb8a418cab58e..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/lib/rules/no-qualified-construct.ts +++ /dev/null @@ -1,134 +0,0 @@ -// -// This rule ensures that the `@aws-cdk/core.Construct` class is always -// referenced without a namespace qualifier (`Construct` instead of -// `xxx.Construct`). The fixer will automatically add an `import` statement -// separated from the main import group to reduce the chance for merge conflicts -// with v2-main. -// -// If there is already an import of `constructs.Construct` under the name -// `Construct`, we will import `core.Construct` as the alias `CoreConstruct` -// instead. -// - -import { AST, Rule } from 'eslint'; -import { ImportCache } from '../private/import-cache'; - -const importCache = new ImportCache(); - -export function create(context: Rule.RuleContext): Rule.NodeListener { - // skip core - if (context.getFilename().includes('@aws-cdk/core')) { - return {}; - } - - return { - // collect all "import" statements. we will later use them to determine - // exactly how to import `core.Construct`. - ImportDeclaration: node => { - for (const s of node.specifiers) { - const typeName = () => { - switch (s.type) { - case 'ImportSpecifier': return s.imported.name; - case 'ImportDefaultSpecifier': return s.local.name; - case 'ImportNamespaceSpecifier': return s.local.name; - } - }; - - importCache.record({ - fileName: context.getFilename(), - typeName: typeName(), - importNode: node, - localName: `${node.source.value}.${s.local.name}` - }); - } - }, - - // this captures `class X extends xxx.Construct` - ClassDeclaration: node => { - if (node.superClass?.type === 'MemberExpression') { - const sc = node.superClass; - // const qualifier = sc.object.type === 'Identifier' ? sc.object.name : undefined; - const baseClass = sc.property.type === 'Identifier' ? sc.property.name : undefined; - if (baseClass === 'Construct' && sc.range) { - report(context, node, sc.range); - } - } - }, - - // this captures using `xxx.Construct` as an identifier - Identifier: node => { - const typeAnnotation = (node as any).typeAnnotation?.typeAnnotation; - const type = typeAnnotation?.typeName; - if (type?.type === 'TSQualifiedName' && type?.right.name === 'Construct' && type?.left.name !== 'constructs') { - report(context, node, typeAnnotation.range); - } - }, - } -} - -/** - * Reports an error indicating that we found `xxx.Construct` usage, and apply - * the appropriate fix. - * @param context Rule context - * @param node Rule node (for the report) - * @param replaceRange Text range to replace - */ -function report(context: Rule.RuleContext, node: Rule.Node, replaceRange: AST.Range) { - context.report({ - message: 'To avoid merge conflicts with the v2-main branch, the "Construct" type must be referenced without a qualifier (e.g. "Construct" instead of "CoreConstruct")', - node, - fix: fixer => { - const imports = importCache.imports.filter(x => x.fileName === context.getFilename()); - const findImport = (x: string) => imports.find(i => i.localName === x); - - const coreConstruct = findImport('@aws-cdk/core.Construct') - const coreCoreConstruct = findImport('@aws-cdk/core.CoreConstruct'); - const constructsConstruct = findImport('constructs.Construct'); - - // determines whether we will replace with `Construct` or `CoreConstruct` - // based on whether this file already imported `constructs.Construct`. - let replaceBy: string | undefined; - - // determines whether an "import" statement should be added and it's - // contents. - let addImport: string | undefined; - - if (coreConstruct) { - // we already import `core.Construct` as `Construct` - replaceBy = 'Construct'; - } else if (coreCoreConstruct) { - // we already import `core.Construct` as `CoreConstruct` - replaceBy = 'CoreConstruct' - } else if (constructsConstruct) { - // we import `constructs.Construct`, so import and replace - // `core.Construct` with `CoreConstruct` - replaceBy = 'CoreConstruct'; - addImport = `import { Construct as ${replaceBy} } from '@aws-cdk/core';`; - } else { - // import `core.Construct` as `Construct` and replace - replaceBy = 'Construct'; - addImport = `import { ${replaceBy} } from '@aws-cdk/core';`; - } - - const fixes: Rule.Fix[] = [ - fixer.replaceTextRange(replaceRange, replaceBy) - ]; - - if (addImport) { - // find the last import statement in the file and add our import immediately after - const lastImport = imports[imports.length - 1]; - if (lastImport) { - fixes.push(fixer.insertTextAfter(lastImport.importNode, [ - "", - "", - "// keep this import separate from other imports to reduce chance for merge conflicts with v2-main", - "// eslint-disable-next-line no-duplicate-imports, import/order", - addImport, - ].join('\n'))); - } - } - - return fixes; - }, - }); -} \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/both-constructs.expected.ts b/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/both-constructs.expected.ts deleted file mode 100644 index 20caf8244cd1b..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/both-constructs.expected.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Construct } from 'constructs' -import * as cdk from '@aws-cdk/core'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct as CoreConstruct } from '@aws-cdk/core'; - -let x: CoreConstruct; -let y: Construct; \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/both-constructs.ts b/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/both-constructs.ts deleted file mode 100644 index bd92a909af763..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/both-constructs.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Construct } from 'constructs' -import * as cdk from '@aws-cdk/core'; - -let x: cdk.Construct; -let y: Construct; \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/eslintrc.js b/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/eslintrc.js deleted file mode 100644 index 882ad41024e7f..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['@aws-cdk'], - rules: { - '@aws-cdk/no-qualified-construct': [ 'error' ], - } -} \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-heritage.expected.ts b/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-heritage.expected.ts deleted file mode 100644 index 6510d7dd5542f..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-heritage.expected.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as cdk from '@aws-cdk/core'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -class MyConstruct extends Construct { -} \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-heritage.ts b/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-heritage.ts deleted file mode 100644 index 3f8b877e32c2e..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-heritage.ts +++ /dev/null @@ -1,4 +0,0 @@ -import * as cdk from '@aws-cdk/core'; - -class MyConstruct extends cdk.Construct { -} \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-usage.expected.ts b/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-usage.expected.ts deleted file mode 100644 index bba5c3ae8aa50..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-usage.expected.ts +++ /dev/null @@ -1,7 +0,0 @@ -import * as cdk from '@aws-cdk/core'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -let x: Construct; \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-usage.ts b/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-usage.ts deleted file mode 100644 index d2ebc12dc01ff..0000000000000 --- a/tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-qualified-construct/qualified-usage.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as cdk from '@aws-cdk/core'; - -let x: cdk.Construct; \ No newline at end of file diff --git a/tools/@aws-cdk/pkglint/.eslintrc.js b/tools/@aws-cdk/pkglint/.eslintrc.js index fc925d6f67b8b..061eb5b0a80c9 100644 --- a/tools/@aws-cdk/pkglint/.eslintrc.js +++ b/tools/@aws-cdk/pkglint/.eslintrc.js @@ -35,7 +35,6 @@ module.exports = { ignorePatterns: ['*.js', '*.d.ts', 'node_modules/', '*.generated.ts'], rules: { '@aws-cdk/no-core-construct': ['error'], - '@aws-cdk/no-qualified-construct': ['error'], '@aws-cdk/invalid-cfn-imports': ['error'], // Require use of the `import { foo } from 'bar';` form instead of `import foo = require('bar');` '@typescript-eslint/no-require-imports': ['error'],