From 86555397ba8f4bd93a52b0c7c9681b1c8974af58 Mon Sep 17 00:00:00 2001 From: Mitchell Valine Date: Tue, 11 Jul 2023 10:46:05 -0700 Subject: [PATCH] chore: remove aws-cdk-migration package Removes the aws-cdk-migration package as this was used to rewrite imports when migrating an application from v1 to v2. --- packages/aws-cdk-migration/.eslintrc.js | 3 - packages/aws-cdk-migration/.gitignore | 15 - .../.no-packagejson-validator | 1 - packages/aws-cdk-migration/.npmignore | 17 - packages/aws-cdk-migration/LICENSE | 201 -------- packages/aws-cdk-migration/NOTICE | 2 - packages/aws-cdk-migration/README.md | 11 - .../aws-cdk-migration/bin/rewrite-imports-v2 | 2 - .../bin/rewrite-imports-v2.ts | 39 -- packages/aws-cdk-migration/jest.config.js | 10 - packages/aws-cdk-migration/lib/rewrite.ts | 451 ------------------ packages/aws-cdk-migration/package.json | 60 --- .../aws-cdk-migration/test/rewrite.test.ts | 404 ---------------- packages/aws-cdk-migration/tsconfig.json | 27 -- 14 files changed, 1243 deletions(-) delete mode 100644 packages/aws-cdk-migration/.eslintrc.js delete mode 100644 packages/aws-cdk-migration/.gitignore delete mode 100644 packages/aws-cdk-migration/.no-packagejson-validator delete mode 100644 packages/aws-cdk-migration/.npmignore delete mode 100644 packages/aws-cdk-migration/LICENSE delete mode 100644 packages/aws-cdk-migration/NOTICE delete mode 100644 packages/aws-cdk-migration/README.md delete mode 100755 packages/aws-cdk-migration/bin/rewrite-imports-v2 delete mode 100644 packages/aws-cdk-migration/bin/rewrite-imports-v2.ts delete mode 100644 packages/aws-cdk-migration/jest.config.js delete mode 100644 packages/aws-cdk-migration/lib/rewrite.ts delete mode 100644 packages/aws-cdk-migration/package.json delete mode 100644 packages/aws-cdk-migration/test/rewrite.test.ts delete mode 100644 packages/aws-cdk-migration/tsconfig.json diff --git a/packages/aws-cdk-migration/.eslintrc.js b/packages/aws-cdk-migration/.eslintrc.js deleted file mode 100644 index 2658ee8727166..0000000000000 --- a/packages/aws-cdk-migration/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); -baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; diff --git a/packages/aws-cdk-migration/.gitignore b/packages/aws-cdk-migration/.gitignore deleted file mode 100644 index 6b33b2cabe8ed..0000000000000 --- a/packages/aws-cdk-migration/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -node_modules -*.js -*.d.ts - -dist -.LAST_PACKAGE -.LAST_BUILD -*.snk -.nyc_output -coverage -nyc.config.js -!.eslintrc.js -!jest.config.js - -junit.xml \ No newline at end of file diff --git a/packages/aws-cdk-migration/.no-packagejson-validator b/packages/aws-cdk-migration/.no-packagejson-validator deleted file mode 100644 index 171d30544e368..0000000000000 --- a/packages/aws-cdk-migration/.no-packagejson-validator +++ /dev/null @@ -1 +0,0 @@ -disable pkglint diff --git a/packages/aws-cdk-migration/.npmignore b/packages/aws-cdk-migration/.npmignore deleted file mode 100644 index 4a2955c9ce9f9..0000000000000 --- a/packages/aws-cdk-migration/.npmignore +++ /dev/null @@ -1,17 +0,0 @@ - -dist -.LAST_PACKAGE -*.tsbuildinfo -tsconfig.json -.LAST_BUILD -*.snk - -*.ts -!*.d.ts -.eslintrc.js -jest.config.js - -# exclude cdk artifacts -**/cdk.out -junit.xml -test/ \ No newline at end of file diff --git a/packages/aws-cdk-migration/LICENSE b/packages/aws-cdk-migration/LICENSE deleted file mode 100644 index 9b722c65c5481..0000000000000 --- a/packages/aws-cdk-migration/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/packages/aws-cdk-migration/NOTICE b/packages/aws-cdk-migration/NOTICE deleted file mode 100644 index a27b7dd317649..0000000000000 --- a/packages/aws-cdk-migration/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/aws-cdk-migration/README.md b/packages/aws-cdk-migration/README.md deleted file mode 100644 index ba37d609c28db..0000000000000 --- a/packages/aws-cdk-migration/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# aws-cdk-migration - -Migrate TypeScript `import` statements from modular CDK (i.e. `@aws-cdk/aws-s3`) to aws-cdk-lib (i.e. `aws-cdk-lib`); - -Usage: - -```shell -$ npx -p aws-cdk-migration rewrite-imports-v2 lib/**/*.ts -``` - -NOTE: `node_modules` and `*.d.ts` files are ignored. diff --git a/packages/aws-cdk-migration/bin/rewrite-imports-v2 b/packages/aws-cdk-migration/bin/rewrite-imports-v2 deleted file mode 100755 index 59071f9ed501a..0000000000000 --- a/packages/aws-cdk-migration/bin/rewrite-imports-v2 +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('./rewrite-imports-v2.js'); diff --git a/packages/aws-cdk-migration/bin/rewrite-imports-v2.ts b/packages/aws-cdk-migration/bin/rewrite-imports-v2.ts deleted file mode 100644 index 3b56cd569e1be..0000000000000 --- a/packages/aws-cdk-migration/bin/rewrite-imports-v2.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* eslint-disable no-console */ -import * as fs from 'fs'; -import { promisify } from 'util'; -import * as _glob from 'glob'; - -import { rewriteMonoPackageImports } from '../lib/rewrite'; - -const glob = promisify(_glob); - -async function main() { - if (!process.argv[2]) { - console.error('usage: rewrite-imports **/*.ts'); - return; - } - - const ignore = [ - '**/*.d.ts', - 'node_modules/**', - ]; - - const args = process.argv.slice(2); - for (const arg of args) { - const files = await glob(arg, { ignore, matchBase: true }); - for (const file of files) { - const input = await fs.promises.readFile(file, { encoding: 'utf8' }); - const output = rewriteMonoPackageImports(input, 'aws-cdk-lib', file, { - rewriteConstructsImports: true, - }); - if (output.trim() !== input.trim()) { - await fs.promises.writeFile(file, output); - } - } - } -} - -main().catch(e => { - console.error(e.stack); - process.exit(1); -}); diff --git a/packages/aws-cdk-migration/jest.config.js b/packages/aws-cdk-migration/jest.config.js deleted file mode 100644 index 6a8dc8ed67646..0000000000000 --- a/packages/aws-cdk-migration/jest.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); -module.exports = { - ...baseConfig, - coverageThreshold: { - global: { - statements: 75, - branches: 65, - }, - }, -}; diff --git a/packages/aws-cdk-migration/lib/rewrite.ts b/packages/aws-cdk-migration/lib/rewrite.ts deleted file mode 100644 index 471ea47fb29ad..0000000000000 --- a/packages/aws-cdk-migration/lib/rewrite.ts +++ /dev/null @@ -1,451 +0,0 @@ -import * as ts from 'typescript'; - -/** - * The options for rewriting the file. - */ -export interface RewriteOptions { - /** - * Optional module names that should result in replacing to something different than just 'aws-cdk-lib'. - */ - readonly customModules?: { [moduleName: string]: string }; - - /** - * When true, this will rewrite imports of generated L1s to reference aws-cdk-lib. - * - * For example: - * import * as codestar from './codestar.generated';` - * becomes: - * import * as codestar from 'aws-cdk-lib/aws-codestar'; - */ - readonly rewriteCfnImports?: boolean; - - /** - * The unscoped name of the package, e.g. 'aws-kinesisfirehose'. - */ - readonly packageUnscopedName?: string; - - /** - * When true, imports to known types from the 'constructs' library will be rewritten - * to explicitly import from 'constructs', rather than '@aws-cdk/core'. - * @default false - */ - readonly rewriteConstructsImports?: boolean; -} - -/** - * Re-writes "hyper-modular" CDK imports (most packages in `@aws-cdk/*`) to the - * relevant "mono" CDK import path. The re-writing will only modify the imported - * library path, presrving the existing quote style, etc... - * - * Syntax errors in the source file being processed may cause some import - * statements to not be re-written. - * - * Supported import statement forms are: - * - `import * as lib from '@aws-cdk/lib';` - * - `import { Type } from '@aws-cdk/lib';` - * - `import '@aws-cdk/lib';` - * - `import lib = require('@aws-cdk/lib');` - * - `import { Type } = require('@aws-cdk/lib'); - * - `require('@aws-cdk/lib'); - * - * @param sourceText the source code where imports should be re-written. - * @param libName the mono CDK library name. - * @param fileName a customized file name to provide the TypeScript processor. - * - * @returns the updated source code. - */ -export function rewriteMonoPackageImports(sourceText: string, libName: string, fileName: string = 'index.ts', options: RewriteOptions = {}): string { - return rewriteImports( - sourceText, - (modPath, importedElements) => updatedExternalLocation(modPath, libName, options, importedElements), - fileName, - options.rewriteConstructsImports, - ); -} - -/** - * Re-writes READMEs of "hyper-modular" CDK imports (most packages in `@aws-cdk/*`) - * to the relevant "mono" CDK import path. The re-writing will only modify the imported - * library path, presrving the existing quote style, etc... - * - * Syntax errors in the README snippets being processed may cause some import - * statements to not be re-written. - * - * Supported import statement forms are: - * - `import * as lib from '@aws-cdk/lib';` - * - `import { Type } from '@aws-cdk/lib';` - * - `import '@aws-cdk/lib';` - * - `import lib = require('@aws-cdk/lib');` - * - `import { Type } = require('@aws-cdk/lib'); - * - `require('@aws-cdk/lib'); - * - * @param sourceText the README where snippet imports should be re-written. - * @param libName the mono CDK library name. - * @param fileName a customized file name to provide the TypeScript processor. - * - * @returns the updated source code. - */ -export function rewriteReadmeImports(sourceText: string, libName: string, fileName: string = 'index.ts', options: RewriteOptions = {}): string { - return sourceText.replace(/(```(?:ts|typescript|text)[^\n]*\n)(.*?)(\n\s*```)/gs, (_m, prefix, body, suffix) => { - return prefix + - rewriteImports( - body, - (modPath, importedElements) => updatedExternalLocation(modPath, libName, options, importedElements), - fileName, - options.rewriteConstructsImports, - ) + - suffix; - }); -} - -/** - * Re-writes "hyper-modular" CDK imports (most packages in `@aws-cdk/*`) to the - * relevant "mono" CDK import path. The re-writing will only modify the imported - * library path, presrving the existing quote style, etc... - * - * Syntax errors in the source file being processed may cause some import - * statements to not be re-written. - * - * Supported import statement forms are: - * - `import * as lib from '@aws-cdk/lib';` - * - `import { Type } from '@aws-cdk/lib';` - * - `import '@aws-cdk/lib';` - * - `import lib = require('@aws-cdk/lib');` - * - `import { Type } = require('@aws-cdk/lib'); - * - `require('@aws-cdk/lib'); - * - * @param sourceText the source code where imports should be re-written. - * @param updatedLocation a function that returns the updated location of the import. - * @param fileName a customized file name to provide the TypeScript processor. - * - * @returns the updated source code. - */ -export function rewriteImports( - sourceText: string, - updatedLocation: (modulePath: string, importedElements?: ts.NodeArray) => string | undefined, - fileName: string = 'index.ts', - rewriteConstructsImports: boolean = false, -): string { - const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ES2020, true); - const rewriter = new ImportRewriter(sourceFile, updatedLocation, rewriteConstructsImports); - ts.transform(sourceFile, [rewriter.rewriteTransformer()]); - return rewriter.rewriteImports(); -} - -class ImportRewriter { - private static CONSTRUCTS_TYPES = ['Construct', 'IConstruct']; - - private readonly replacements = new Array<{ original: ts.Node, updatedLocation: string, quoted: boolean }>(); - // Constructs rewrites - private readonly constructsNamedImports: Set = new Set(); - private readonly constructsId = 'constructs'; - private firstImportNode?: ts.Node; - private constructsNamespaceImportRequired: boolean = false; - - public constructor( - private readonly sourceFile: ts.SourceFile, - private readonly updatedLocation: (modulePath: string, importedElements?: ts.NodeArray) => string | undefined, - private readonly rewriteConstructsImports: boolean, - ) { } - - public rewriteTransformer(): ts.TransformerFactory { - const coreNamespaceImports: Set = new Set(); - - return (context) => { - return (sourceFile) => { - const visitor = (node: T): ts.VisitResult => { - const moduleSpecifier = getModuleSpecifier(node); - if (moduleSpecifier) { - return this.visitImportNode(node, coreNamespaceImports, moduleSpecifier); - } - - // Rewrite any access or type references with a format `foo.Construct`, - // where `foo` matches the name of a namespace import for '@aws-cdk/core' - // Simple identifiers (e.g., readonly foo: Construct) do not need to be written, - // only qualified identifiers (e.g., cdk.Construct). - if (ts.isIdentifier(node) && ImportRewriter.CONSTRUCTS_TYPES.includes(node.text)) { - if (ts.isPropertyAccessExpression(node.parent) - && ts.isIdentifier(node.parent.expression) - && coreNamespaceImports.has(node.parent.expression.text)) { - this.replacements.push({ original: node.parent, updatedLocation: `${this.constructsId}.${node.text}`, quoted: false }); - this.constructsNamespaceImportRequired = true; - } else if (ts.isQualifiedName(node.parent) - && ts.isIdentifier(node.parent.left) - && coreNamespaceImports.has(node.parent.left.text)) { - this.replacements.push({ original: node.parent, updatedLocation: `${this.constructsId}.${node.text}`, quoted: false }); - this.constructsNamespaceImportRequired = true; - } - } - - return ts.visitEachChild(node, visitor, context); - }; - - return ts.visitNode(sourceFile, visitor); - }; - }; - } - - /** - * Visit import nodes where a module specifier of some kind has been found. - * - * For most nodes, this simply involves rewritting the location of the module via `this.updatedLocation`. - * - * Assumes the current node is an import (of some type) that imports '@aws-cdk/core'. - * - * The following import types are suported: - * - import * as core1 from '@aws-cdk/core'; - * - import core2 = require('@aws-cdk/core'); - * - import { Type1, Type2 as CoreType2 } from '@aws-cdk/core'; - * - import { Type1, Type2 as CoreType2 } = require('@aws-cdk/core'); - * - * For all namespace imports, capture the namespace used so any references later can be updated. - * For example, 'core1.Construct' needs to be renamed to 'constructs.Construct'. - * For all named imports: - * - If all named imports are constructs types, simply rename the import from core to constructs. - * - If there's a split, the constructs types are removed and captured for later to go into a new import. - * - * @returns true iff all other transforms should be skipped for this node. - */ - private visitImportNode(node: T, coreNamespaceImports: Set, moduleSpecifier: ts.StringLiteral) { - // Used later for constructs imports generation, to mark location and get indentation - if (!this.firstImportNode) { this.firstImportNode = node; } - - // Special-case @aws-cdk/core for the case of constructs imports. - if (this.rewriteConstructsImports && moduleSpecifier.text === '@aws-cdk/core') { - if (ts.isImportEqualsDeclaration(node)) { - // import core = require('@aws-cdk/core'); - coreNamespaceImports.add(node.name.text); - } else if (ts.isImportDeclaration(node) && node.importClause?.namedBindings) { - const bindings = node.importClause?.namedBindings; - if (ts.isNamespaceImport(bindings)) { - // import * as core from '@aws-cdk/core'; - coreNamespaceImports.add(bindings.name.text); - } else if (ts.isNamedImports(bindings)) { - // import { Type1, Type2 as CoreType2 } from '@aws-cdk/core'; - // import { Type1, Type2 as CoreType2 } = require('@aws-cdk/core'); - - // Segment the types into core vs construct types - const constructsImports: ts.ImportSpecifier[] = []; - const coreImports: ts.ImportSpecifier[] = []; - bindings.elements.forEach((e) => { - if (ImportRewriter.CONSTRUCTS_TYPES.includes(e.name.text) || - (e.propertyName && ImportRewriter.CONSTRUCTS_TYPES.includes(e.propertyName.text))) { - constructsImports.push(e); - } else { - coreImports.push(e); - } - }); - - // Three cases: - // 1. There are no constructs imports. No special-casing to do. - // 2. There are ONLY constructs imports. The whole import can be replaced. - // 3. There is a mix. We must remove the constructs imports, and add them to a dedicated line. - if (constructsImports.length > 0) { - if (coreImports.length === 0) { - // Rewrite the module to constructs, skipping the normal updateLocation replacement. - this.replacements.push({ original: moduleSpecifier, updatedLocation: this.constructsId, quoted: true }); - return node; - } else { - // Track these named imports to add to a dedicated import statement later. - constructsImports.forEach((i) => this.constructsNamedImports.add(i)); - - // This replaces the interior of the import statement, between the braces: - // import { Stack as CdkStack, StackProps } ... - const coreBindings = ' ' + coreImports.map((e) => e.getText()).join(', ') + ' '; - this.replacements.push({ original: bindings, updatedLocation: coreBindings, quoted: true }); - } - } - } - } - } - - const newTarget = this.updatedLocation(moduleSpecifier.text, getImportedElements(node)); - if (newTarget != null) { - this.replacements.push({ original: moduleSpecifier, updatedLocation: newTarget, quoted: true }); - } - return node; - } - - /** - * Rewrites the imports -- and possibly some qualified identifiers -- in the source file, - * based on the replacement information gathered via transforming the source through `rewriteTransformer()`. - */ - public rewriteImports(): string { - let updatedSourceText = this.sourceFile.text; - // Applying replacements in reverse order, so node positions remain valid. - const sortedReplacements = this.replacements.sort( - ({ original: l }, { original: r }) => r.getStart(this.sourceFile) - l.getStart(this.sourceFile)); - for (const replacement of sortedReplacements) { - const offset = replacement.quoted ? 1 : 0; - const prefix = updatedSourceText.substring(0, replacement.original.getStart(this.sourceFile) + offset); - const suffix = updatedSourceText.substring(replacement.original.getEnd() - offset); - - updatedSourceText = prefix + replacement.updatedLocation + suffix; - } - - // Lastly, prepend the source with any new constructs imports, as needed. - const constructsImports = this.getConstructsImportsPrefix(); - if (constructsImports) { - const insertionPoint = this.firstImportNode - // Start of the line, past any leading comments or shebang lines - ? (this.firstImportNode.getStart() - this.getNodeIndentation(this.firstImportNode)) - : 0; - updatedSourceText = updatedSourceText.substring(0, insertionPoint) - + constructsImports - + updatedSourceText.substring(insertionPoint); - } - - return updatedSourceText; - } - - /** - * If constructs imports are needed (either namespaced or named types), - * this returns a string with one (or both) imports that can be prepended to the source. - */ - private getConstructsImportsPrefix(): string | undefined { - if (!this.constructsNamespaceImportRequired && this.constructsNamedImports.size === 0) { return undefined; } - - const indentation = ' '.repeat(this.getNodeIndentation(this.firstImportNode)); - let constructsImportPrefix = ''; - if (this.constructsNamespaceImportRequired) { - constructsImportPrefix += `${indentation}import * as ${this.constructsId} from 'constructs';\n`; - } - if (this.constructsNamedImports.size > 0) { - const namedImports = [...this.constructsNamedImports].map(i => i.getText()).join(', '); - constructsImportPrefix += `${indentation}import { ${namedImports} } from 'constructs';\n`; - } - return constructsImportPrefix; - } - - /** - * For a given node, attempts to determine and return how many spaces of indentation are used. - */ - private getNodeIndentation(node?: ts.Node): number { - if (!node) { return 0; } - - // Get leading spaces for the final line in the node's trivia - const fullText = node.getFullText(); - const trivia = fullText.substring(0, fullText.length - node.getWidth()); - const m = /( *)$/.exec(trivia); - return m ? m[1].length : 0; - } -} - -/** - * Returns the module specifier (location) of an import statement in one of the following forms: - * import from 'location'; - * import * as name from 'location'; - * import { Type } from 'location'; - * import { Type } = require('location'); - * import name = require('location'); - * require('location'); - */ -function getModuleSpecifier(node: ts.Node): ts.StringLiteral | undefined { - if (ts.isImportDeclaration(node)) { - // import style - const moduleSpecifier = node.moduleSpecifier; - if (ts.isStringLiteral(moduleSpecifier)) { - // import from 'location'; - // import * as name from 'location'; - // import { Foo } from 'location'; - return moduleSpecifier; - } else if (ts.isBinaryExpression(moduleSpecifier) && ts.isCallExpression(moduleSpecifier.right)) { - // import { Type } = require('location'); - return getModuleSpecifier(moduleSpecifier.right); - } - } else if ( - ts.isImportEqualsDeclaration(node) - && ts.isExternalModuleReference(node.moduleReference) - && ts.isStringLiteral(node.moduleReference.expression) - ) { - // import name = require('location'); - return node.moduleReference.expression; - } else if ( - (ts.isCallExpression(node)) - && ts.isIdentifier(node.expression) - && node.expression.escapedText === 'require' - && node.arguments.length === 1 - ) { - // require('location'); - const argument = node.arguments[0]; - if (ts.isStringLiteral(argument)) { - return argument; - } - } else if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) { - // require('location'); // This is an alternate AST version of it - return getModuleSpecifier(node.expression); - } - return undefined; -} - -const EXEMPTIONS = new Set([ - '@aws-cdk/cloudformation-diff', - // The dev-tools - '@aws-cdk/cdk-build-tools', - '@aws-cdk/cdk-integ-tools', - '@aws-cdk/cfn2ts', - '@aws-cdk/eslint-plugin', - '@aws-cdk/pkglint', -]); - -function updatedExternalLocation( - modulePath: string, - libName: string, - options: RewriteOptions, - importedElements?: ts.NodeArray, -): string | undefined { - const customModulePath = options.customModules?.[modulePath]; - if (customModulePath) { - let awsCdkLibLocation = undefined; - importedElements?.forEach(e => { - if (e.name.text.startsWith('Cfn') || e.propertyName?.text.startsWith('Cfn')) { - // This is an L1 import, so don't return the customModulePath (which is the alpha module). - // Return the relevant aws-cdk-lib location. - awsCdkLibLocation = `${libName}/${modulePath.substring('@aws-cdk/'.length)}`; - } - }); - if (awsCdkLibLocation) { - return awsCdkLibLocation; - } - return customModulePath; - } - - if (options.rewriteCfnImports && modulePath.endsWith(`${options.packageUnscopedName?.slice('aws-'.length)}.generated`)) { - return `${libName}/${options.packageUnscopedName}`; - } - - if ( - !modulePath.startsWith('@aws-cdk/') - || EXEMPTIONS.has(modulePath) - || Array.from(EXEMPTIONS).some((ex) => modulePath.startsWith(`${ex}/`)) - ) { - return undefined; - } - - if (modulePath.startsWith('@aws-cdk/core/lib')) { - return `${libName}/core/lib/${modulePath.substring('@aws-cdk/core/lib/'.length)}`; - } - - if (modulePath === '@aws-cdk/core') { - return libName; - } - - return `${libName}/${modulePath.substring('@aws-cdk/'.length)}`; -} - -/** - * Returns the names of all types imported via named imports of the form: - * import { Type } from 'location' - */ -function getImportedElements(node: ts.Node): ts.NodeArray | undefined { - if ( - ts.isImportDeclaration(node) - && ts.isStringLiteral(node.moduleSpecifier) - && node.importClause - && node.importClause.namedBindings - && ts.isNamedImports(node.importClause.namedBindings) - ) { - return node.importClause.namedBindings.elements; - } - return undefined; -} diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json deleted file mode 100644 index 8a0e1e21fe12b..0000000000000 --- a/packages/aws-cdk-migration/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "aws-cdk-migration", - "version": "0.0.0", - "description": "Rewrites typescript 'import' statements from @aws-cdk/xxx to aws-cdk-lib", - "bin": { - "rewrite-imports-v2": "bin/rewrite-imports-v2" - }, - "main": "lib/rewrite.js", - "types": "lib/rewrite.d.ts", - "scripts": { - "build": "cdk-build", - "watch": "cdk-watch", - "test": "cdk-test", - "lint": "cdk-lint", - "pkglint": "pkglint -f", - "package": "cdk-package", - "build+test+package": "yarn build+test && yarn package", - "build+test": "yarn build && yarn test", - "build+test+extract": "yarn build+test", - "build+extract": "yarn build" - }, - "cdk-build": { - "jest": true - }, - "keywords": [ - "aws", - "cdk", - "awscdk" - ], - "author": { - "name": "Amazon Web Services", - "url": "https://aws.amazon.com", - "organization": true - }, - "license": "Apache-2.0", - "dependencies": { - "glob": "^7.2.3", - "typescript": "~5.1.3" - }, - "devDependencies": { - "@types/glob": "^7.2.0", - "@types/jest": "^29.5.0", - "@aws-cdk/cdk-build-tools": "0.0.0", - "@aws-cdk/pkglint": "0.0.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/aws/aws-cdk.git", - "directory": "packages/aws-cdk-migration" - }, - "homepage": "https://github.com/aws/aws-cdk", - "stability": "experimental", - "engines": { - "node": ">= 14.15.0" - }, - "publishConfig": { - "tag": "next" - }, - "private": true -} diff --git a/packages/aws-cdk-migration/test/rewrite.test.ts b/packages/aws-cdk-migration/test/rewrite.test.ts deleted file mode 100644 index ee45157a2083b..0000000000000 --- a/packages/aws-cdk-migration/test/rewrite.test.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { rewriteMonoPackageImports, rewriteReadmeImports } from '../lib/rewrite'; - -describe(rewriteMonoPackageImports, () => { - test('correctly rewrites naked "import"', () => { - const output = rewriteMonoPackageImports(` - // something before - import '@aws-cdk/aws-s3/hello'; - // something after - - console.log('Look! I did something!');`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - // something before - import 'aws-cdk-lib/aws-s3/hello'; - // something after - - console.log('Look! I did something!');`); - }); - - test('correctly rewrites naked "require"', () => { - const output = rewriteMonoPackageImports(` - // something before - require('@aws-cdk/aws-s3/hello'); - // something after - - console.log('Look! I did something!');`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - // something before - require('aws-cdk-lib/aws-s3/hello'); - // something after - - console.log('Look! I did something!');`); - }); - - test('correctly rewrites "import from"', () => { - const output = rewriteMonoPackageImports(` - // something before - import * as s3 from '@aws-cdk/aws-s3'; - import * as cfndiff from '@aws-cdk/cloudformation-diff'; - import { Stack } from "@aws-cdk/core"; - // something after - - console.log('Look! I did something!');`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - // something before - import * as s3 from 'aws-cdk-lib/aws-s3'; - import * as cfndiff from '@aws-cdk/cloudformation-diff'; - import { Stack } from "aws-cdk-lib"; - // something after - - console.log('Look! I did something!');`); - }); - - test('correctly rewrites "import = require"', () => { - const output = rewriteMonoPackageImports(` - // something before - import s3 = require('@aws-cdk/aws-s3'); - import cfndiff = require('@aws-cdk/cloudformation-diff'); - import { Stack } = require("@aws-cdk/core"); - // something after - - console.log('Look! I did something!');`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - // something before - import s3 = require('aws-cdk-lib/aws-s3'); - import cfndiff = require('@aws-cdk/cloudformation-diff'); - import { Stack } = require("aws-cdk-lib"); - // something after - - console.log('Look! I did something!');`); - }); - - test('correctly rewrites Cfn imports', () => { - // Codestar example - const codestar = rewriteMonoPackageImports(` - // something before - import * as codestar from './codestar.generated'; - import { CfnY } from '../codestar.generated'; - import { CfnX } from '../lib/codestar.generated'; - // something after - - console.log('Look! I did something!');`, 'aws-cdk-lib', 'subject.ts', { - rewriteCfnImports: true, - packageUnscopedName: 'aws-codestar', - }); - - expect(codestar).toBe(` - // something before - import * as codestar from 'aws-cdk-lib/aws-codestar'; - import { CfnY } from 'aws-cdk-lib/aws-codestar'; - import { CfnX } from 'aws-cdk-lib/aws-codestar'; - // something after - - console.log('Look! I did something!');`); - }); - - test('correctly rewrites Cfn imports from an alpha module', () => { - const customModules = { - '@aws-cdk/aws-kinesisfirehose': 'aws-kinesisfirehose-alpha', - }; - const output = rewriteMonoPackageImports(` - // something before - import * as firehose from '@aws-cdk/aws-kinesisfirehose'; - import { CfnDeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; - // something after - - console.log('Look! I did something!');`, 'aws-cdk-lib', 'subject.ts', { - rewriteCfnImports: true, - customModules: customModules, - }); - - expect(output).toBe(` - // something before - import * as firehose from 'aws-kinesisfirehose-alpha'; - import { CfnDeliveryStream } from 'aws-cdk-lib/aws-kinesisfirehose'; - // something after - - console.log('Look! I did something!');`); - }); -}); - -describe(rewriteReadmeImports, () => { - test('parses ts code snippet', () => { - const output = rewriteReadmeImports(` - Some README text. - \`\`\`ts - import * as s3 from '@aws-cdk/aws-s3'; - import { Stack } from "@aws-cdk/core"; - \`\`\` - Some more README text.`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - Some README text. - \`\`\`ts - import * as s3 from 'aws-cdk-lib/aws-s3'; - import { Stack } from "aws-cdk-lib"; - \`\`\` - Some more README text.`); - }); - - test('parses typescript code snippet', () => { - const output = rewriteReadmeImports(` - Some README text. - \`\`\`typescript - import * as s3 from '@aws-cdk/aws-s3'; - import { Stack } from "@aws-cdk/core"; - \`\`\` - Some more README text.`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - Some README text. - \`\`\`typescript - import * as s3 from 'aws-cdk-lib/aws-s3'; - import { Stack } from "aws-cdk-lib"; - \`\`\` - Some more README text.`); - }); - - test('parses text code snippet', () => { - const output = rewriteReadmeImports(` - Some README text. - \`\`\`text - import * as s3 from '@aws-cdk/aws-s3'; - import { Stack } from "@aws-cdk/core"; - \`\`\` - Some more README text.`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - Some README text. - \`\`\`text - import * as s3 from 'aws-cdk-lib/aws-s3'; - import { Stack } from "aws-cdk-lib"; - \`\`\` - Some more README text.`); - }); - - test('ignores non ts|typescript|text code snippet', () => { - const output = rewriteReadmeImports(` - Some README text. - \`\`\`java - import * as s3 from '@aws-cdk/aws-s3'; - \`\`\` - Some more README text.`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - Some README text. - \`\`\`java - import * as s3 from '@aws-cdk/aws-s3'; - \`\`\` - Some more README text.`); - }); - - test('parses multiple snippets', () => { - const output = rewriteReadmeImports(` - Some README text. - \`\`\`ts - import * as s3 from '@aws-cdk/aws-s3'; - \`\`\` - Some more README text. - \`\`\`ts - import { CfnDeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; - \`\`\``, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - Some README text. - \`\`\`ts - import * as s3 from 'aws-cdk-lib/aws-s3'; - \`\`\` - Some more README text. - \`\`\`ts - import { CfnDeliveryStream } from 'aws-cdk-lib/aws-kinesisfirehose'; - \`\`\``); - }); -}); - -describe('constructs imports', () => { - describe('namespace imports', () => { - test('import declaration', () => { - const output = rewriteMonoPackageImports(` - import * as core from '@aws-cdk/core'; - class FooBar extends core.Construct { - private readonly foo: core.Construct; - private doStuff() { return new core.Construct(); } - }`, 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - import * as constructs from 'constructs'; - import * as core from 'aws-cdk-lib'; - class FooBar extends constructs.Construct { - private readonly foo: constructs.Construct; - private doStuff() { return new constructs.Construct(); } - }`); - }); - - test('import equals declaration', () => { - const output = rewriteMonoPackageImports(` - import core = require('@aws-cdk/core'); - class FooBar extends core.Construct { - private readonly foo: core.Construct; - private doStuff() { return new core.Construct(); } - }`, 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - import * as constructs from 'constructs'; - import core = require('aws-cdk-lib'); - class FooBar extends constructs.Construct { - private readonly foo: constructs.Construct; - private doStuff() { return new constructs.Construct(); } - }`); - }); - }); - - describe('named imports', () => { - test('no constructs imports', () => { - const output = rewriteMonoPackageImports(` - import { Stack, StackProps } from '@aws-cdk/core'; - class FooBar extends Stack { }`, - 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - import { Stack, StackProps } from 'aws-cdk-lib'; - class FooBar extends Stack { }`); - }); - - test('all constructs imports', () => { - const output = rewriteMonoPackageImports(` - import { IConstruct, Construct } from '@aws-cdk/core'; - class FooBar implements IConstruct extends Construct { }`, - 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - import { IConstruct, Construct } from 'constructs'; - class FooBar implements IConstruct extends Construct { }`); - }); - - test('mixed constructs and core imports', () => { - const output = rewriteMonoPackageImports(` - import { Stack, Construct, IConstruct, StackProps } from '@aws-cdk/core'; - class FooBar implements IConstruct extends Construct { }`, - 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - import { Construct, IConstruct } from 'constructs'; - import { Stack, StackProps } from 'aws-cdk-lib'; - class FooBar implements IConstruct extends Construct { }`); - }); - }); - - test('exhaustive test', () => { - const output = rewriteMonoPackageImports(` - import * as core1 from '@aws-cdk/core'; - // a comment of some kind - import core2 = require('@aws-cdk/core'); - import { Stack } from '@aws-cdk/core'; - // more comments - import { Construct as CoreConstruct } from '@aws-cdk/core'; - import { IConstruct, Stack, StackProps } from '@aws-cdk/core'; - import * as s3 from '@aws-cdk/aws-s3'; - - class FooBar implements core1.IConstruct { - readonly foo1: core2.Construct; - public static bar1() { return CoreConstruct(); } - public static bar2() { return new class implements IConstruct {}; } - }`, 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - import * as constructs from 'constructs'; - import { IConstruct } from 'constructs'; - import * as core1 from 'aws-cdk-lib'; - // a comment of some kind - import core2 = require('aws-cdk-lib'); - import { Stack } from 'aws-cdk-lib'; - // more comments - import { Construct as CoreConstruct } from 'constructs'; - import { Stack, StackProps } from 'aws-cdk-lib'; - import * as s3 from 'aws-cdk-lib/aws-s3'; - - class FooBar implements constructs.IConstruct { - readonly foo1: constructs.Construct; - public static bar1() { return CoreConstruct(); } - public static bar2() { return new class implements IConstruct {}; } - }`); - }); - - test('does not rewrite constructs imports unless the option is explicitly set', () => { - const output = rewriteMonoPackageImports(` - import * as core1 from '@aws-cdk/core'; - // a comment of some kind - import { Stack } from '@aws-cdk/core'; - // more comments - import { Construct as CoreConstruct } from '@aws-cdk/core'; - import { IConstruct, Stack, StackProps } from '@aws-cdk/core'; - import * as s3 from '@aws-cdk/aws-s3'; - - class FooBar implements core1.IConstruct { - readonly foo1: CoreConstruct; - public static bar2() { return new class implements IConstruct {}; } - }`, 'aws-cdk-lib', 'subject.ts'); - - expect(output).toBe(` - import * as core1 from 'aws-cdk-lib'; - // a comment of some kind - import { Stack } from 'aws-cdk-lib'; - // more comments - import { Construct as CoreConstruct } from 'aws-cdk-lib'; - import { IConstruct, Stack, StackProps } from 'aws-cdk-lib'; - import * as s3 from 'aws-cdk-lib/aws-s3'; - - class FooBar implements core1.IConstruct { - readonly foo1: CoreConstruct; - public static bar2() { return new class implements IConstruct {}; } - }`); - }); - - test('puts constructs imports after shebang lines', () => { - const output = rewriteMonoPackageImports(` - #!/usr/bin/env node - import * as core from '@aws-cdk/core'; - class FooBar extends core.Construct { - private readonly foo: core.Construct; - private doStuff() { return new core.Construct(); } - }`, 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - #!/usr/bin/env node - import * as constructs from 'constructs'; - import * as core from 'aws-cdk-lib'; - class FooBar extends constructs.Construct { - private readonly foo: constructs.Construct; - private doStuff() { return new constructs.Construct(); } - }`); - }); - - test('supports rewriteReadmeImports', () => { - const output = rewriteReadmeImports(` - Some README text. - \`\`\`ts - import * as s3 from '@aws-cdk/aws-s3'; - import * as core from "@aws-cdk/core"; - import { Construct, Stack } from "@aws-cdk/core"; - class Foo extends core.Construct { - public bar() { return new Construct(); } - } - \`\`\` - Some more README text.`, 'aws-cdk-lib', 'subject.ts', { rewriteConstructsImports: true }); - - expect(output).toBe(` - Some README text. - \`\`\`ts - import * as constructs from 'constructs'; - import { Construct } from 'constructs'; - import * as s3 from 'aws-cdk-lib/aws-s3'; - import * as core from "aws-cdk-lib"; - import { Stack } from "aws-cdk-lib"; - class Foo extends constructs.Construct { - public bar() { return new Construct(); } - } - \`\`\` - Some more README text.`); - }); -}); diff --git a/packages/aws-cdk-migration/tsconfig.json b/packages/aws-cdk-migration/tsconfig.json deleted file mode 100644 index e48deb1b6520b..0000000000000 --- a/packages/aws-cdk-migration/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "commonjs", - "lib": ["es2020", "dom"], - "strict": true, - "alwaysStrict": true, - "declaration": true, - "inlineSourceMap": true, - "inlineSources": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "resolveJsonModule": true, - "composite": true, - "incremental": true - }, - "include": [ - "**/*.ts", - "**/*.d.ts" - ], - "exclude": [ - "node_modules" - ] -} -