From ab743faa4d502b77e315620022d1dc8b297edcdc Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 16:22:24 -0500 Subject: [PATCH 1/8] user-input-gen --- tools/@aws-cdk/user-input-gen/.eslintrc.js | 3 + tools/@aws-cdk/user-input-gen/.gitignore | 18 ++ tools/@aws-cdk/user-input-gen/.npmignore | 7 + tools/@aws-cdk/user-input-gen/LICENSE | 201 ++++++++++++ tools/@aws-cdk/user-input-gen/NOTICE | 2 + tools/@aws-cdk/user-input-gen/README.md | 26 ++ tools/@aws-cdk/user-input-gen/jest.config.js | 10 + .../lib/convert-to-user-input-gen.ts | 105 ++++++ tools/@aws-cdk/user-input-gen/lib/index.ts | 4 + .../user-input-gen/lib/user-input-gen.ts | 158 +++++++++ tools/@aws-cdk/user-input-gen/lib/util.ts | 34 ++ .../@aws-cdk/user-input-gen/lib/yargs-gen.ts | 175 ++++++++++ .../user-input-gen/lib/yargs-types.ts | 52 +++ tools/@aws-cdk/user-input-gen/package.json | 59 ++++ .../test/convert-to-user-input-gen.test.ts | 82 +++++ .../test/user-input-gen.test.ts | 305 ++++++++++++++++++ .../user-input-gen/test/yargs-gen.test.ts | 222 +++++++++++++ tools/@aws-cdk/user-input-gen/tsconfig.json | 21 ++ 18 files changed, 1484 insertions(+) create mode 100644 tools/@aws-cdk/user-input-gen/.eslintrc.js create mode 100644 tools/@aws-cdk/user-input-gen/.gitignore create mode 100644 tools/@aws-cdk/user-input-gen/.npmignore create mode 100644 tools/@aws-cdk/user-input-gen/LICENSE create mode 100644 tools/@aws-cdk/user-input-gen/NOTICE create mode 100644 tools/@aws-cdk/user-input-gen/README.md create mode 100644 tools/@aws-cdk/user-input-gen/jest.config.js create mode 100644 tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts create mode 100644 tools/@aws-cdk/user-input-gen/lib/index.ts create mode 100644 tools/@aws-cdk/user-input-gen/lib/user-input-gen.ts create mode 100644 tools/@aws-cdk/user-input-gen/lib/util.ts create mode 100644 tools/@aws-cdk/user-input-gen/lib/yargs-gen.ts create mode 100644 tools/@aws-cdk/user-input-gen/lib/yargs-types.ts create mode 100644 tools/@aws-cdk/user-input-gen/package.json create mode 100644 tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts create mode 100644 tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts create mode 100644 tools/@aws-cdk/user-input-gen/test/yargs-gen.test.ts create mode 100644 tools/@aws-cdk/user-input-gen/tsconfig.json diff --git a/tools/@aws-cdk/user-input-gen/.eslintrc.js b/tools/@aws-cdk/user-input-gen/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/tools/@aws-cdk/user-input-gen/.gitignore b/tools/@aws-cdk/user-input-gen/.gitignore new file mode 100644 index 0000000000000..39180f6eb0bb4 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/.gitignore @@ -0,0 +1,18 @@ +# Build files +*.js +node_modules +*.js.map +*.d.ts +lib/services + +# Test artifacts +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +*.snk +junit.xml + +# Keep configs +!.eslintrc.js +!jest.config.js diff --git a/tools/@aws-cdk/user-input-gen/.npmignore b/tools/@aws-cdk/user-input-gen/.npmignore new file mode 100644 index 0000000000000..79f3b5a763216 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/.npmignore @@ -0,0 +1,7 @@ + +.LAST_BUILD +*.snk +junit.xml +.eslintrc.js +# exclude cdk artifacts +**/cdk.out \ No newline at end of file diff --git a/tools/@aws-cdk/user-input-gen/LICENSE b/tools/@aws-cdk/user-input-gen/LICENSE new file mode 100644 index 0000000000000..5ccf0c6780bab --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/LICENSE @@ -0,0 +1,201 @@ + 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-2025 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/tools/@aws-cdk/user-input-gen/NOTICE b/tools/@aws-cdk/user-input-gen/NOTICE new file mode 100644 index 0000000000000..cd0946c1cf193 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/tools/@aws-cdk/user-input-gen/README.md b/tools/@aws-cdk/user-input-gen/README.md new file mode 100644 index 0000000000000..1bf6701f61e4d --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/README.md @@ -0,0 +1,26 @@ +# user-input-gen + +Generates CDK CLI configurations from the source of truth in `packages/aws-cdk/lib/config.ts`. +Currently generates the following files: + +- `packages/aws-cdk/lib/parse-command-line-arguments.ts`: `yargs` config. +- `packages/aws-cdk/lib/user-input.ts`: strongly typed `UserInput` interface. +- `packages/aws-cdk/lib/convert-to-user-inpu.ts`: converts input from the CLI or `cdk.json` into `UserInput`. + +## Usage + +```ts +import { renderYargs } from '@aws-cdk/user-input-gen'; + +declare const config: CliConfig; + +fs.writeFileSync('./lib/parse-command-line-arguments.ts', await renderYargs(config)); +``` + +This package exports `renderYargs()`, which accepts the CLI command config as input and returns the yargs definition for it as a string. + +### Dynamic Values + +Some values must be computed at runtime, when a command is run. This is achieved with dynamic values; +if the framework sees a CLI option with a `dynamicValue`, then the framework will reference the corresponding parameter. +We should automatically generate the parameter definitions, instead of manually adding them, in the future. diff --git a/tools/@aws-cdk/user-input-gen/jest.config.js b/tools/@aws-cdk/user-input-gen/jest.config.js new file mode 100644 index 0000000000000..696b3d5b6e281 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); + +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + branches: 30, + }, + }, +}; diff --git a/tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts b/tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts new file mode 100644 index 0000000000000..77c693795d048 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts @@ -0,0 +1,105 @@ +import { code, FreeFunction, Module, SelectiveModuleImport, Type, TypeScriptRenderer } from '@cdklabs/typewriter'; +import { EsLintRules } from '@cdklabs/typewriter/lib/eslint-rules'; +import * as prettier from 'prettier'; +import { kebabToCamelCase } from './util'; +import { CliAction, CliConfig } from './yargs-types'; + +export async function renderUserInputFuncs(config: CliConfig): Promise { + const scope = new Module('aws-cdk'); + + scope.documentation.push( '-------------------------------------------------------------------------------------------'); + scope.documentation.push('GENERATED FROM packages/aws-cdk/lib/config.ts.'); + scope.documentation.push('Do not edit by hand; all changes will be overwritten at build time from the config file.'); + scope.documentation.push('-------------------------------------------------------------------------------------------'); + + scope.addImport(new SelectiveModuleImport(scope, './user-input', ['UserInput', 'GlobalOptions'])); + const userInputType = Type.fromName(scope, 'UserInput'); + + scope.addImport(new SelectiveModuleImport(scope, './settings', ['Command'])); + + const convertYargsToUserInput = new FreeFunction(scope, { + name: 'convertYargsToUserInput', + export: true, + returnType: userInputType, + parameters: [ + { name: 'args', type: Type.ANY }, + ], + }); + convertYargsToUserInput.addBody(code.expr.directCode(buildYargsToUserInputFunction(config))); + + const ts = new TypeScriptRenderer({ + disabledEsLintRules: [EsLintRules.MAX_LEN], // the default disabled rules result in 'Definition for rule 'prettier/prettier' was not found' + }).render(scope); + + return prettier.format(ts, { + parser: 'typescript', + printWidth: 150, + singleQuote: true, + quoteProps: 'consistent', + }); +} + +function buildYargsToUserInputFunction(config: CliConfig): string { + const globalOptions = buildGlobalOptions(config); + const commandSwitch = buildCommandSwitch(config); + const userInput = buildUserInput(); + return [ + globalOptions, + commandSwitch, + userInput, + ].join('\n'); +} + +function buildGlobalOptions(config: CliConfig): string { + const globalOptionExprs = ['const globalOptions: GlobalOptions = {']; + for (const optionName of Object.keys(config.globalOptions)) { + const name = kebabToCamelCase(optionName); + globalOptionExprs.push(`'${name}': args.${name},`); + } + globalOptionExprs.push('}'); + return globalOptionExprs.join('\n'); +} + +function buildCommandSwitch(config: CliConfig): string { + const commandSwitchExprs = ['let commandOptions;', 'switch (args._[0] as Command) {']; + for (const commandName of Object.keys(config.commands)) { + commandSwitchExprs.push( + `case '${commandName}':`, + 'commandOptions = {', + ...buildCommandOptions(config.commands[commandName]), + ...(config.commands[commandName].arg ? [buildPositionalArguments(config.commands[commandName].arg)] : []), + '};', + `break; + `); + } + commandSwitchExprs.push('}'); + return commandSwitchExprs.join('\n'); +} + +function buildCommandOptions(options: CliAction): string[] { + const commandOptions: string[] = []; + for (const optionName of Object.keys(options.options ?? {})) { + const name = kebabToCamelCase(optionName); + commandOptions.push(`'${name}': args.${name},`); + } + return commandOptions; +} + +function buildPositionalArguments(arg: { name: string; variadic: boolean }): string { + if (arg.variadic) { + return `${arg.name}: args.${arg.name}`; + } + return `${arg.name}: args.${arg.name}`; +} + +function buildUserInput(): string { + return [ + 'const userInput: UserInput = {', + '_: args._[0],', + 'globalOptions,', + '[args._[0]]: commandOptions', + '}', + '', + 'return userInput', + ].join('\n'); +} diff --git a/tools/@aws-cdk/user-input-gen/lib/index.ts b/tools/@aws-cdk/user-input-gen/lib/index.ts new file mode 100644 index 0000000000000..be47e3278f75e --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/lib/index.ts @@ -0,0 +1,4 @@ +export * from './yargs-gen'; +export * from './yargs-types'; +export * from './user-input-gen'; +export * from './convert-to-user-input-gen'; diff --git a/tools/@aws-cdk/user-input-gen/lib/user-input-gen.ts b/tools/@aws-cdk/user-input-gen/lib/user-input-gen.ts new file mode 100644 index 0000000000000..70bf24a351ce2 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/lib/user-input-gen.ts @@ -0,0 +1,158 @@ +import { Module, SelectiveModuleImport, StructType, Type, TypeScriptRenderer } from '@cdklabs/typewriter'; +import { EsLintRules } from '@cdklabs/typewriter/lib/eslint-rules'; +import * as prettier from 'prettier'; +import { generateDefault, kebabToCamelCase, kebabToPascal } from './util'; +import { CliConfig } from './yargs-types'; + +export async function renderUserInputType(config: CliConfig): Promise { + const scope = new Module('aws-cdk'); + + scope.documentation.push( '-------------------------------------------------------------------------------------------'); + scope.documentation.push('GENERATED FROM packages/aws-cdk/lib/config.ts.'); + scope.documentation.push('Do not edit by hand; all changes will be overwritten at build time from the config file.'); + scope.documentation.push('-------------------------------------------------------------------------------------------'); + + const userInputType = new StructType(scope, { + export: true, + name: 'UserInput', + docs: { + summary: 'The structure of the user input -- either CLI options or cdk.json -- generated from packages/aws-cdk/lib/config.ts', + }, + }); + + // add required command + scope.addImport(new SelectiveModuleImport(scope, './settings', ['Command'])); + const commandEnum = Type.fromName(scope, 'Command'); + + userInputType.addProperty({ + name: '_', + type: commandEnum, + docs: { + summary: 'The CLI command name', + }, + }); + + // add global options + const globalOptionType = new StructType(scope, { + export: true, + name: 'GlobalOptions', + docs: { + summary: 'Global options available to all CLI commands', + }, + }); + for (const [optionName, option] of Object.entries(config.globalOptions)) { + globalOptionType.addProperty({ + name: kebabToCamelCase(optionName), + type: convertType(option.type, option.count), + docs: { + default: normalizeDefault(option.default, option.type), + summary: option.desc, + deprecated: option.deprecated ? String(option.deprecated) : undefined, + }, + optional: true, + }); + } + + userInputType.addProperty({ + name: 'globalOptions', + type: Type.fromName(scope, globalOptionType.name), + docs: { + summary: 'Global options available to all CLI commands', + }, + optional: true, + }); + + // add command-specific options + for (const [commandName, command] of Object.entries(config.commands)) { + const commandType = new StructType(scope, { + export: true, + name: `${kebabToPascal(commandName)}Options`, + docs: { + summary: command.description, + remarks: command.aliases ? `aliases: ${command.aliases.join(' ')}` : undefined, + }, + }); + + // add command level options + for (const [optionName, option] of Object.entries(command.options ?? {})) { + commandType.addProperty({ + name: kebabToCamelCase(optionName), + type: convertType(option.type, option.count), + docs: { + // Notification Arns is a special property where undefined and [] mean different things + default: optionName === 'notification-arns' ? 'undefined' : normalizeDefault(option.default, option.type), + summary: option.desc, + deprecated: option.deprecated ? String(option.deprecated) : undefined, + remarks: option.alias ? `aliases: ${Array.isArray(option.alias) ? option.alias.join(' ') : option.alias}` : undefined, + }, + optional: true, + }); + } + + // add positional argument associated with the command + if (command.arg) { + commandType.addProperty({ + name: command.arg.name, + type: command.arg.variadic ? Type.arrayOf(Type.STRING) : Type.STRING, + docs: { + summary: `Positional argument for ${commandName}`, + }, + optional: true, + }); + } + + userInputType.addProperty({ + name: kebabToCamelCase(commandName), + type: Type.fromName(scope, commandType.name), + docs: { + summary: command.description, + remarks: command.aliases ? `aliases: ${command.aliases.join(' ')}` : undefined, + }, + optional: true, + }); + } + + const ts = new TypeScriptRenderer({ + disabledEsLintRules: [EsLintRules.MAX_LEN], // the default disabled rules result in 'Definition for rule 'prettier/prettier' was not found' + }).render(scope); + + return prettier.format(ts, { + parser: 'typescript', + printWidth: 150, + singleQuote: true, + quoteProps: 'consistent', + }); +} + +function convertType(type: 'string' | 'array' | 'number' | 'boolean' | 'count', count?: boolean): Type { + switch (type) { + case 'boolean': + return count ? Type.NUMBER : Type.BOOLEAN; + case 'string': + return Type.STRING; + case 'number': + return Type.NUMBER; + case 'array': + return Type.arrayOf(Type.STRING); + case 'count': + return Type.NUMBER; + } +} + +function normalizeDefault(defaultValue: any, type: string): string { + switch (typeof defaultValue) { + case 'boolean': + case 'string': + case 'number': + case 'object': + return JSON.stringify(defaultValue); + + // In these cases we cannot use the given defaultValue, so we then check the type + // of the option to determine the default value + case 'undefined': + case 'function': + default: + const generatedDefault = generateDefault(type); + return generatedDefault ? JSON.stringify(generatedDefault) : 'undefined'; + } +} diff --git a/tools/@aws-cdk/user-input-gen/lib/util.ts b/tools/@aws-cdk/user-input-gen/lib/util.ts new file mode 100644 index 0000000000000..6d7d050315738 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/lib/util.ts @@ -0,0 +1,34 @@ +import { code, Expression } from '@cdklabs/typewriter'; + +export function generateDefault(type: string) { + return type === 'array' ? [] : undefined; +} + +export function lit(value: any): Expression { + switch (value) { + case undefined: + return code.expr.UNDEFINED; + case null: + return code.expr.NULL; + default: + return code.expr.lit(value); + } +} + +export function kebabToCamelCase(str: string): string { + return str + .split('-') + .map((word, index) => + index === 0 + ? word.toLowerCase() + : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(), + ) + .join(''); +} + +export function kebabToPascal(str: string): string { + return str + .split('-') + .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(''); +} diff --git a/tools/@aws-cdk/user-input-gen/lib/yargs-gen.ts b/tools/@aws-cdk/user-input-gen/lib/yargs-gen.ts new file mode 100644 index 0000000000000..89fdbe4523cb1 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/lib/yargs-gen.ts @@ -0,0 +1,175 @@ +import { $E, Expression, ExternalModule, FreeFunction, IScope, Module, SelectiveModuleImport, Statement, ThingSymbol, Type, TypeScriptRenderer, code, expr } from '@cdklabs/typewriter'; +import { EsLintRules } from '@cdklabs/typewriter/lib/eslint-rules'; +import * as prettier from 'prettier'; +import { generateDefault, lit } from './util'; +import { CliConfig, CliOption, YargsOption } from './yargs-types'; + +// to import lodash.clonedeep properly, we would need to set esModuleInterop: true +// however that setting does not work in the CLI, so we fudge it. +// eslint-disable-next-line @typescript-eslint/no-require-imports +const cloneDeep = require('lodash.clonedeep'); + +export class CliHelpers extends ExternalModule { + public readonly browserForPlatform = makeCallableExpr(this, 'browserForPlatform'); + public readonly cliVersion = makeCallableExpr(this, 'cliVersion'); + public readonly isCI = makeCallableExpr(this, 'isCI'); + public readonly yargsNegativeAlias = makeCallableExpr(this, 'yargsNegativeAlias'); +} + +function makeCallableExpr(scope: IScope, name: string) { + return $E(expr.sym(new ThingSymbol(name, scope))); +} + +export async function renderYargs(config: CliConfig, helpers: CliHelpers): Promise { + const scope = new Module('aws-cdk'); + + scope.documentation.push( '-------------------------------------------------------------------------------------------'); + scope.documentation.push('GENERATED FROM packages/aws-cdk/lib/config.ts.'); + scope.documentation.push('Do not edit by hand; all changes will be overwritten at build time from the config file.'); + scope.documentation.push('-------------------------------------------------------------------------------------------'); + + scope.addImport(new SelectiveModuleImport(scope, 'yargs', ['Argv'])); + helpers.import(scope, 'helpers'); + + // 'https://github.com/yargs/yargs/issues/1929', + // 'https://github.com/evanw/esbuild/issues/1492', + scope.addInitialization(code.comment('eslint-disable-next-line @typescript-eslint/no-require-imports')); + scope.addInitialization(code.stmt.constVar(code.expr.ident('yargs'), code.expr.directCode("require('yargs')"))); + + const parseCommandLineArguments = new FreeFunction(scope, { + name: 'parseCommandLineArguments', + export: true, + returnType: Type.ANY, + parameters: [ + { name: 'args', type: Type.arrayOf(Type.STRING) }, + ], + }); + parseCommandLineArguments.addBody(makeYargs(config, helpers)); + + const ts = new TypeScriptRenderer({ + disabledEsLintRules: [EsLintRules.MAX_LEN], // the default disabled rules result in 'Definition for rule 'prettier/prettier' was not found' + }).render(scope); + + return prettier.format(ts, { + parser: 'typescript', + printWidth: 150, + singleQuote: true, + trailingComma: 'all', + }); +} + +// Use the following configuration for array arguments: +// +// { type: 'array', default: [], nargs: 1, requiresArg: true } +// +// The default behavior of yargs is to eat all strings following an array argument: +// +// ./prog --arg one two positional => will parse to { arg: ['one', 'two', 'positional'], _: [] } (so no positional arguments) +// ./prog --arg one two -- positional => does not help, for reasons that I can't understand. Still gets parsed incorrectly. +// +// By using the config above, every --arg will only consume one argument, so you can do the following: +// +// ./prog --arg one --arg two position => will parse to { arg: ['one', 'two'], _: ['positional'] }. +function makeYargs(config: CliConfig, helpers: CliHelpers): Statement { + let yargsExpr: Expression = code.expr.ident('yargs'); + yargsExpr = yargsExpr + .callMethod('env', lit('CDK')) + .callMethod('usage', lit('Usage: cdk -a COMMAND')); + + // we must compute global options first, as they are not part of an argument to a command call + yargsExpr = makeOptions(yargsExpr, config.globalOptions, helpers); + + for (const command of Object.keys(config.commands)) { + const commandFacts = config.commands[command]; + const commandArg = commandFacts.arg + ? ` [${commandFacts.arg?.name}${commandFacts.arg?.variadic ? '..' : ''}]` + : ''; + const aliases = commandFacts.aliases + ? commandFacts.aliases.map((alias) => `, '${alias}${commandArg}'`) + : ''; + + // must compute options before we compute the full command, because in yargs, the options are an argument to the command call. + let optionsExpr: Expression = code.expr.directCode('(yargs: Argv) => yargs'); + optionsExpr = makeOptions(optionsExpr, commandFacts.options ?? {}, helpers); + + const commandCallArgs: Array = []; + if (aliases) { + commandCallArgs.push(code.expr.directCode(`['${command}${commandArg}'${aliases}]`)); + } else { + commandCallArgs.push(code.expr.directCode(`'${command}${commandArg}'`)); + } + commandCallArgs.push(lit(commandFacts.description)); + + if (commandFacts.options) { + commandCallArgs.push(optionsExpr); + } + + yargsExpr = yargsExpr.callMethod('command', ...commandCallArgs); + } + + return code.stmt.ret(makeEpilogue(yargsExpr, helpers)); +} + +function makeOptions(prefix: Expression, options: { [optionName: string]: CliOption }, helpers: CliHelpers) { + let optionsExpr = prefix; + for (const option of Object.keys(options)) { + const theOption: CliOption = { + // Make the default explicit (overridden if the option includes an actual default) + // 'notification-arns' is a special snowflake that should be defaulted to 'undefined', but https://github.com/yargs/yargs/issues/2443 + // prevents us from doing so. This should be changed if the issue is resolved. + ...(option === 'notification-arns' ? {} : { default: generateDefault(options[option].type) }), + ...options[option], + }; + const optionProps: YargsOption = cloneDeep(theOption); + const optionArgs: { [key: string]: Expression } = {}; + + // Array defaults + if (optionProps.type === 'array') { + optionProps.nargs = 1; + optionProps.requiresArg = true; + } + + for (const optionProp of Object.keys(optionProps).filter(opt => !['negativeAlias'].includes(opt))) { + const optionValue = (optionProps as any)[optionProp]; + if (optionValue instanceof Expression) { + optionArgs[optionProp] = optionValue; + } else { + optionArgs[optionProp] = lit(optionValue); + } + } + + // Register the option with yargs + optionsExpr = optionsExpr.callMethod('option', lit(option), code.expr.object(optionArgs)); + + // Special case for negativeAlias + // We need an additional option and a middleware: + // .option('R', { type: 'boolean', hidden: true }).middleware(yargsNegativeAlias('R', 'rollback'), true) + if (theOption.negativeAlias) { + const middleware = helpers.yargsNegativeAlias.call(lit(theOption.negativeAlias), lit(option)); + optionsExpr = optionsExpr.callMethod('option', lit(theOption.negativeAlias), code.expr.lit({ + type: 'boolean', + hidden: true, + })); + optionsExpr = optionsExpr.callMethod('middleware', middleware, lit(true)); + } + } + + return optionsExpr; +} + +function makeEpilogue(prefix: Expression, helpers: CliHelpers) { + let completeDefinition = prefix.callMethod('version', helpers.cliVersion()); + completeDefinition = completeDefinition.callMethod('demandCommand', lit(1), lit('')); // just print help + completeDefinition = completeDefinition.callMethod('recommendCommands'); + completeDefinition = completeDefinition.callMethod('help'); + completeDefinition = completeDefinition.callMethod('alias', lit('h'), lit('help')); + completeDefinition = completeDefinition.callMethod('epilogue', lit([ + 'If your app has a single stack, there is no need to specify the stack name', + 'If one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', + ].join('\n\n'))); + + completeDefinition = completeDefinition.callMethod('parse', code.expr.ident('args')); + + return completeDefinition; +} + diff --git a/tools/@aws-cdk/user-input-gen/lib/yargs-types.ts b/tools/@aws-cdk/user-input-gen/lib/yargs-types.ts new file mode 100644 index 0000000000000..91c23b288cd04 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/lib/yargs-types.ts @@ -0,0 +1,52 @@ +interface YargsCommand { + description: string; + options?: { [optionName: string]: YargsOption }; + aliases?: string[]; + arg?: YargsArg; +} + +export interface CliAction extends YargsCommand { + options?: { [optionName: string]: CliOption }; +} + +interface YargsArg { + name: string; + variadic: boolean; +} + +export interface YargsOption { + type: 'string' | 'array' | 'number' | 'boolean' | 'count'; + desc?: string; + default?: any; + deprecated?: boolean | string; + choices?: ReadonlyArray; + alias?: string | string[]; + conflicts?: string | readonly string[] | { [key: string]: string | readonly string[] }; + nargs?: number; + requiresArg?: boolean; + hidden?: boolean; + count?: boolean; +} + +export interface CliOption extends Omit { + negativeAlias?: string; +} + +export interface Middleware { + callback: string; + args: string[]; + applyBeforeValidation?: boolean; +} + +export interface CliConfig { + globalOptions: { [optionName: string]: CliOption }; + commands: { [commandName: string]: CliAction }; +} + +/** + * The result of a DynamicValue call + */ +export interface DynamicResult { + dynamicType: 'parameter' | 'function'; + dynamicValue: string; +} diff --git a/tools/@aws-cdk/user-input-gen/package.json b/tools/@aws-cdk/user-input-gen/package.json new file mode 100644 index 0000000000000..53444e58fbfac --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/package.json @@ -0,0 +1,59 @@ +{ + "name": "@aws-cdk/user-input-gen", + "private": true, + "version": "0.0.0", + "description": "Generate User Inputs", + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "tools/@aws-cdk/user-input-gen" + }, + "main": "./lib/index.js", + "types": "./lib/index.d.ts", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "pkglint": "pkglint -f", + "build+test": "yarn build && yarn test", + "build+extract": "yarn build", + "build+test+extract": "yarn build+test", + "build+test+package": "yarn build+test" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "dependencies": { + "@cdklabs/typewriter": "^0.0.5", + "lodash.clonedeep": "^4.5.0", + "prettier": "^2.8.8" + }, + "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^29.5.12", + "@types/lodash.clonedeep": "^4.5.0", + "@types/node": "^18", + "jest": "^29.7.0" + }, + "keywords": [ + "aws", + "cdk" + ], + "homepage": "https://github.com/aws/aws-cdk", + "engines": { + "node": ">= 14.15.0" + }, + "ubergen": { + "exclude": true + }, + "pkglint": { + "exclude": [ + "dependencies/cdk-point-dependencies" + ] + } +} diff --git a/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts b/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts new file mode 100644 index 0000000000000..327a106c1ff9b --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts @@ -0,0 +1,82 @@ +import { CliConfig, renderUserInputFuncs } from '../lib'; + +describe('render', () => { + test('can generate conversion function', async () => { + const config: CliConfig = { + globalOptions: { + app: { + type: 'string', + desc: 'REQUIRED: Command-line for executing your app', + }, + debug: { + type: 'boolean', + desc: 'Enable debug logging', + default: false, + }, + context: { + default: [], + type: 'array', + alias: 'c', + desc: 'context values', + }, + plugin: { + type: 'array', + desc: 'plugins to load', + }, + }, + commands: { + deploy: { + arg: { + name: 'STACKS', + variadic: true, + }, + description: 'Deploy a stack', + options: { + all: { + type: 'boolean', + desc: 'Deploy all stacks', + default: false, + }, + }, + }, + }, + }; + + expect(await renderUserInputFuncs(config)).toMatchInlineSnapshot(` + "// ------------------------------------------------------------------------------------------- + // GENERATED FROM packages/aws-cdk/lib/config.ts. + // Do not edit by hand; all changes will be overwritten at build time from the config file. + // ------------------------------------------------------------------------------------------- + /* eslint-disable @stylistic/max-len */ + import { CliArguments, GlobalOptions } from './cli-arguments'; + import { Command } from './settings'; + + // @ts-ignore TS6133 + export function convertToCliArgs(args: any): CliArguments { + const globalOptions: GlobalOptions = { + app: args.app, + debug: args.debug, + context: args.context, + plugin: args.plugin, + }; + let commandOptions; + switch (args._[0] as Command) { + case 'deploy': + commandOptions = { + all: args.all, + STACKS: args.STACKS, + }; + break; + } + const cliArguments: CliArguments = { + _: args._[0], + globalOptions, + [args._[0]]: commandOptions, + }; + + return cliArguments; + } + " + `); + }); +}); diff --git a/tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts b/tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts new file mode 100644 index 0000000000000..9cc216f8a9254 --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts @@ -0,0 +1,305 @@ +import { CliConfig, renderUserInputType } from '../lib'; + +describe('render', () => { + test('can generate UserInput type', async () => { + const config: CliConfig = { + globalOptions: { + app: { + type: 'string', + desc: 'REQUIRED: Command-line for executing your app', + }, + debug: { + type: 'boolean', + desc: 'Enable debug logging', + default: false, + }, + verbose: { + type: 'boolean', + count: true, + desc: 'Increase logging verbosity', + }, + context: { + default: [], + type: 'array', + alias: 'c', + desc: 'context values', + }, + plugin: { + type: 'array', + desc: 'plugins to load', + }, + }, + commands: { + deploy: { + description: 'Deploy a stack', + options: { + all: { + type: 'boolean', + desc: 'Deploy all stacks', + default: false, + }, + }, + }, + }, + }; + + expect(await renderUserInputType(config)).toMatchInlineSnapshot(` + "// ------------------------------------------------------------------------------------------- + // GENERATED FROM packages/aws-cdk/lib/config.ts. + // Do not edit by hand; all changes will be overwritten at build time from the config file. + // ------------------------------------------------------------------------------------------- + /* eslint-disable @stylistic/max-len */ + import { Command } from './settings'; + + /** + * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts + * + * @struct + */ + export interface CliArguments { + /** + * The CLI command name + */ + readonly _: Command; + + /** + * Global options available to all CLI commands + */ + readonly globalOptions?: GlobalOptions; + + /** + * Deploy a stack + */ + readonly deploy?: DeployOptions; + } + + /** + * Global options available to all CLI commands + * + * @struct + */ + export interface GlobalOptions { + /** + * REQUIRED: Command-line for executing your app + * + * @default - undefined + */ + readonly app?: string; + + /** + * Enable debug logging + * + * @default - false + */ + readonly debug?: boolean; + + /** + * Increase logging verbosity + * + * @default - undefined + */ + readonly verbose?: number; + + /** + * context values + * + * @default - [] + */ + readonly context?: Array; + + /** + * plugins to load + * + * @default - [] + */ + readonly plugin?: Array; + } + + /** + * Deploy a stack + * + * @struct + */ + export interface DeployOptions { + /** + * Deploy all stacks + * + * @default - false + */ + readonly all?: boolean; + } + " + `); + }); + + test('special notification-arn option gets undefined default', async () => { + const config: CliConfig = { + commands: { + deploy: { + description: 'Notification Arns', + options: { + ['notification-arns']: { + type: 'array', + desc: 'Deploy all stacks', + }, + ['other-array']: { + type: 'array', + desc: 'Other array', + }, + }, + }, + }, + globalOptions: {}, + }; + + expect(await renderUserInputType(config)).toMatchInlineSnapshot(` + "// ------------------------------------------------------------------------------------------- + // GENERATED FROM packages/aws-cdk/lib/config.ts. + // Do not edit by hand; all changes will be overwritten at build time from the config file. + // ------------------------------------------------------------------------------------------- + /* eslint-disable @stylistic/max-len */ + import { Command } from './settings'; + + /** + * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts + * + * @struct + */ + export interface CliArguments { + /** + * The CLI command name + */ + readonly _: Command; + + /** + * Global options available to all CLI commands + */ + readonly globalOptions?: GlobalOptions; + + /** + * Notification Arns + */ + readonly deploy?: DeployOptions; + } + + /** + * Global options available to all CLI commands + * + * @struct + */ + export interface GlobalOptions {} + + /** + * Notification Arns + * + * @struct + */ + export interface DeployOptions { + /** + * Deploy all stacks + * + * @default - undefined + */ + readonly notificationArns?: Array; + + /** + * Other array + * + * @default - [] + */ + readonly otherArray?: Array; + } + " + `); + }); + + test('positional arguments', async () => { + const config: CliConfig = { + commands: { + deploy: { + arg: { + name: 'STACKS', + variadic: true, + }, + description: 'deploy', + }, + acknowledge: { + arg: { + name: 'ID', + variadic: false, + }, + description: 'acknowledge', + }, + }, + globalOptions: {}, + }; + + expect(await renderUserInputType(config)).toMatchInlineSnapshot(` + "// ------------------------------------------------------------------------------------------- + // GENERATED FROM packages/aws-cdk/lib/config.ts. + // Do not edit by hand; all changes will be overwritten at build time from the config file. + // ------------------------------------------------------------------------------------------- + /* eslint-disable @stylistic/max-len */ + import { Command } from './settings'; + + /** + * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts + * + * @struct + */ + export interface CliArguments { + /** + * The CLI command name + */ + readonly _: Command; + + /** + * Global options available to all CLI commands + */ + readonly globalOptions?: GlobalOptions; + + /** + * deploy + */ + readonly deploy?: DeployOptions; + + /** + * acknowledge + */ + readonly acknowledge?: AcknowledgeOptions; + } + + /** + * Global options available to all CLI commands + * + * @struct + */ + export interface GlobalOptions {} + + /** + * deploy + * + * @struct + */ + export interface DeployOptions { + /** + * Positional argument for deploy + */ + readonly STACKS?: Array; + } + + /** + * acknowledge + * + * @struct + */ + export interface AcknowledgeOptions { + /** + * Positional argument for acknowledge + */ + readonly ID?: string; + } + " + `); + }); +}); diff --git a/tools/@aws-cdk/user-input-gen/test/yargs-gen.test.ts b/tools/@aws-cdk/user-input-gen/test/yargs-gen.test.ts new file mode 100644 index 0000000000000..75540361fcc3a --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/test/yargs-gen.test.ts @@ -0,0 +1,222 @@ +import { $E, expr, ThingSymbol } from '@cdklabs/typewriter'; +import { CliConfig, CliHelpers, renderYargs } from '../lib'; + +const YARGS_HELPERS = new CliHelpers('./util/yargs-helpers'); + +describe('render', () => { + test('can generate global options', async () => { + const config: CliConfig = { + globalOptions: { + one: { + type: 'string', + alias: 'o', + desc: 'text for one', + requiresArg: true, + }, + two: { type: 'number', desc: 'text for two' }, + three: { + type: 'array', + alias: 't', + desc: 'text for three', + }, + }, + commands: {}, + }; + + expect(await renderYargs(config, YARGS_HELPERS)).toMatchInlineSnapshot(` + "// ------------------------------------------------------------------------------------------- + // GENERATED FROM packages/aws-cdk/lib/config.ts. + // Do not edit by hand; all changes will be overwritten at build time from the config file. + // ------------------------------------------------------------------------------------------- + /* eslint-disable @stylistic/max-len */ + import { Argv } from 'yargs'; + import * as helpers from './util/yargs-helpers'; + + // @ts-ignore TS6133 + export function parseCommandLineArguments(args: Array): any { + return yargs + .env('CDK') + .usage('Usage: cdk -a COMMAND') + .option('one', { + default: undefined, + type: 'string', + alias: 'o', + desc: 'text for one', + requiresArg: true, + }) + .option('two', { + default: undefined, + type: 'number', + desc: 'text for two', + }) + .option('three', { + default: [], + type: 'array', + alias: 't', + desc: 'text for three', + nargs: 1, + requiresArg: true, + }) + .version(helpers.cliVersion()) + .demandCommand(1, '') + .recommendCommands() + .help() + .alias('h', 'help') + .epilogue( + 'If your app has a single stack, there is no need to specify the stack name\\n\\nIf one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', + ) + .parse(args); + } // eslint-disable-next-line @typescript-eslint/no-require-imports + const yargs = require('yargs'); + " + `); + }); + + test('can generate negativeAlias', async () => { + const config: CliConfig = { + globalOptions: {}, + commands: { + test: { + description: 'the action under test', + options: { + one: { + type: 'boolean', + alias: 'o', + desc: 'text for one', + negativeAlias: 'O', + }, + }, + }, + }, + }; + + expect(await renderYargs(config, YARGS_HELPERS)).toMatchInlineSnapshot(` + "// ------------------------------------------------------------------------------------------- + // GENERATED FROM packages/aws-cdk/lib/config.ts. + // Do not edit by hand; all changes will be overwritten at build time from the config file. + // ------------------------------------------------------------------------------------------- + /* eslint-disable @stylistic/max-len */ + import { Argv } from 'yargs'; + import * as helpers from './util/yargs-helpers'; + + // @ts-ignore TS6133 + export function parseCommandLineArguments(args: Array): any { + return yargs + .env('CDK') + .usage('Usage: cdk -a COMMAND') + .command('test', 'the action under test', (yargs: Argv) => + yargs + .option('one', { + default: undefined, + type: 'boolean', + alias: 'o', + desc: 'text for one', + }) + .option('O', { type: 'boolean', hidden: true }) + .middleware(helpers.yargsNegativeAlias('O', 'one'), true), + ) + .version(helpers.cliVersion()) + .demandCommand(1, '') + .recommendCommands() + .help() + .alias('h', 'help') + .epilogue( + 'If your app has a single stack, there is no need to specify the stack name\\n\\nIf one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', + ) + .parse(args); + } // eslint-disable-next-line @typescript-eslint/no-require-imports + const yargs = require('yargs'); + " + `); + }); + + test('can pass-through expression unchanged', async () => { + const config: CliConfig = { + globalOptions: {}, + commands: { + test: { + description: 'the action under test', + options: { + one: { + type: 'boolean', + default: $E( + expr + .sym(new ThingSymbol('banana', YARGS_HELPERS)) + .call(expr.lit(1), expr.lit(2), expr.lit(3)), + ), + }, + }, + }, + }, + }; + + expect(await renderYargs(config, YARGS_HELPERS)).toContain( + 'default: helpers.banana(1, 2, 3)', + ); + }); + + test('special notification-arn option gets NO default value', async () => { + const config: CliConfig = { + commands: { + deploy: { + description: 'Notification Arns', + options: { + ['notification-arns']: { + type: 'array', + desc: 'Deploy all stacks', + }, + ['other-array']: { + type: 'array', + desc: 'Other array', + }, + }, + }, + }, + globalOptions: {}, + }; + + expect(await renderYargs(config, YARGS_HELPERS)).toMatchInlineSnapshot(` + "// ------------------------------------------------------------------------------------------- + // GENERATED FROM packages/aws-cdk/lib/config.ts. + // Do not edit by hand; all changes will be overwritten at build time from the config file. + // ------------------------------------------------------------------------------------------- + /* eslint-disable @stylistic/max-len */ + import { Argv } from 'yargs'; + import * as helpers from './util/yargs-helpers'; + + // @ts-ignore TS6133 + export function parseCommandLineArguments(args: Array): any { + return yargs + .env('CDK') + .usage('Usage: cdk -a COMMAND') + .command('deploy', 'Notification Arns', (yargs: Argv) => + yargs + .option('notification-arns', { + type: 'array', + desc: 'Deploy all stacks', + nargs: 1, + requiresArg: true, + }) + .option('other-array', { + default: [], + type: 'array', + desc: 'Other array', + nargs: 1, + requiresArg: true, + }), + ) + .version(helpers.cliVersion()) + .demandCommand(1, '') + .recommendCommands() + .help() + .alias('h', 'help') + .epilogue( + 'If your app has a single stack, there is no need to specify the stack name\\n\\nIf one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', + ) + .parse(args); + } // eslint-disable-next-line @typescript-eslint/no-require-imports + const yargs = require('yargs'); + " + `); + }); +}); diff --git a/tools/@aws-cdk/user-input-gen/tsconfig.json b/tools/@aws-cdk/user-input-gen/tsconfig.json new file mode 100644 index 0000000000000..8ac2abcd4fc9d --- /dev/null +++ b/tools/@aws-cdk/user-input-gen/tsconfig.json @@ -0,0 +1,21 @@ +{ + "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"], + "exclude": ["**/*.d.ts"] +} From de651b2e749e814b1242296eb0f4dfc64cfc702e Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 16:23:38 -0500 Subject: [PATCH 2/8] tests --- .../test/convert-to-user-input-gen.test.ts | 8 ++++---- .../user-input-gen/test/user-input-gen.test.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts b/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts index 327a106c1ff9b..967b77d78486f 100644 --- a/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts +++ b/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts @@ -48,11 +48,11 @@ describe('render', () => { // Do not edit by hand; all changes will be overwritten at build time from the config file. // ------------------------------------------------------------------------------------------- /* eslint-disable @stylistic/max-len */ - import { CliArguments, GlobalOptions } from './cli-arguments'; + import { UserInput, GlobalOptions } from './user-input'; import { Command } from './settings'; // @ts-ignore TS6133 - export function convertToCliArgs(args: any): CliArguments { + export function convertYargsToUserInput(args: any): UserInput { const globalOptions: GlobalOptions = { app: args.app, debug: args.debug, @@ -68,13 +68,13 @@ describe('render', () => { }; break; } - const cliArguments: CliArguments = { + const userInput: UserInput = { _: args._[0], globalOptions, [args._[0]]: commandOptions, }; - return cliArguments; + return userInput; } " `); diff --git a/tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts b/tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts index 9cc216f8a9254..06886210a2f9b 100644 --- a/tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts +++ b/tools/@aws-cdk/user-input-gen/test/user-input-gen.test.ts @@ -52,11 +52,11 @@ describe('render', () => { import { Command } from './settings'; /** - * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts + * The structure of the user input -- either CLI options or cdk.json -- generated from packages/aws-cdk/lib/config.ts * * @struct */ - export interface CliArguments { + export interface UserInput { /** * The CLI command name */ @@ -161,11 +161,11 @@ describe('render', () => { import { Command } from './settings'; /** - * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts + * The structure of the user input -- either CLI options or cdk.json -- generated from packages/aws-cdk/lib/config.ts * * @struct */ - export interface CliArguments { + export interface UserInput { /** * The CLI command name */ @@ -243,11 +243,11 @@ describe('render', () => { import { Command } from './settings'; /** - * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts + * The structure of the user input -- either CLI options or cdk.json -- generated from packages/aws-cdk/lib/config.ts * * @struct */ - export interface CliArguments { + export interface UserInput { /** * The CLI command name */ From aa89ea642caa3d4b6e2df68782dc8ecd8d1b0e21 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 16:23:54 -0500 Subject: [PATCH 3/8] deleted cli-args-gen --- tools/@aws-cdk/cli-args-gen/.eslintrc.js | 3 - tools/@aws-cdk/cli-args-gen/.gitignore | 18 -- tools/@aws-cdk/cli-args-gen/.npmignore | 7 - tools/@aws-cdk/cli-args-gen/LICENSE | 201 ------------ tools/@aws-cdk/cli-args-gen/NOTICE | 2 - tools/@aws-cdk/cli-args-gen/README.md | 26 -- tools/@aws-cdk/cli-args-gen/jest.config.js | 10 - .../cli-args-gen/lib/cli-args-function-gen.ts | 105 ------ .../@aws-cdk/cli-args-gen/lib/cli-args-gen.ts | 158 --------- tools/@aws-cdk/cli-args-gen/lib/index.ts | 4 - tools/@aws-cdk/cli-args-gen/lib/util.ts | 34 -- tools/@aws-cdk/cli-args-gen/lib/yargs-gen.ts | 175 ---------- .../@aws-cdk/cli-args-gen/lib/yargs-types.ts | 52 --- tools/@aws-cdk/cli-args-gen/package.json | 59 ---- .../test/cli-args-function-gen.test.ts | 82 ----- .../cli-args-gen/test/cli-args-gen.test.ts | 305 ------------------ .../cli-args-gen/test/yargs-gen.test.ts | 222 ------------- tools/@aws-cdk/cli-args-gen/tsconfig.json | 21 -- 18 files changed, 1484 deletions(-) delete mode 100644 tools/@aws-cdk/cli-args-gen/.eslintrc.js delete mode 100644 tools/@aws-cdk/cli-args-gen/.gitignore delete mode 100644 tools/@aws-cdk/cli-args-gen/.npmignore delete mode 100644 tools/@aws-cdk/cli-args-gen/LICENSE delete mode 100644 tools/@aws-cdk/cli-args-gen/NOTICE delete mode 100644 tools/@aws-cdk/cli-args-gen/README.md delete mode 100644 tools/@aws-cdk/cli-args-gen/jest.config.js delete mode 100644 tools/@aws-cdk/cli-args-gen/lib/cli-args-function-gen.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/lib/cli-args-gen.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/lib/index.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/lib/util.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/lib/yargs-gen.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/lib/yargs-types.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/package.json delete mode 100644 tools/@aws-cdk/cli-args-gen/test/cli-args-function-gen.test.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/test/cli-args-gen.test.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/test/yargs-gen.test.ts delete mode 100644 tools/@aws-cdk/cli-args-gen/tsconfig.json diff --git a/tools/@aws-cdk/cli-args-gen/.eslintrc.js b/tools/@aws-cdk/cli-args-gen/.eslintrc.js deleted file mode 100644 index 2658ee8727166..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/.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/tools/@aws-cdk/cli-args-gen/.gitignore b/tools/@aws-cdk/cli-args-gen/.gitignore deleted file mode 100644 index 39180f6eb0bb4..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -# Build files -*.js -node_modules -*.js.map -*.d.ts -lib/services - -# Test artifacts -.LAST_BUILD -.nyc_output -coverage -nyc.config.js -*.snk -junit.xml - -# Keep configs -!.eslintrc.js -!jest.config.js diff --git a/tools/@aws-cdk/cli-args-gen/.npmignore b/tools/@aws-cdk/cli-args-gen/.npmignore deleted file mode 100644 index 79f3b5a763216..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ - -.LAST_BUILD -*.snk -junit.xml -.eslintrc.js -# exclude cdk artifacts -**/cdk.out \ No newline at end of file diff --git a/tools/@aws-cdk/cli-args-gen/LICENSE b/tools/@aws-cdk/cli-args-gen/LICENSE deleted file mode 100644 index 5ccf0c6780bab..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/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-2025 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/tools/@aws-cdk/cli-args-gen/NOTICE b/tools/@aws-cdk/cli-args-gen/NOTICE deleted file mode 100644 index cd0946c1cf193..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/tools/@aws-cdk/cli-args-gen/README.md b/tools/@aws-cdk/cli-args-gen/README.md deleted file mode 100644 index 8915e8d8de23b..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# cli-args-gen - -Generates CDK CLI configurations from the source of truth in `packages/aws-cdk/lib/config.ts`. -Currently generates the following files: - -- `packages/aws-cdk/lib/parse-command-line-arguments.ts`: `yargs` config. -- `packages/aws-cdk-lib/cli-arguments.ts`: strongly typed `CliArguments` interface. -- `packages/aws-cdk-lib/convert-to-cli-args.ts`: converts the `any` returned by `yargs` to `CliArguments`. - -## Usage - -```ts -import { renderYargs } from '@aws-cdk/cli-args-gen'; - -declare const config: CliConfig; - -fs.writeFileSync('./lib/parse-command-line-arguments.ts', await renderYargs(config)); -``` - -This package exports `renderYargs()`, which accepts the CLI command config as input and returns the yargs definition for it as a string. - -### Dynamic Values - -Some values must be computed at runtime, when a command is run. This is achieved with dynamic values; -if the framework sees a CLI option with a `dynamicValue`, then the framework will reference the corresponding parameter. -We should automatically generate the parameter definitions, instead of manually adding them, in the future. diff --git a/tools/@aws-cdk/cli-args-gen/jest.config.js b/tools/@aws-cdk/cli-args-gen/jest.config.js deleted file mode 100644 index 696b3d5b6e281..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/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: { - branches: 30, - }, - }, -}; diff --git a/tools/@aws-cdk/cli-args-gen/lib/cli-args-function-gen.ts b/tools/@aws-cdk/cli-args-gen/lib/cli-args-function-gen.ts deleted file mode 100644 index cb7e6a6dd22d4..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/lib/cli-args-function-gen.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { code, FreeFunction, Module, SelectiveModuleImport, Type, TypeScriptRenderer } from '@cdklabs/typewriter'; -import { EsLintRules } from '@cdklabs/typewriter/lib/eslint-rules'; -import * as prettier from 'prettier'; -import { kebabToCamelCase } from './util'; -import { CliAction, CliConfig } from './yargs-types'; - -export async function renderCliArgsFunc(config: CliConfig): Promise { - const scope = new Module('aws-cdk'); - - scope.documentation.push( '-------------------------------------------------------------------------------------------'); - scope.documentation.push('GENERATED FROM packages/aws-cdk/lib/config.ts.'); - scope.documentation.push('Do not edit by hand; all changes will be overwritten at build time from the config file.'); - scope.documentation.push('-------------------------------------------------------------------------------------------'); - - scope.addImport(new SelectiveModuleImport(scope, './cli-arguments', ['CliArguments', 'GlobalOptions'])); - const cliArgType = Type.fromName(scope, 'CliArguments'); - - scope.addImport(new SelectiveModuleImport(scope, './settings', ['Command'])); - - const createCliArguments = new FreeFunction(scope, { - name: 'convertToCliArgs', - export: true, - returnType: cliArgType, - parameters: [ - { name: 'args', type: Type.ANY }, - ], - }); - createCliArguments.addBody(code.expr.directCode(buildCliArgsFunction(config))); - - const ts = new TypeScriptRenderer({ - disabledEsLintRules: [EsLintRules.MAX_LEN], // the default disabled rules result in 'Definition for rule 'prettier/prettier' was not found' - }).render(scope); - - return prettier.format(ts, { - parser: 'typescript', - printWidth: 150, - singleQuote: true, - quoteProps: 'consistent', - }); -} - -function buildCliArgsFunction(config: CliConfig): string { - const globalOptions = buildGlobalOptions(config); - const commandSwitch = buildCommandSwitch(config); - const cliArgs = buildCliArgs(); - return [ - globalOptions, - commandSwitch, - cliArgs, - ].join('\n'); -} - -function buildGlobalOptions(config: CliConfig): string { - const globalOptionExprs = ['const globalOptions: GlobalOptions = {']; - for (const optionName of Object.keys(config.globalOptions)) { - const name = kebabToCamelCase(optionName); - globalOptionExprs.push(`'${name}': args.${name},`); - } - globalOptionExprs.push('}'); - return globalOptionExprs.join('\n'); -} - -function buildCommandSwitch(config: CliConfig): string { - const commandSwitchExprs = ['let commandOptions;', 'switch (args._[0] as Command) {']; - for (const commandName of Object.keys(config.commands)) { - commandSwitchExprs.push( - `case '${commandName}':`, - 'commandOptions = {', - ...buildCommandOptions(config.commands[commandName]), - ...(config.commands[commandName].arg ? [buildPositionalArguments(config.commands[commandName].arg)] : []), - '};', - `break; - `); - } - commandSwitchExprs.push('}'); - return commandSwitchExprs.join('\n'); -} - -function buildCommandOptions(options: CliAction): string[] { - const commandOptions: string[] = []; - for (const optionName of Object.keys(options.options ?? {})) { - const name = kebabToCamelCase(optionName); - commandOptions.push(`'${name}': args.${name},`); - } - return commandOptions; -} - -function buildPositionalArguments(arg: { name: string; variadic: boolean }): string { - if (arg.variadic) { - return `${arg.name}: args.${arg.name}`; - } - return `${arg.name}: args.${arg.name}`; -} - -function buildCliArgs(): string { - return [ - 'const cliArguments: CliArguments = {', - '_: args._[0],', - 'globalOptions,', - '[args._[0]]: commandOptions', - '}', - '', - 'return cliArguments', - ].join('\n'); -} diff --git a/tools/@aws-cdk/cli-args-gen/lib/cli-args-gen.ts b/tools/@aws-cdk/cli-args-gen/lib/cli-args-gen.ts deleted file mode 100644 index da469e5cb9dc0..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/lib/cli-args-gen.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { Module, SelectiveModuleImport, StructType, Type, TypeScriptRenderer } from '@cdklabs/typewriter'; -import { EsLintRules } from '@cdklabs/typewriter/lib/eslint-rules'; -import * as prettier from 'prettier'; -import { generateDefault, kebabToCamelCase, kebabToPascal } from './util'; -import { CliConfig } from './yargs-types'; - -export async function renderCliArgsType(config: CliConfig): Promise { - const scope = new Module('aws-cdk'); - - scope.documentation.push( '-------------------------------------------------------------------------------------------'); - scope.documentation.push('GENERATED FROM packages/aws-cdk/lib/config.ts.'); - scope.documentation.push('Do not edit by hand; all changes will be overwritten at build time from the config file.'); - scope.documentation.push('-------------------------------------------------------------------------------------------'); - - const cliArgType = new StructType(scope, { - export: true, - name: 'CliArguments', - docs: { - summary: 'The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts', - }, - }); - - // add required command - scope.addImport(new SelectiveModuleImport(scope, './settings', ['Command'])); - const commandEnum = Type.fromName(scope, 'Command'); - - cliArgType.addProperty({ - name: '_', - type: commandEnum, - docs: { - summary: 'The CLI command name', - }, - }); - - // add global options - const globalOptionType = new StructType(scope, { - export: true, - name: 'GlobalOptions', - docs: { - summary: 'Global options available to all CLI commands', - }, - }); - for (const [optionName, option] of Object.entries(config.globalOptions)) { - globalOptionType.addProperty({ - name: kebabToCamelCase(optionName), - type: convertType(option.type, option.count), - docs: { - default: normalizeDefault(option.default, option.type), - summary: option.desc, - deprecated: option.deprecated ? String(option.deprecated) : undefined, - }, - optional: true, - }); - } - - cliArgType.addProperty({ - name: 'globalOptions', - type: Type.fromName(scope, globalOptionType.name), - docs: { - summary: 'Global options available to all CLI commands', - }, - optional: true, - }); - - // add command-specific options - for (const [commandName, command] of Object.entries(config.commands)) { - const commandType = new StructType(scope, { - export: true, - name: `${kebabToPascal(commandName)}Options`, - docs: { - summary: command.description, - remarks: command.aliases ? `aliases: ${command.aliases.join(' ')}` : undefined, - }, - }); - - // add command level options - for (const [optionName, option] of Object.entries(command.options ?? {})) { - commandType.addProperty({ - name: kebabToCamelCase(optionName), - type: convertType(option.type, option.count), - docs: { - // Notification Arns is a special property where undefined and [] mean different things - default: optionName === 'notification-arns' ? 'undefined' : normalizeDefault(option.default, option.type), - summary: option.desc, - deprecated: option.deprecated ? String(option.deprecated) : undefined, - remarks: option.alias ? `aliases: ${Array.isArray(option.alias) ? option.alias.join(' ') : option.alias}` : undefined, - }, - optional: true, - }); - } - - // add positional argument associated with the command - if (command.arg) { - commandType.addProperty({ - name: command.arg.name, - type: command.arg.variadic ? Type.arrayOf(Type.STRING) : Type.STRING, - docs: { - summary: `Positional argument for ${commandName}`, - }, - optional: true, - }); - } - - cliArgType.addProperty({ - name: kebabToCamelCase(commandName), - type: Type.fromName(scope, commandType.name), - docs: { - summary: command.description, - remarks: command.aliases ? `aliases: ${command.aliases.join(' ')}` : undefined, - }, - optional: true, - }); - } - - const ts = new TypeScriptRenderer({ - disabledEsLintRules: [EsLintRules.MAX_LEN], // the default disabled rules result in 'Definition for rule 'prettier/prettier' was not found' - }).render(scope); - - return prettier.format(ts, { - parser: 'typescript', - printWidth: 150, - singleQuote: true, - quoteProps: 'consistent', - }); -} - -function convertType(type: 'string' | 'array' | 'number' | 'boolean' | 'count', count?: boolean): Type { - switch (type) { - case 'boolean': - return count ? Type.NUMBER : Type.BOOLEAN; - case 'string': - return Type.STRING; - case 'number': - return Type.NUMBER; - case 'array': - return Type.arrayOf(Type.STRING); - case 'count': - return Type.NUMBER; - } -} - -function normalizeDefault(defaultValue: any, type: string): string { - switch (typeof defaultValue) { - case 'boolean': - case 'string': - case 'number': - case 'object': - return JSON.stringify(defaultValue); - - // In these cases we cannot use the given defaultValue, so we then check the type - // of the option to determine the default value - case 'undefined': - case 'function': - default: - const generatedDefault = generateDefault(type); - return generatedDefault ? JSON.stringify(generatedDefault) : 'undefined'; - } -} diff --git a/tools/@aws-cdk/cli-args-gen/lib/index.ts b/tools/@aws-cdk/cli-args-gen/lib/index.ts deleted file mode 100644 index 6dfee4beeac38..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/lib/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './yargs-gen'; -export * from './yargs-types'; -export * from './cli-args-gen'; -export * from './cli-args-function-gen'; diff --git a/tools/@aws-cdk/cli-args-gen/lib/util.ts b/tools/@aws-cdk/cli-args-gen/lib/util.ts deleted file mode 100644 index 6d7d050315738..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/lib/util.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { code, Expression } from '@cdklabs/typewriter'; - -export function generateDefault(type: string) { - return type === 'array' ? [] : undefined; -} - -export function lit(value: any): Expression { - switch (value) { - case undefined: - return code.expr.UNDEFINED; - case null: - return code.expr.NULL; - default: - return code.expr.lit(value); - } -} - -export function kebabToCamelCase(str: string): string { - return str - .split('-') - .map((word, index) => - index === 0 - ? word.toLowerCase() - : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(), - ) - .join(''); -} - -export function kebabToPascal(str: string): string { - return str - .split('-') - .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) - .join(''); -} diff --git a/tools/@aws-cdk/cli-args-gen/lib/yargs-gen.ts b/tools/@aws-cdk/cli-args-gen/lib/yargs-gen.ts deleted file mode 100644 index 89fdbe4523cb1..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/lib/yargs-gen.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { $E, Expression, ExternalModule, FreeFunction, IScope, Module, SelectiveModuleImport, Statement, ThingSymbol, Type, TypeScriptRenderer, code, expr } from '@cdklabs/typewriter'; -import { EsLintRules } from '@cdklabs/typewriter/lib/eslint-rules'; -import * as prettier from 'prettier'; -import { generateDefault, lit } from './util'; -import { CliConfig, CliOption, YargsOption } from './yargs-types'; - -// to import lodash.clonedeep properly, we would need to set esModuleInterop: true -// however that setting does not work in the CLI, so we fudge it. -// eslint-disable-next-line @typescript-eslint/no-require-imports -const cloneDeep = require('lodash.clonedeep'); - -export class CliHelpers extends ExternalModule { - public readonly browserForPlatform = makeCallableExpr(this, 'browserForPlatform'); - public readonly cliVersion = makeCallableExpr(this, 'cliVersion'); - public readonly isCI = makeCallableExpr(this, 'isCI'); - public readonly yargsNegativeAlias = makeCallableExpr(this, 'yargsNegativeAlias'); -} - -function makeCallableExpr(scope: IScope, name: string) { - return $E(expr.sym(new ThingSymbol(name, scope))); -} - -export async function renderYargs(config: CliConfig, helpers: CliHelpers): Promise { - const scope = new Module('aws-cdk'); - - scope.documentation.push( '-------------------------------------------------------------------------------------------'); - scope.documentation.push('GENERATED FROM packages/aws-cdk/lib/config.ts.'); - scope.documentation.push('Do not edit by hand; all changes will be overwritten at build time from the config file.'); - scope.documentation.push('-------------------------------------------------------------------------------------------'); - - scope.addImport(new SelectiveModuleImport(scope, 'yargs', ['Argv'])); - helpers.import(scope, 'helpers'); - - // 'https://github.com/yargs/yargs/issues/1929', - // 'https://github.com/evanw/esbuild/issues/1492', - scope.addInitialization(code.comment('eslint-disable-next-line @typescript-eslint/no-require-imports')); - scope.addInitialization(code.stmt.constVar(code.expr.ident('yargs'), code.expr.directCode("require('yargs')"))); - - const parseCommandLineArguments = new FreeFunction(scope, { - name: 'parseCommandLineArguments', - export: true, - returnType: Type.ANY, - parameters: [ - { name: 'args', type: Type.arrayOf(Type.STRING) }, - ], - }); - parseCommandLineArguments.addBody(makeYargs(config, helpers)); - - const ts = new TypeScriptRenderer({ - disabledEsLintRules: [EsLintRules.MAX_LEN], // the default disabled rules result in 'Definition for rule 'prettier/prettier' was not found' - }).render(scope); - - return prettier.format(ts, { - parser: 'typescript', - printWidth: 150, - singleQuote: true, - trailingComma: 'all', - }); -} - -// Use the following configuration for array arguments: -// -// { type: 'array', default: [], nargs: 1, requiresArg: true } -// -// The default behavior of yargs is to eat all strings following an array argument: -// -// ./prog --arg one two positional => will parse to { arg: ['one', 'two', 'positional'], _: [] } (so no positional arguments) -// ./prog --arg one two -- positional => does not help, for reasons that I can't understand. Still gets parsed incorrectly. -// -// By using the config above, every --arg will only consume one argument, so you can do the following: -// -// ./prog --arg one --arg two position => will parse to { arg: ['one', 'two'], _: ['positional'] }. -function makeYargs(config: CliConfig, helpers: CliHelpers): Statement { - let yargsExpr: Expression = code.expr.ident('yargs'); - yargsExpr = yargsExpr - .callMethod('env', lit('CDK')) - .callMethod('usage', lit('Usage: cdk -a COMMAND')); - - // we must compute global options first, as they are not part of an argument to a command call - yargsExpr = makeOptions(yargsExpr, config.globalOptions, helpers); - - for (const command of Object.keys(config.commands)) { - const commandFacts = config.commands[command]; - const commandArg = commandFacts.arg - ? ` [${commandFacts.arg?.name}${commandFacts.arg?.variadic ? '..' : ''}]` - : ''; - const aliases = commandFacts.aliases - ? commandFacts.aliases.map((alias) => `, '${alias}${commandArg}'`) - : ''; - - // must compute options before we compute the full command, because in yargs, the options are an argument to the command call. - let optionsExpr: Expression = code.expr.directCode('(yargs: Argv) => yargs'); - optionsExpr = makeOptions(optionsExpr, commandFacts.options ?? {}, helpers); - - const commandCallArgs: Array = []; - if (aliases) { - commandCallArgs.push(code.expr.directCode(`['${command}${commandArg}'${aliases}]`)); - } else { - commandCallArgs.push(code.expr.directCode(`'${command}${commandArg}'`)); - } - commandCallArgs.push(lit(commandFacts.description)); - - if (commandFacts.options) { - commandCallArgs.push(optionsExpr); - } - - yargsExpr = yargsExpr.callMethod('command', ...commandCallArgs); - } - - return code.stmt.ret(makeEpilogue(yargsExpr, helpers)); -} - -function makeOptions(prefix: Expression, options: { [optionName: string]: CliOption }, helpers: CliHelpers) { - let optionsExpr = prefix; - for (const option of Object.keys(options)) { - const theOption: CliOption = { - // Make the default explicit (overridden if the option includes an actual default) - // 'notification-arns' is a special snowflake that should be defaulted to 'undefined', but https://github.com/yargs/yargs/issues/2443 - // prevents us from doing so. This should be changed if the issue is resolved. - ...(option === 'notification-arns' ? {} : { default: generateDefault(options[option].type) }), - ...options[option], - }; - const optionProps: YargsOption = cloneDeep(theOption); - const optionArgs: { [key: string]: Expression } = {}; - - // Array defaults - if (optionProps.type === 'array') { - optionProps.nargs = 1; - optionProps.requiresArg = true; - } - - for (const optionProp of Object.keys(optionProps).filter(opt => !['negativeAlias'].includes(opt))) { - const optionValue = (optionProps as any)[optionProp]; - if (optionValue instanceof Expression) { - optionArgs[optionProp] = optionValue; - } else { - optionArgs[optionProp] = lit(optionValue); - } - } - - // Register the option with yargs - optionsExpr = optionsExpr.callMethod('option', lit(option), code.expr.object(optionArgs)); - - // Special case for negativeAlias - // We need an additional option and a middleware: - // .option('R', { type: 'boolean', hidden: true }).middleware(yargsNegativeAlias('R', 'rollback'), true) - if (theOption.negativeAlias) { - const middleware = helpers.yargsNegativeAlias.call(lit(theOption.negativeAlias), lit(option)); - optionsExpr = optionsExpr.callMethod('option', lit(theOption.negativeAlias), code.expr.lit({ - type: 'boolean', - hidden: true, - })); - optionsExpr = optionsExpr.callMethod('middleware', middleware, lit(true)); - } - } - - return optionsExpr; -} - -function makeEpilogue(prefix: Expression, helpers: CliHelpers) { - let completeDefinition = prefix.callMethod('version', helpers.cliVersion()); - completeDefinition = completeDefinition.callMethod('demandCommand', lit(1), lit('')); // just print help - completeDefinition = completeDefinition.callMethod('recommendCommands'); - completeDefinition = completeDefinition.callMethod('help'); - completeDefinition = completeDefinition.callMethod('alias', lit('h'), lit('help')); - completeDefinition = completeDefinition.callMethod('epilogue', lit([ - 'If your app has a single stack, there is no need to specify the stack name', - 'If one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', - ].join('\n\n'))); - - completeDefinition = completeDefinition.callMethod('parse', code.expr.ident('args')); - - return completeDefinition; -} - diff --git a/tools/@aws-cdk/cli-args-gen/lib/yargs-types.ts b/tools/@aws-cdk/cli-args-gen/lib/yargs-types.ts deleted file mode 100644 index 91c23b288cd04..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/lib/yargs-types.ts +++ /dev/null @@ -1,52 +0,0 @@ -interface YargsCommand { - description: string; - options?: { [optionName: string]: YargsOption }; - aliases?: string[]; - arg?: YargsArg; -} - -export interface CliAction extends YargsCommand { - options?: { [optionName: string]: CliOption }; -} - -interface YargsArg { - name: string; - variadic: boolean; -} - -export interface YargsOption { - type: 'string' | 'array' | 'number' | 'boolean' | 'count'; - desc?: string; - default?: any; - deprecated?: boolean | string; - choices?: ReadonlyArray; - alias?: string | string[]; - conflicts?: string | readonly string[] | { [key: string]: string | readonly string[] }; - nargs?: number; - requiresArg?: boolean; - hidden?: boolean; - count?: boolean; -} - -export interface CliOption extends Omit { - negativeAlias?: string; -} - -export interface Middleware { - callback: string; - args: string[]; - applyBeforeValidation?: boolean; -} - -export interface CliConfig { - globalOptions: { [optionName: string]: CliOption }; - commands: { [commandName: string]: CliAction }; -} - -/** - * The result of a DynamicValue call - */ -export interface DynamicResult { - dynamicType: 'parameter' | 'function'; - dynamicValue: string; -} diff --git a/tools/@aws-cdk/cli-args-gen/package.json b/tools/@aws-cdk/cli-args-gen/package.json deleted file mode 100644 index 29a15729acc0c..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "@aws-cdk/cli-args-gen", - "private": true, - "version": "0.0.0", - "description": "Generate CLI arguments", - "repository": { - "type": "git", - "url": "https://github.com/aws/aws-cdk.git", - "directory": "tools/@aws-cdk/cli-args-gen" - }, - "main": "./lib/index.js", - "types": "./lib/index.d.ts", - "scripts": { - "build": "cdk-build", - "watch": "cdk-watch", - "lint": "cdk-lint", - "test": "cdk-test", - "pkglint": "pkglint -f", - "build+test": "yarn build && yarn test", - "build+extract": "yarn build", - "build+test+extract": "yarn build+test", - "build+test+package": "yarn build+test" - }, - "author": { - "name": "Amazon Web Services", - "url": "https://aws.amazon.com", - "organization": true - }, - "license": "Apache-2.0", - "dependencies": { - "@cdklabs/typewriter": "^0.0.5", - "lodash.clonedeep": "^4.5.0", - "prettier": "^2.8.8" - }, - "devDependencies": { - "@aws-cdk/cdk-build-tools": "0.0.0", - "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^29.5.12", - "@types/lodash.clonedeep": "^4.5.0", - "@types/node": "^18", - "jest": "^29.7.0" - }, - "keywords": [ - "aws", - "cdk" - ], - "homepage": "https://github.com/aws/aws-cdk", - "engines": { - "node": ">= 14.15.0" - }, - "ubergen": { - "exclude": true - }, - "pkglint": { - "exclude": [ - "dependencies/cdk-point-dependencies" - ] - } -} diff --git a/tools/@aws-cdk/cli-args-gen/test/cli-args-function-gen.test.ts b/tools/@aws-cdk/cli-args-gen/test/cli-args-function-gen.test.ts deleted file mode 100644 index 24b92c7fe291e..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/test/cli-args-function-gen.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { CliConfig, renderCliArgsFunc } from '../lib'; - -describe('render', () => { - test('can generate conversion function', async () => { - const config: CliConfig = { - globalOptions: { - app: { - type: 'string', - desc: 'REQUIRED: Command-line for executing your app', - }, - debug: { - type: 'boolean', - desc: 'Enable debug logging', - default: false, - }, - context: { - default: [], - type: 'array', - alias: 'c', - desc: 'context values', - }, - plugin: { - type: 'array', - desc: 'plugins to load', - }, - }, - commands: { - deploy: { - arg: { - name: 'STACKS', - variadic: true, - }, - description: 'Deploy a stack', - options: { - all: { - type: 'boolean', - desc: 'Deploy all stacks', - default: false, - }, - }, - }, - }, - }; - - expect(await renderCliArgsFunc(config)).toMatchInlineSnapshot(` - "// ------------------------------------------------------------------------------------------- - // GENERATED FROM packages/aws-cdk/lib/config.ts. - // Do not edit by hand; all changes will be overwritten at build time from the config file. - // ------------------------------------------------------------------------------------------- - /* eslint-disable @stylistic/max-len */ - import { CliArguments, GlobalOptions } from './cli-arguments'; - import { Command } from './settings'; - - // @ts-ignore TS6133 - export function convertToCliArgs(args: any): CliArguments { - const globalOptions: GlobalOptions = { - app: args.app, - debug: args.debug, - context: args.context, - plugin: args.plugin, - }; - let commandOptions; - switch (args._[0] as Command) { - case 'deploy': - commandOptions = { - all: args.all, - STACKS: args.STACKS, - }; - break; - } - const cliArguments: CliArguments = { - _: args._[0], - globalOptions, - [args._[0]]: commandOptions, - }; - - return cliArguments; - } - " - `); - }); -}); diff --git a/tools/@aws-cdk/cli-args-gen/test/cli-args-gen.test.ts b/tools/@aws-cdk/cli-args-gen/test/cli-args-gen.test.ts deleted file mode 100644 index 341931d53e8f8..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/test/cli-args-gen.test.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { CliConfig, renderCliArgsType } from '../lib'; - -describe('render', () => { - test('can generate CliArguments type', async () => { - const config: CliConfig = { - globalOptions: { - app: { - type: 'string', - desc: 'REQUIRED: Command-line for executing your app', - }, - debug: { - type: 'boolean', - desc: 'Enable debug logging', - default: false, - }, - verbose: { - type: 'boolean', - count: true, - desc: 'Increase logging verbosity', - }, - context: { - default: [], - type: 'array', - alias: 'c', - desc: 'context values', - }, - plugin: { - type: 'array', - desc: 'plugins to load', - }, - }, - commands: { - deploy: { - description: 'Deploy a stack', - options: { - all: { - type: 'boolean', - desc: 'Deploy all stacks', - default: false, - }, - }, - }, - }, - }; - - expect(await renderCliArgsType(config)).toMatchInlineSnapshot(` - "// ------------------------------------------------------------------------------------------- - // GENERATED FROM packages/aws-cdk/lib/config.ts. - // Do not edit by hand; all changes will be overwritten at build time from the config file. - // ------------------------------------------------------------------------------------------- - /* eslint-disable @stylistic/max-len */ - import { Command } from './settings'; - - /** - * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts - * - * @struct - */ - export interface CliArguments { - /** - * The CLI command name - */ - readonly _: Command; - - /** - * Global options available to all CLI commands - */ - readonly globalOptions?: GlobalOptions; - - /** - * Deploy a stack - */ - readonly deploy?: DeployOptions; - } - - /** - * Global options available to all CLI commands - * - * @struct - */ - export interface GlobalOptions { - /** - * REQUIRED: Command-line for executing your app - * - * @default - undefined - */ - readonly app?: string; - - /** - * Enable debug logging - * - * @default - false - */ - readonly debug?: boolean; - - /** - * Increase logging verbosity - * - * @default - undefined - */ - readonly verbose?: number; - - /** - * context values - * - * @default - [] - */ - readonly context?: Array; - - /** - * plugins to load - * - * @default - [] - */ - readonly plugin?: Array; - } - - /** - * Deploy a stack - * - * @struct - */ - export interface DeployOptions { - /** - * Deploy all stacks - * - * @default - false - */ - readonly all?: boolean; - } - " - `); - }); - - test('special notification-arn option gets undefined default', async () => { - const config: CliConfig = { - commands: { - deploy: { - description: 'Notification Arns', - options: { - ['notification-arns']: { - type: 'array', - desc: 'Deploy all stacks', - }, - ['other-array']: { - type: 'array', - desc: 'Other array', - }, - }, - }, - }, - globalOptions: {}, - }; - - expect(await renderCliArgsType(config)).toMatchInlineSnapshot(` - "// ------------------------------------------------------------------------------------------- - // GENERATED FROM packages/aws-cdk/lib/config.ts. - // Do not edit by hand; all changes will be overwritten at build time from the config file. - // ------------------------------------------------------------------------------------------- - /* eslint-disable @stylistic/max-len */ - import { Command } from './settings'; - - /** - * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts - * - * @struct - */ - export interface CliArguments { - /** - * The CLI command name - */ - readonly _: Command; - - /** - * Global options available to all CLI commands - */ - readonly globalOptions?: GlobalOptions; - - /** - * Notification Arns - */ - readonly deploy?: DeployOptions; - } - - /** - * Global options available to all CLI commands - * - * @struct - */ - export interface GlobalOptions {} - - /** - * Notification Arns - * - * @struct - */ - export interface DeployOptions { - /** - * Deploy all stacks - * - * @default - undefined - */ - readonly notificationArns?: Array; - - /** - * Other array - * - * @default - [] - */ - readonly otherArray?: Array; - } - " - `); - }); - - test('positional arguments', async () => { - const config: CliConfig = { - commands: { - deploy: { - arg: { - name: 'STACKS', - variadic: true, - }, - description: 'deploy', - }, - acknowledge: { - arg: { - name: 'ID', - variadic: false, - }, - description: 'acknowledge', - }, - }, - globalOptions: {}, - }; - - expect(await renderCliArgsType(config)).toMatchInlineSnapshot(` - "// ------------------------------------------------------------------------------------------- - // GENERATED FROM packages/aws-cdk/lib/config.ts. - // Do not edit by hand; all changes will be overwritten at build time from the config file. - // ------------------------------------------------------------------------------------------- - /* eslint-disable @stylistic/max-len */ - import { Command } from './settings'; - - /** - * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts - * - * @struct - */ - export interface CliArguments { - /** - * The CLI command name - */ - readonly _: Command; - - /** - * Global options available to all CLI commands - */ - readonly globalOptions?: GlobalOptions; - - /** - * deploy - */ - readonly deploy?: DeployOptions; - - /** - * acknowledge - */ - readonly acknowledge?: AcknowledgeOptions; - } - - /** - * Global options available to all CLI commands - * - * @struct - */ - export interface GlobalOptions {} - - /** - * deploy - * - * @struct - */ - export interface DeployOptions { - /** - * Positional argument for deploy - */ - readonly STACKS?: Array; - } - - /** - * acknowledge - * - * @struct - */ - export interface AcknowledgeOptions { - /** - * Positional argument for acknowledge - */ - readonly ID?: string; - } - " - `); - }); -}); diff --git a/tools/@aws-cdk/cli-args-gen/test/yargs-gen.test.ts b/tools/@aws-cdk/cli-args-gen/test/yargs-gen.test.ts deleted file mode 100644 index 75540361fcc3a..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/test/yargs-gen.test.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { $E, expr, ThingSymbol } from '@cdklabs/typewriter'; -import { CliConfig, CliHelpers, renderYargs } from '../lib'; - -const YARGS_HELPERS = new CliHelpers('./util/yargs-helpers'); - -describe('render', () => { - test('can generate global options', async () => { - const config: CliConfig = { - globalOptions: { - one: { - type: 'string', - alias: 'o', - desc: 'text for one', - requiresArg: true, - }, - two: { type: 'number', desc: 'text for two' }, - three: { - type: 'array', - alias: 't', - desc: 'text for three', - }, - }, - commands: {}, - }; - - expect(await renderYargs(config, YARGS_HELPERS)).toMatchInlineSnapshot(` - "// ------------------------------------------------------------------------------------------- - // GENERATED FROM packages/aws-cdk/lib/config.ts. - // Do not edit by hand; all changes will be overwritten at build time from the config file. - // ------------------------------------------------------------------------------------------- - /* eslint-disable @stylistic/max-len */ - import { Argv } from 'yargs'; - import * as helpers from './util/yargs-helpers'; - - // @ts-ignore TS6133 - export function parseCommandLineArguments(args: Array): any { - return yargs - .env('CDK') - .usage('Usage: cdk -a COMMAND') - .option('one', { - default: undefined, - type: 'string', - alias: 'o', - desc: 'text for one', - requiresArg: true, - }) - .option('two', { - default: undefined, - type: 'number', - desc: 'text for two', - }) - .option('three', { - default: [], - type: 'array', - alias: 't', - desc: 'text for three', - nargs: 1, - requiresArg: true, - }) - .version(helpers.cliVersion()) - .demandCommand(1, '') - .recommendCommands() - .help() - .alias('h', 'help') - .epilogue( - 'If your app has a single stack, there is no need to specify the stack name\\n\\nIf one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', - ) - .parse(args); - } // eslint-disable-next-line @typescript-eslint/no-require-imports - const yargs = require('yargs'); - " - `); - }); - - test('can generate negativeAlias', async () => { - const config: CliConfig = { - globalOptions: {}, - commands: { - test: { - description: 'the action under test', - options: { - one: { - type: 'boolean', - alias: 'o', - desc: 'text for one', - negativeAlias: 'O', - }, - }, - }, - }, - }; - - expect(await renderYargs(config, YARGS_HELPERS)).toMatchInlineSnapshot(` - "// ------------------------------------------------------------------------------------------- - // GENERATED FROM packages/aws-cdk/lib/config.ts. - // Do not edit by hand; all changes will be overwritten at build time from the config file. - // ------------------------------------------------------------------------------------------- - /* eslint-disable @stylistic/max-len */ - import { Argv } from 'yargs'; - import * as helpers from './util/yargs-helpers'; - - // @ts-ignore TS6133 - export function parseCommandLineArguments(args: Array): any { - return yargs - .env('CDK') - .usage('Usage: cdk -a COMMAND') - .command('test', 'the action under test', (yargs: Argv) => - yargs - .option('one', { - default: undefined, - type: 'boolean', - alias: 'o', - desc: 'text for one', - }) - .option('O', { type: 'boolean', hidden: true }) - .middleware(helpers.yargsNegativeAlias('O', 'one'), true), - ) - .version(helpers.cliVersion()) - .demandCommand(1, '') - .recommendCommands() - .help() - .alias('h', 'help') - .epilogue( - 'If your app has a single stack, there is no need to specify the stack name\\n\\nIf one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', - ) - .parse(args); - } // eslint-disable-next-line @typescript-eslint/no-require-imports - const yargs = require('yargs'); - " - `); - }); - - test('can pass-through expression unchanged', async () => { - const config: CliConfig = { - globalOptions: {}, - commands: { - test: { - description: 'the action under test', - options: { - one: { - type: 'boolean', - default: $E( - expr - .sym(new ThingSymbol('banana', YARGS_HELPERS)) - .call(expr.lit(1), expr.lit(2), expr.lit(3)), - ), - }, - }, - }, - }, - }; - - expect(await renderYargs(config, YARGS_HELPERS)).toContain( - 'default: helpers.banana(1, 2, 3)', - ); - }); - - test('special notification-arn option gets NO default value', async () => { - const config: CliConfig = { - commands: { - deploy: { - description: 'Notification Arns', - options: { - ['notification-arns']: { - type: 'array', - desc: 'Deploy all stacks', - }, - ['other-array']: { - type: 'array', - desc: 'Other array', - }, - }, - }, - }, - globalOptions: {}, - }; - - expect(await renderYargs(config, YARGS_HELPERS)).toMatchInlineSnapshot(` - "// ------------------------------------------------------------------------------------------- - // GENERATED FROM packages/aws-cdk/lib/config.ts. - // Do not edit by hand; all changes will be overwritten at build time from the config file. - // ------------------------------------------------------------------------------------------- - /* eslint-disable @stylistic/max-len */ - import { Argv } from 'yargs'; - import * as helpers from './util/yargs-helpers'; - - // @ts-ignore TS6133 - export function parseCommandLineArguments(args: Array): any { - return yargs - .env('CDK') - .usage('Usage: cdk -a COMMAND') - .command('deploy', 'Notification Arns', (yargs: Argv) => - yargs - .option('notification-arns', { - type: 'array', - desc: 'Deploy all stacks', - nargs: 1, - requiresArg: true, - }) - .option('other-array', { - default: [], - type: 'array', - desc: 'Other array', - nargs: 1, - requiresArg: true, - }), - ) - .version(helpers.cliVersion()) - .demandCommand(1, '') - .recommendCommands() - .help() - .alias('h', 'help') - .epilogue( - 'If your app has a single stack, there is no need to specify the stack name\\n\\nIf one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence.', - ) - .parse(args); - } // eslint-disable-next-line @typescript-eslint/no-require-imports - const yargs = require('yargs'); - " - `); - }); -}); diff --git a/tools/@aws-cdk/cli-args-gen/tsconfig.json b/tools/@aws-cdk/cli-args-gen/tsconfig.json deleted file mode 100644 index 8ac2abcd4fc9d..0000000000000 --- a/tools/@aws-cdk/cli-args-gen/tsconfig.json +++ /dev/null @@ -1,21 +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"], - "exclude": ["**/*.d.ts"] -} From 5ebfc9781fa7dbd1383b7a38e7c815d0a3bc3ea4 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 16:28:12 -0500 Subject: [PATCH 4/8] finish renaming --- aws-cdk.code-workspace | 2 +- lerna.json | 2 +- package.json | 2 +- packages/aws-cdk/CONTRIBUTING.md | 8 +- packages/aws-cdk/lib/config.ts | 9 +- packages/aws-cdk/lib/convert-to-user-input.ts | 256 ++++ packages/aws-cdk/lib/user-input.ts | 1327 +++++++++++++++++ packages/aws-cdk/package.json | 6 +- packages/aws-cdk/scripts/cli-args-gen | 2 - packages/aws-cdk/scripts/cli-args-gen.ts | 15 - packages/aws-cdk/scripts/user-input-gen | 2 + packages/aws-cdk/scripts/user-input-gen.ts | 16 + .../lib/convert-to-user-input-gen.ts | 3 +- 13 files changed, 1618 insertions(+), 32 deletions(-) create mode 100644 packages/aws-cdk/lib/convert-to-user-input.ts create mode 100644 packages/aws-cdk/lib/user-input.ts delete mode 100755 packages/aws-cdk/scripts/cli-args-gen delete mode 100644 packages/aws-cdk/scripts/cli-args-gen.ts create mode 100755 packages/aws-cdk/scripts/user-input-gen create mode 100644 packages/aws-cdk/scripts/user-input-gen.ts diff --git a/aws-cdk.code-workspace b/aws-cdk.code-workspace index a7ebb6636469f..406bc32a95401 100644 --- a/aws-cdk.code-workspace +++ b/aws-cdk.code-workspace @@ -31,7 +31,7 @@ "name": "aws-custom-resource-sdk-adapter", "rootPath": "packages/@aws-cdk/aws-custom-resource-sdk-adapter" }, - { "name": "cli-args-gen", "rootPath": "tools/@aws-cdk/cli-args-gen" } + { "name": "user-input-gen", "rootPath": "tools/@aws-cdk/user-input-gen" } ] }, "extensions": { diff --git a/lerna.json b/lerna.json index c10809593a0e4..05a0f3ac14fb5 100644 --- a/lerna.json +++ b/lerna.json @@ -10,7 +10,7 @@ "packages/@aws-cdk-testing/*", "packages/@aws-cdk/*/lambda-packages/*", "tools/@aws-cdk/cdk-build-tools", - "tools/@aws-cdk/cli-args-gen", + "tools/@aws-cdk/user-input-gen", "tools/@aws-cdk/cdk-release", "tools/@aws-cdk/node-bundle", "tools/@aws-cdk/pkglint", diff --git a/package.json b/package.json index 0f3eb7971f811..a75d010d3c217 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "packages/@aws-cdk-testing/*", "packages/@aws-cdk/*/lambda-packages/*", "tools/@aws-cdk/cdk-build-tools", - "tools/@aws-cdk/cli-args-gen", + "tools/@aws-cdk/user-input-gen", "tools/@aws-cdk/cdk-release", "tools/@aws-cdk/node-bundle", "tools/@aws-cdk/pkglint", diff --git a/packages/aws-cdk/CONTRIBUTING.md b/packages/aws-cdk/CONTRIBUTING.md index 7619772294894..f3c967f03c9e4 100644 --- a/packages/aws-cdk/CONTRIBUTING.md +++ b/packages/aws-cdk/CONTRIBUTING.md @@ -1,21 +1,21 @@ ## CLI Commands All CDK CLI Commands are defined in `lib/config.ts`. This file is translated -into a valid `yargs` configuration by `bin/cli-args-gen`, which is generated by `@aws-cdk/cli-args-gen`. +into a valid `yargs` configuration by `bin/user-input-gen`, which is generated by `@aws-cdk/user-input-gen`. The `yargs` configuration is generated into the function `parseCommandLineArguments()`, in `lib/parse-command-line-arguments.ts`, and is checked into git for readability and inspectability; do not edit this file by hand, as every subsequent `yarn build` will overwrite any manual edits. If you need to leverage a `yargs` feature not used by -the CLI, you must add support for it to `@aws-cdk/cli-args-gen`. +the CLI, you must add support for it to `@aws-cdk/user-input-gen`. -Note that `bin/cli-args-gen` is executed by `ts-node`, which allows `config.ts` to +Note that `bin/user-input-gen` is executed by `ts-node`, which allows `config.ts` to reference functions and other identifiers defined in the CLI before the CLI is built. ### Dynamic Values Some values, such as the user's platform, cannot be computed at build time. -Some commands depend on these values, and thus `cli-args-gen` must generate the +Some commands depend on these values, and thus `user-input-gen` must generate the code to compute these values at build time. The only way to do this today is to reference a parameter with `DynamicValue.fromParameter`. diff --git a/packages/aws-cdk/lib/config.ts b/packages/aws-cdk/lib/config.ts index 5e881733a3606..13898df29fa7a 100644 --- a/packages/aws-cdk/lib/config.ts +++ b/packages/aws-cdk/lib/config.ts @@ -1,5 +1,5 @@ // eslint-disable-next-line import/no-extraneous-dependencies -import { CliHelpers, type CliConfig } from '@aws-cdk/cli-args-gen'; +import { CliHelpers, type CliConfig } from '@aws-cdk/user-input-gen'; import { StackActivityProgress } from './api/util/cloudformation/stack-activity-monitor'; import { MIGRATE_SUPPORTED_LANGUAGES } from './commands/migrate'; import { RequireApproval } from './diff'; @@ -8,8 +8,11 @@ import { availableInitLanguages } from './init'; export const YARGS_HELPERS = new CliHelpers('./util/yargs-helpers'); /** - * Source of truth for all CDK CLI commands. `cli-args-gen` translates this into the `yargs` definition - * in `lib/parse-command-line-arguments.ts`. + * Source of truth for all CDK CLI commands. `user-input-gen` translates this into: + * + * - the `yargs` definition in `lib/parse-command-line-arguments.ts`. + * - the `UserInput` type in `lib/user-input.ts`. + * - the `convertXxxToUserInput` functions in `lib/convert-to-user-input.ts`. */ export async function makeConfig(): Promise { return { diff --git a/packages/aws-cdk/lib/convert-to-user-input.ts b/packages/aws-cdk/lib/convert-to-user-input.ts new file mode 100644 index 0000000000000..9ddbd2d5baec5 --- /dev/null +++ b/packages/aws-cdk/lib/convert-to-user-input.ts @@ -0,0 +1,256 @@ +// ------------------------------------------------------------------------------------------- +// GENERATED FROM packages/aws-cdk/lib/config.ts. +// Do not edit by hand; all changes will be overwritten at build time from the config file. +// ------------------------------------------------------------------------------------------- +/* eslint-disable @stylistic/max-len */ +import { Command } from './settings'; +import { UserInput, GlobalOptions } from './user-input'; + +// @ts-ignore TS6133 +export function convertYargsToUserInput(args: any): UserInput { + const globalOptions: GlobalOptions = { + app: args.app, + build: args.build, + context: args.context, + plugin: args.plugin, + trace: args.trace, + strict: args.strict, + lookups: args.lookups, + ignoreErrors: args.ignoreErrors, + json: args.json, + verbose: args.verbose, + debug: args.debug, + profile: args.profile, + proxy: args.proxy, + caBundlePath: args.caBundlePath, + ec2creds: args.ec2creds, + versionReporting: args.versionReporting, + pathMetadata: args.pathMetadata, + assetMetadata: args.assetMetadata, + roleArn: args.roleArn, + staging: args.staging, + output: args.output, + notices: args.notices, + noColor: args.noColor, + ci: args.ci, + unstable: args.unstable, + }; + let commandOptions; + switch (args._[0] as Command) { + case 'list': + commandOptions = { + long: args.long, + showDependencies: args.showDependencies, + STACKS: args.STACKS, + }; + break; + + case 'synthesize': + commandOptions = { + exclusively: args.exclusively, + validation: args.validation, + quiet: args.quiet, + STACKS: args.STACKS, + }; + break; + + case 'bootstrap': + commandOptions = { + bootstrapBucketName: args.bootstrapBucketName, + bootstrapKmsKeyId: args.bootstrapKmsKeyId, + examplePermissionsBoundary: args.examplePermissionsBoundary, + customPermissionsBoundary: args.customPermissionsBoundary, + bootstrapCustomerKey: args.bootstrapCustomerKey, + qualifier: args.qualifier, + publicAccessBlockConfiguration: args.publicAccessBlockConfiguration, + tags: args.tags, + execute: args.execute, + trust: args.trust, + trustForLookup: args.trustForLookup, + cloudformationExecutionPolicies: args.cloudformationExecutionPolicies, + force: args.force, + terminationProtection: args.terminationProtection, + showTemplate: args.showTemplate, + toolkitStackName: args.toolkitStackName, + template: args.template, + previousParameters: args.previousParameters, + ENVIRONMENTS: args.ENVIRONMENTS, + }; + break; + + case 'gc': + commandOptions = { + action: args.action, + type: args.type, + rollbackBufferDays: args.rollbackBufferDays, + createdBufferDays: args.createdBufferDays, + confirm: args.confirm, + bootstrapStackName: args.bootstrapStackName, + ENVIRONMENTS: args.ENVIRONMENTS, + }; + break; + + case 'deploy': + commandOptions = { + all: args.all, + buildExclude: args.buildExclude, + exclusively: args.exclusively, + requireApproval: args.requireApproval, + notificationArns: args.notificationArns, + tags: args.tags, + execute: args.execute, + changeSetName: args.changeSetName, + method: args.method, + importExistingResources: args.importExistingResources, + force: args.force, + parameters: args.parameters, + outputsFile: args.outputsFile, + previousParameters: args.previousParameters, + toolkitStackName: args.toolkitStackName, + progress: args.progress, + rollback: args.rollback, + hotswap: args.hotswap, + hotswapFallback: args.hotswapFallback, + watch: args.watch, + logs: args.logs, + concurrency: args.concurrency, + assetParallelism: args.assetParallelism, + assetPrebuild: args.assetPrebuild, + ignoreNoStacks: args.ignoreNoStacks, + STACKS: args.STACKS, + }; + break; + + case 'rollback': + commandOptions = { + all: args.all, + toolkitStackName: args.toolkitStackName, + force: args.force, + validateBootstrapVersion: args.validateBootstrapVersion, + orphan: args.orphan, + STACKS: args.STACKS, + }; + break; + + case 'import': + commandOptions = { + execute: args.execute, + changeSetName: args.changeSetName, + toolkitStackName: args.toolkitStackName, + rollback: args.rollback, + force: args.force, + recordResourceMapping: args.recordResourceMapping, + resourceMapping: args.resourceMapping, + STACK: args.STACK, + }; + break; + + case 'watch': + commandOptions = { + buildExclude: args.buildExclude, + exclusively: args.exclusively, + changeSetName: args.changeSetName, + force: args.force, + toolkitStackName: args.toolkitStackName, + progress: args.progress, + rollback: args.rollback, + hotswap: args.hotswap, + hotswapFallback: args.hotswapFallback, + logs: args.logs, + concurrency: args.concurrency, + STACKS: args.STACKS, + }; + break; + + case 'destroy': + commandOptions = { + all: args.all, + exclusively: args.exclusively, + force: args.force, + STACKS: args.STACKS, + }; + break; + + case 'diff': + commandOptions = { + exclusively: args.exclusively, + contextLines: args.contextLines, + template: args.template, + strict: args.strict, + securityOnly: args.securityOnly, + fail: args.fail, + processed: args.processed, + quiet: args.quiet, + changeSet: args.changeSet, + STACKS: args.STACKS, + }; + break; + + case 'metadata': + commandOptions = { + STACK: args.STACK, + }; + break; + + case 'acknowledge': + commandOptions = { + ID: args.ID, + }; + break; + + case 'notices': + commandOptions = { + unacknowledged: args.unacknowledged, + }; + break; + + case 'init': + commandOptions = { + language: args.language, + list: args.list, + generateOnly: args.generateOnly, + TEMPLATE: args.TEMPLATE, + }; + break; + + case 'migrate': + commandOptions = { + stackName: args.stackName, + language: args.language, + account: args.account, + region: args.region, + fromPath: args.fromPath, + fromStack: args.fromStack, + outputPath: args.outputPath, + fromScan: args.fromScan, + filter: args.filter, + compress: args.compress, + }; + break; + + case 'context': + commandOptions = { + reset: args.reset, + force: args.force, + clear: args.clear, + }; + break; + + case 'docs': + commandOptions = { + browser: args.browser, + }; + break; + + case 'doctor': + commandOptions = {}; + break; + } + const userInput: UserInput = { + _: args._[0], + globalOptions, + [args._[0]]: commandOptions, + }; + + return userInput; +} diff --git a/packages/aws-cdk/lib/user-input.ts b/packages/aws-cdk/lib/user-input.ts new file mode 100644 index 0000000000000..cb850b9e86b00 --- /dev/null +++ b/packages/aws-cdk/lib/user-input.ts @@ -0,0 +1,1327 @@ +// ------------------------------------------------------------------------------------------- +// GENERATED FROM packages/aws-cdk/lib/config.ts. +// Do not edit by hand; all changes will be overwritten at build time from the config file. +// ------------------------------------------------------------------------------------------- +/* eslint-disable @stylistic/max-len */ +import { Command } from './settings'; + +/** + * The structure of the user input -- either CLI options or cdk.json -- generated from packages/aws-cdk/lib/config.ts + * + * @struct + */ +export interface UserInput { + /** + * The CLI command name + */ + readonly _: Command; + + /** + * Global options available to all CLI commands + */ + readonly globalOptions?: GlobalOptions; + + /** + * Lists all stacks in the app + * + * aliases: ls + */ + readonly list?: ListOptions; + + /** + * Synthesizes and prints the CloudFormation template for this stack + * + * aliases: synth + */ + readonly synthesize?: SynthesizeOptions; + + /** + * Deploys the CDK toolkit stack into an AWS environment + */ + readonly bootstrap?: BootstrapOptions; + + /** + * Garbage collect assets. Options detailed here: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk/README.md#cdk-gc + */ + readonly gc?: GcOptions; + + /** + * Deploys the stack(s) named STACKS into your AWS account + */ + readonly deploy?: DeployOptions; + + /** + * Rolls back the stack(s) named STACKS to their last stable state + */ + readonly rollback?: RollbackOptions; + + /** + * Import existing resource(s) into the given STACK + */ + readonly import?: ImportOptions; + + /** + * Shortcut for 'deploy --watch' + */ + readonly watch?: WatchOptions; + + /** + * Destroy the stack(s) named STACKS + */ + readonly destroy?: DestroyOptions; + + /** + * Compares the specified stack with the deployed stack or a local template file, and returns with status 1 if any difference is found + */ + readonly diff?: DiffOptions; + + /** + * Returns all metadata associated with this stack + */ + readonly metadata?: MetadataOptions; + + /** + * Acknowledge a notice so that it does not show up anymore + * + * aliases: ack + */ + readonly acknowledge?: AcknowledgeOptions; + + /** + * Returns a list of relevant notices + */ + readonly notices?: NoticesOptions; + + /** + * Create a new, empty CDK project from a template. + */ + readonly init?: InitOptions; + + /** + * Migrate existing AWS resources into a CDK app + */ + readonly migrate?: MigrateOptions; + + /** + * Manage cached context values + */ + readonly context?: ContextOptions; + + /** + * Opens the reference documentation in a browser + * + * aliases: doc + */ + readonly docs?: DocsOptions; + + /** + * Check your set-up for potential problems + */ + readonly doctor?: DoctorOptions; +} + +/** + * Global options available to all CLI commands + * + * @struct + */ +export interface GlobalOptions { + /** + * REQUIRED WHEN RUNNING APP: command-line for executing your app or a cloud assembly directory (e.g. "node bin/my-app.js"). Can also be specified in cdk.json or ~/.cdk.json + * + * @default - undefined + */ + readonly app?: string; + + /** + * Command-line for a pre-synth build + * + * @default - undefined + */ + readonly build?: string; + + /** + * Add contextual string parameter (KEY=VALUE) + * + * @default - [] + */ + readonly context?: Array; + + /** + * Name or path of a node package that extend the CDK features. Can be specified multiple times + * + * @default - [] + */ + readonly plugin?: Array; + + /** + * Print trace for stack warnings + * + * @default - undefined + */ + readonly trace?: boolean; + + /** + * Do not construct stacks with warnings + * + * @default - undefined + */ + readonly strict?: boolean; + + /** + * Perform context lookups (synthesis fails if this is disabled and context lookups need to be performed) + * + * @default - true + */ + readonly lookups?: boolean; + + /** + * Ignores synthesis errors, which will likely produce an invalid output + * + * @default - false + */ + readonly ignoreErrors?: boolean; + + /** + * Use JSON output instead of YAML when templates are printed to STDOUT + * + * @default - false + */ + readonly json?: boolean; + + /** + * Show debug logs (specify multiple times to increase verbosity) + * + * @default - false + */ + readonly verbose?: number; + + /** + * Debug the CDK app. Log additional information during synthesis, such as creation stack traces of tokens (sets CDK_DEBUG, will slow down synthesis) + * + * @default - false + */ + readonly debug?: boolean; + + /** + * Use the indicated AWS profile as the default environment + * + * @default - undefined + */ + readonly profile?: string; + + /** + * Use the indicated proxy. Will read from HTTPS_PROXY environment variable if not specified + * + * @default - undefined + */ + readonly proxy?: string; + + /** + * Path to CA certificate to use when validating HTTPS requests. Will read from AWS_CA_BUNDLE environment variable if not specified + * + * @default - undefined + */ + readonly caBundlePath?: string; + + /** + * Force trying to fetch EC2 instance credentials. Default: guess EC2 instance status + * + * @default - undefined + */ + readonly ec2creds?: boolean; + + /** + * Include the "AWS::CDK::Metadata" resource in synthesized templates (enabled by default) + * + * @default - undefined + */ + readonly versionReporting?: boolean; + + /** + * Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default) + * + * @default - undefined + */ + readonly pathMetadata?: boolean; + + /** + * Include "aws:asset:*" CloudFormation metadata for resources that uses assets (enabled by default) + * + * @default - undefined + */ + readonly assetMetadata?: boolean; + + /** + * ARN of Role to use when invoking CloudFormation + * + * @default - undefined + */ + readonly roleArn?: string; + + /** + * Copy assets to the output directory (use --no-staging to disable the copy of assets which allows local debugging via the SAM CLI to reference the original source files) + * + * @default - true + */ + readonly staging?: boolean; + + /** + * Emits the synthesized cloud assembly into a directory (default: cdk.out) + * + * @default - undefined + */ + readonly output?: string; + + /** + * Show relevant notices + * + * @default - undefined + */ + readonly notices?: boolean; + + /** + * Removes colors and other style from console output + * + * @default - false + */ + readonly noColor?: boolean; + + /** + * Force CI detection. If CI=true then logs will be sent to stdout instead of stderr + * + * @default - undefined + */ + readonly ci?: boolean; + + /** + * Opt in to unstable features. The flag indicates that the scope and API of a feature might still change. Otherwise the feature is generally production ready and fully supported. Can be specified multiple times. + * + * @default - [] + */ + readonly unstable?: Array; +} + +/** + * Lists all stacks in the app + * + * aliases: ls + * + * @struct + */ +export interface ListOptions { + /** + * Display environment information for each stack + * + * aliases: l + * + * @default - false + */ + readonly long?: boolean; + + /** + * Display stack dependency information for each stack + * + * aliases: d + * + * @default - false + */ + readonly showDependencies?: boolean; + + /** + * Positional argument for list + */ + readonly STACKS?: Array; +} + +/** + * Synthesizes and prints the CloudFormation template for this stack + * + * aliases: synth + * + * @struct + */ +export interface SynthesizeOptions { + /** + * Only synthesize requested stacks, don't include dependencies + * + * aliases: e + * + * @default - undefined + */ + readonly exclusively?: boolean; + + /** + * After synthesis, validate stacks with the "validateOnSynth" attribute set (can also be controlled with CDK_VALIDATION) + * + * @default - true + */ + readonly validation?: boolean; + + /** + * Do not output CloudFormation Template to stdout + * + * aliases: q + * + * @default - false + */ + readonly quiet?: boolean; + + /** + * Positional argument for synthesize + */ + readonly STACKS?: Array; +} + +/** + * Deploys the CDK toolkit stack into an AWS environment + * + * @struct + */ +export interface BootstrapOptions { + /** + * The name of the CDK toolkit bucket; bucket will be created and must not exist + * + * aliases: b toolkit-bucket-name + * + * @default - undefined + */ + readonly bootstrapBucketName?: string; + + /** + * AWS KMS master key ID used for the SSE-KMS encryption + * + * @default - undefined + */ + readonly bootstrapKmsKeyId?: string; + + /** + * Use the example permissions boundary. + * + * aliases: epb + * + * @default - undefined + */ + readonly examplePermissionsBoundary?: boolean; + + /** + * Use the permissions boundary specified by name. + * + * aliases: cpb + * + * @default - undefined + */ + readonly customPermissionsBoundary?: string; + + /** + * Create a Customer Master Key (CMK) for the bootstrap bucket (you will be charged but can customize permissions, modern bootstrapping only) + * + * @default - undefined + */ + readonly bootstrapCustomerKey?: boolean; + + /** + * String which must be unique for each bootstrap stack. You must configure it on your CDK app if you change this from the default. + * + * @default - undefined + */ + readonly qualifier?: string; + + /** + * Block public access configuration on CDK toolkit bucket (enabled by default) + * + * @default - undefined + */ + readonly publicAccessBlockConfiguration?: boolean; + + /** + * Tags to add for the stack (KEY=VALUE) + * + * aliases: t + * + * @default - [] + */ + readonly tags?: Array; + + /** + * Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet) + * + * @default - true + */ + readonly execute?: boolean; + + /** + * The AWS account IDs that should be trusted to perform deployments into this environment (may be repeated, modern bootstrapping only) + * + * @default - [] + */ + readonly trust?: Array; + + /** + * The AWS account IDs that should be trusted to look up values in this environment (may be repeated, modern bootstrapping only) + * + * @default - [] + */ + readonly trustForLookup?: Array; + + /** + * The Managed Policy ARNs that should be attached to the role performing deployments into this environment (may be repeated, modern bootstrapping only) + * + * @default - [] + */ + readonly cloudformationExecutionPolicies?: Array; + + /** + * Always bootstrap even if it would downgrade template version + * + * aliases: f + * + * @default - false + */ + readonly force?: boolean; + + /** + * Toggle CloudFormation termination protection on the bootstrap stacks + * + * @default - undefined + */ + readonly terminationProtection?: boolean; + + /** + * Instead of actual bootstrapping, print the current CLI's bootstrapping template to stdout for customization + * + * @default - false + */ + readonly showTemplate?: boolean; + + /** + * The name of the CDK toolkit stack to create + * + * @default - undefined + */ + readonly toolkitStackName?: string; + + /** + * Use the template from the given file instead of the built-in one (use --show-template to obtain an example) + * + * @default - undefined + */ + readonly template?: string; + + /** + * Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled) + * + * @default - true + */ + readonly previousParameters?: boolean; + + /** + * Positional argument for bootstrap + */ + readonly ENVIRONMENTS?: Array; +} + +/** + * Garbage collect assets. Options detailed here: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk/README.md#cdk-gc + * + * @struct + */ +export interface GcOptions { + /** + * The action (or sub-action) you want to perform. Valid entires are "print", "tag", "delete-tagged", "full". + * + * @default - "full" + */ + readonly action?: string; + + /** + * Specify either ecr, s3, or all + * + * @default - "all" + */ + readonly type?: string; + + /** + * Delete assets that have been marked as isolated for this many days + * + * @default - 0 + */ + readonly rollbackBufferDays?: number; + + /** + * Never delete assets younger than this (in days) + * + * @default - 1 + */ + readonly createdBufferDays?: number; + + /** + * Confirm via manual prompt before deletion + * + * @default - true + */ + readonly confirm?: boolean; + + /** + * The name of the CDK toolkit stack, if different from the default "CDKToolkit" + * + * @default - undefined + */ + readonly bootstrapStackName?: string; + + /** + * Positional argument for gc + */ + readonly ENVIRONMENTS?: Array; +} + +/** + * Deploys the stack(s) named STACKS into your AWS account + * + * @struct + */ +export interface DeployOptions { + /** + * Deploy all available stacks + * + * @default - false + */ + readonly all?: boolean; + + /** + * Do not rebuild asset with the given ID. Can be specified multiple times + * + * aliases: E + * + * @default - [] + */ + readonly buildExclude?: Array; + + /** + * Only deploy requested stacks, don't include dependencies + * + * aliases: e + * + * @default - undefined + */ + readonly exclusively?: boolean; + + /** + * What security-sensitive changes need manual approval + * + * @default - undefined + */ + readonly requireApproval?: string; + + /** + * ARNs of SNS topics that CloudFormation will notify with stack related events. These will be added to ARNs specified with the 'notificationArns' stack property. + * + * @default - undefined + */ + readonly notificationArns?: Array; + + /** + * Tags to add to the stack (KEY=VALUE), overrides tags from Cloud Assembly (deprecated) + * + * aliases: t + * + * @default - [] + */ + readonly tags?: Array; + + /** + * Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet) (deprecated) + * + * @deprecated true + * @default - undefined + */ + readonly execute?: boolean; + + /** + * Name of the CloudFormation change set to create (only if method is not direct) + * + * @default - undefined + */ + readonly changeSetName?: string; + + /** + * How to perform the deployment. Direct is a bit faster but lacks progress information + * + * aliases: m + * + * @default - undefined + */ + readonly method?: string; + + /** + * Indicates if the stack set imports resources that already exist. + * + * @default - false + */ + readonly importExistingResources?: boolean; + + /** + * Always deploy stack even if templates are identical + * + * aliases: f + * + * @default - false + */ + readonly force?: boolean; + + /** + * Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE) + * + * @default - {} + */ + readonly parameters?: Array; + + /** + * Path to file where stack outputs will be written as JSON + * + * aliases: O + * + * @default - undefined + */ + readonly outputsFile?: string; + + /** + * Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled) + * + * @default - true + */ + readonly previousParameters?: boolean; + + /** + * The name of the existing CDK toolkit stack (only used for app using legacy synthesis) + * + * @default - undefined + */ + readonly toolkitStackName?: string; + + /** + * Display mode for stack activity events + * + * @default - undefined + */ + readonly progress?: string; + + /** + * Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. Note: do **not** disable this flag for deployments with resource replacements, as that will always fail + * + * @default - undefined + */ + readonly rollback?: boolean; + + /** + * Attempts to perform a 'hotswap' deployment, but does not fall back to a full deployment if that is not possible. Instead, changes to any non-hotswappable properties are ignored.Do not use this in production environments + * + * @default - undefined + */ + readonly hotswap?: boolean; + + /** + * Attempts to perform a 'hotswap' deployment, which skips CloudFormation and updates the resources directly, and falls back to a full deployment if that is not possible. Do not use this in production environments + * + * @default - undefined + */ + readonly hotswapFallback?: boolean; + + /** + * Continuously observe the project files, and deploy the given stack(s) automatically when changes are detected. Implies --hotswap by default + * + * @default - undefined + */ + readonly watch?: boolean; + + /** + * Show CloudWatch log events from all resources in the selected Stacks in the terminal. 'true' by default, use --no-logs to turn off. Only in effect if specified alongside the '--watch' option + * + * @default - true + */ + readonly logs?: boolean; + + /** + * Maximum number of simultaneous deployments (dependency permitting) to execute. + * + * @default - 1 + */ + readonly concurrency?: number; + + /** + * Whether to build/publish assets in parallel + * + * @default - undefined + */ + readonly assetParallelism?: boolean; + + /** + * Whether to build all assets before deploying the first stack (useful for failing Docker builds) + * + * @default - true + */ + readonly assetPrebuild?: boolean; + + /** + * Whether to deploy if the app contains no stacks + * + * @default - false + */ + readonly ignoreNoStacks?: boolean; + + /** + * Positional argument for deploy + */ + readonly STACKS?: Array; +} + +/** + * Rolls back the stack(s) named STACKS to their last stable state + * + * @struct + */ +export interface RollbackOptions { + /** + * Roll back all available stacks + * + * @default - false + */ + readonly all?: boolean; + + /** + * The name of the CDK toolkit stack the environment is bootstrapped with + * + * @default - undefined + */ + readonly toolkitStackName?: string; + + /** + * Orphan all resources for which the rollback operation fails. + * + * aliases: f + * + * @default - undefined + */ + readonly force?: boolean; + + /** + * Whether to validate the bootstrap stack version. Defaults to 'true', disable with --no-validate-bootstrap-version. + * + * @default - undefined + */ + readonly validateBootstrapVersion?: boolean; + + /** + * Orphan the given resources, identified by their logical ID (can be specified multiple times) + * + * @default - [] + */ + readonly orphan?: Array; + + /** + * Positional argument for rollback + */ + readonly STACKS?: Array; +} + +/** + * Import existing resource(s) into the given STACK + * + * @struct + */ +export interface ImportOptions { + /** + * Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet) + * + * @default - true + */ + readonly execute?: boolean; + + /** + * Name of the CloudFormation change set to create + * + * @default - undefined + */ + readonly changeSetName?: string; + + /** + * The name of the CDK toolkit stack to create + * + * @default - undefined + */ + readonly toolkitStackName?: string; + + /** + * Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. Note: do **not** disable this flag for deployments with resource replacements, as that will always fail + * + * @default - undefined + */ + readonly rollback?: boolean; + + /** + * Do not abort if the template diff includes updates or deletes. This is probably safe but we're not sure, let us know how it goes. + * + * aliases: f + * + * @default - undefined + */ + readonly force?: boolean; + + /** + * If specified, CDK will generate a mapping of existing physical resources to CDK resources to be imported as. The mapping will be written in the given file path. No actual import operation will be performed + * + * aliases: r + * + * @default - undefined + */ + readonly recordResourceMapping?: string; + + /** + * If specified, CDK will use the given file to map physical resources to CDK resources for import, instead of interactively asking the user. Can be run from scripts + * + * aliases: m + * + * @default - undefined + */ + readonly resourceMapping?: string; + + /** + * Positional argument for import + */ + readonly STACK?: string; +} + +/** + * Shortcut for 'deploy --watch' + * + * @struct + */ +export interface WatchOptions { + /** + * Do not rebuild asset with the given ID. Can be specified multiple times + * + * aliases: E + * + * @default - [] + */ + readonly buildExclude?: Array; + + /** + * Only deploy requested stacks, don't include dependencies + * + * aliases: e + * + * @default - undefined + */ + readonly exclusively?: boolean; + + /** + * Name of the CloudFormation change set to create + * + * @default - undefined + */ + readonly changeSetName?: string; + + /** + * Always deploy stack even if templates are identical + * + * aliases: f + * + * @default - false + */ + readonly force?: boolean; + + /** + * The name of the existing CDK toolkit stack (only used for app using legacy synthesis) + * + * @default - undefined + */ + readonly toolkitStackName?: string; + + /** + * Display mode for stack activity events + * + * @default - undefined + */ + readonly progress?: string; + + /** + * Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. Note: do **not** disable this flag for deployments with resource replacements, as that will always fail + * + * @default - undefined + */ + readonly rollback?: boolean; + + /** + * Attempts to perform a 'hotswap' deployment, but does not fall back to a full deployment if that is not possible. Instead, changes to any non-hotswappable properties are ignored.'true' by default, use --no-hotswap to turn off + * + * @default - undefined + */ + readonly hotswap?: boolean; + + /** + * Attempts to perform a 'hotswap' deployment, which skips CloudFormation and updates the resources directly, and falls back to a full deployment if that is not possible. + * + * @default - undefined + */ + readonly hotswapFallback?: boolean; + + /** + * Show CloudWatch log events from all resources in the selected Stacks in the terminal. 'true' by default, use --no-logs to turn off + * + * @default - true + */ + readonly logs?: boolean; + + /** + * Maximum number of simultaneous deployments (dependency permitting) to execute. + * + * @default - 1 + */ + readonly concurrency?: number; + + /** + * Positional argument for watch + */ + readonly STACKS?: Array; +} + +/** + * Destroy the stack(s) named STACKS + * + * @struct + */ +export interface DestroyOptions { + /** + * Destroy all available stacks + * + * @default - false + */ + readonly all?: boolean; + + /** + * Only destroy requested stacks, don't include dependees + * + * aliases: e + * + * @default - undefined + */ + readonly exclusively?: boolean; + + /** + * Do not ask for confirmation before destroying the stacks + * + * aliases: f + * + * @default - undefined + */ + readonly force?: boolean; + + /** + * Positional argument for destroy + */ + readonly STACKS?: Array; +} + +/** + * Compares the specified stack with the deployed stack or a local template file, and returns with status 1 if any difference is found + * + * @struct + */ +export interface DiffOptions { + /** + * Only diff requested stacks, don't include dependencies + * + * aliases: e + * + * @default - undefined + */ + readonly exclusively?: boolean; + + /** + * Number of context lines to include in arbitrary JSON diff rendering + * + * @default - 3 + */ + readonly contextLines?: number; + + /** + * The path to the CloudFormation template to compare with + * + * @default - undefined + */ + readonly template?: string; + + /** + * Do not filter out AWS::CDK::Metadata resources, mangled non-ASCII characters, or the CheckBootstrapVersionRule + * + * @default - false + */ + readonly strict?: boolean; + + /** + * Only diff for broadened security changes + * + * @default - false + */ + readonly securityOnly?: boolean; + + /** + * Fail with exit code 1 in case of diff + * + * @default - undefined + */ + readonly fail?: boolean; + + /** + * Whether to compare against the template with Transforms already processed + * + * @default - false + */ + readonly processed?: boolean; + + /** + * Do not print stack name and default message when there is no diff to stdout + * + * aliases: q + * + * @default - false + */ + readonly quiet?: boolean; + + /** + * Whether to create a changeset to analyze resource replacements. In this mode, diff will use the deploy role instead of the lookup role. + * + * aliases: changeset + * + * @default - true + */ + readonly changeSet?: boolean; + + /** + * Positional argument for diff + */ + readonly STACKS?: Array; +} + +/** + * Returns all metadata associated with this stack + * + * @struct + */ +export interface MetadataOptions { + /** + * Positional argument for metadata + */ + readonly STACK?: string; +} + +/** + * Acknowledge a notice so that it does not show up anymore + * + * aliases: ack + * + * @struct + */ +export interface AcknowledgeOptions { + /** + * Positional argument for acknowledge + */ + readonly ID?: string; +} + +/** + * Returns a list of relevant notices + * + * @struct + */ +export interface NoticesOptions { + /** + * Returns a list of unacknowledged notices + * + * aliases: u + * + * @default - false + */ + readonly unacknowledged?: boolean; +} + +/** + * Create a new, empty CDK project from a template. + * + * @struct + */ +export interface InitOptions { + /** + * The language to be used for the new project (default can be configured in ~/.cdk.json) + * + * aliases: l + * + * @default - undefined + */ + readonly language?: string; + + /** + * List the available templates + * + * @default - undefined + */ + readonly list?: boolean; + + /** + * If true, only generates project files, without executing additional operations such as setting up a git repo, installing dependencies or compiling the project + * + * @default - false + */ + readonly generateOnly?: boolean; + + /** + * Positional argument for init + */ + readonly TEMPLATE?: string; +} + +/** + * Migrate existing AWS resources into a CDK app + * + * @struct + */ +export interface MigrateOptions { + /** + * The name assigned to the stack created in the new project. The name of the app will be based off this name as well. + * + * aliases: n + * + * @default - undefined + */ + readonly stackName?: string; + + /** + * The language to be used for the new project + * + * aliases: l + * + * @default - "typescript" + */ + readonly language?: string; + + /** + * The account to retrieve the CloudFormation stack template from + * + * @default - undefined + */ + readonly account?: string; + + /** + * The region to retrieve the CloudFormation stack template from + * + * @default - undefined + */ + readonly region?: string; + + /** + * The path to the CloudFormation template to migrate. Use this for locally stored templates + * + * @default - undefined + */ + readonly fromPath?: string; + + /** + * Use this flag to retrieve the template for an existing CloudFormation stack + * + * @default - undefined + */ + readonly fromStack?: boolean; + + /** + * The output path for the migrated CDK app + * + * @default - undefined + */ + readonly outputPath?: string; + + /** + * Determines if a new scan should be created, or the last successful existing scan should be used + * options are "new" or "most-recent" + * + * @default - undefined + */ + readonly fromScan?: string; + + /** + * Filters the resource scan based on the provided criteria in the following format: "key1=value1,key2=value2" + * This field can be passed multiple times for OR style filtering: + * filtering options: + * resource-identifier: A key-value pair that identifies the target resource. i.e. {"ClusterName", "myCluster"} + * resource-type-prefix: A string that represents a type-name prefix. i.e. "AWS::DynamoDB::" + * tag-key: a string that matches resources with at least one tag with the provided key. i.e. "myTagKey" + * tag-value: a string that matches resources with at least one tag with the provided value. i.e. "myTagValue" + * + * @default - [] + */ + readonly filter?: Array; + + /** + * Use this flag to zip the generated CDK app + * + * @default - undefined + */ + readonly compress?: boolean; +} + +/** + * Manage cached context values + * + * @struct + */ +export interface ContextOptions { + /** + * The context key (or its index) to reset + * + * aliases: e + * + * @default - undefined + */ + readonly reset?: string; + + /** + * Ignore missing key error + * + * aliases: f + * + * @default - false + */ + readonly force?: boolean; + + /** + * Clear all context + * + * @default - false + */ + readonly clear?: boolean; +} + +/** + * Opens the reference documentation in a browser + * + * aliases: doc + * + * @struct + */ +export interface DocsOptions { + /** + * the command to use to open the browser, using %u as a placeholder for the path of the file to open + * + * aliases: b + * + * @default - undefined + */ + readonly browser?: string; +} + +/** + * Check your set-up for potential problems + * + * @struct + */ +export interface DoctorOptions {} diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 609be4d5af8fa..e77fbb90d7ea2 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -7,7 +7,7 @@ }, "scripts": { "build": "cdk-build", - "cli-args-gen": "ts-node --preferTsExts scripts/cli-args-gen.ts", + "user-input-gen": "ts-node --preferTsExts scripts/user-input-gen.ts", "watch": "cdk-watch", "lint": "cdk-lint", "pkglint": "pkglint -f", @@ -29,7 +29,7 @@ }, "cdk-build": { "pre": [ - "yarn cli-args-gen" + "yarn user-input-gen" ], "post": [ "cp ../../node_modules/cdk-from-cfn/index_bg.wasm ./lib/", @@ -70,7 +70,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cli-plugin-contract": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@aws-cdk/cli-args-gen": "0.0.0", + "@aws-cdk/user-input-gen": "0.0.0", "@octokit/rest": "^18.12.0", "@types/archiver": "^5.3.4", "@types/fs-extra": "^9.0.13", diff --git a/packages/aws-cdk/scripts/cli-args-gen b/packages/aws-cdk/scripts/cli-args-gen deleted file mode 100755 index 29484fb39cf9f..0000000000000 --- a/packages/aws-cdk/scripts/cli-args-gen +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('./cli-args-gen.js'); diff --git a/packages/aws-cdk/scripts/cli-args-gen.ts b/packages/aws-cdk/scripts/cli-args-gen.ts deleted file mode 100644 index 68d53eeff0597..0000000000000 --- a/packages/aws-cdk/scripts/cli-args-gen.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as fs from 'fs'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { renderYargs, renderCliArgsType, renderCliArgsFunc } from '@aws-cdk/cli-args-gen'; -import { makeConfig, YARGS_HELPERS } from '../lib/config'; - -async function main() { - fs.writeFileSync('./lib/parse-command-line-arguments.ts', await renderYargs(await makeConfig(), YARGS_HELPERS)); - fs.writeFileSync('./lib/cli-arguments.ts', await renderCliArgsType(await makeConfig())); - fs.writeFileSync('./lib/convert-to-cli-args.ts', await renderCliArgsFunc(await makeConfig())); -} - -main().then(() => { -}).catch((e) => { - throw e; -}); diff --git a/packages/aws-cdk/scripts/user-input-gen b/packages/aws-cdk/scripts/user-input-gen new file mode 100755 index 0000000000000..8e9fe2a7c9bfc --- /dev/null +++ b/packages/aws-cdk/scripts/user-input-gen @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('./user-input-gen.js'); diff --git a/packages/aws-cdk/scripts/user-input-gen.ts b/packages/aws-cdk/scripts/user-input-gen.ts new file mode 100644 index 0000000000000..3ef7e03204165 --- /dev/null +++ b/packages/aws-cdk/scripts/user-input-gen.ts @@ -0,0 +1,16 @@ +import * as fs from 'fs'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { renderYargs, renderUserInputType, renderUserInputFuncs } from '@aws-cdk/user-input-gen'; +import { makeConfig, YARGS_HELPERS } from '../lib/config'; + +async function main() { + const config = await makeConfig(); + fs.writeFileSync('./lib/parse-command-line-arguments.ts', await renderYargs(config, YARGS_HELPERS)); + fs.writeFileSync('./lib/user-input.ts', await renderUserInputType(config)); + fs.writeFileSync('./lib/convert-to-user-input.ts', await renderUserInputFuncs(config)); +} + +main().then(() => { +}).catch((e) => { + throw e; +}); diff --git a/tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts b/tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts index 77c693795d048..a2cd333c96332 100644 --- a/tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts +++ b/tools/@aws-cdk/user-input-gen/lib/convert-to-user-input-gen.ts @@ -12,11 +12,10 @@ export async function renderUserInputFuncs(config: CliConfig): Promise { scope.documentation.push('Do not edit by hand; all changes will be overwritten at build time from the config file.'); scope.documentation.push('-------------------------------------------------------------------------------------------'); + scope.addImport(new SelectiveModuleImport(scope, './settings', ['Command'])); scope.addImport(new SelectiveModuleImport(scope, './user-input', ['UserInput', 'GlobalOptions'])); const userInputType = Type.fromName(scope, 'UserInput'); - scope.addImport(new SelectiveModuleImport(scope, './settings', ['Command'])); - const convertYargsToUserInput = new FreeFunction(scope, { name: 'convertYargsToUserInput', export: true, From 4912013b612e6be20f625423ac403347d5695285 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 16:41:33 -0500 Subject: [PATCH 5/8] update test --- .../user-input-gen/test/convert-to-user-input-gen.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts b/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts index 967b77d78486f..152df4c53e317 100644 --- a/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts +++ b/tools/@aws-cdk/user-input-gen/test/convert-to-user-input-gen.test.ts @@ -48,8 +48,8 @@ describe('render', () => { // Do not edit by hand; all changes will be overwritten at build time from the config file. // ------------------------------------------------------------------------------------------- /* eslint-disable @stylistic/max-len */ - import { UserInput, GlobalOptions } from './user-input'; import { Command } from './settings'; + import { UserInput, GlobalOptions } from './user-input'; // @ts-ignore TS6133 export function convertYargsToUserInput(args: any): UserInput { From 52445d15a0570f197c0fc8338cae0f8201bc4562 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 16:58:39 -0500 Subject: [PATCH 6/8] delete old files --- packages/aws-cdk/lib/cli-arguments.ts | 1327 ------------------- packages/aws-cdk/lib/convert-to-cli-args.ts | 256 ---- 2 files changed, 1583 deletions(-) delete mode 100644 packages/aws-cdk/lib/cli-arguments.ts delete mode 100644 packages/aws-cdk/lib/convert-to-cli-args.ts diff --git a/packages/aws-cdk/lib/cli-arguments.ts b/packages/aws-cdk/lib/cli-arguments.ts deleted file mode 100644 index 665f81b2ce9d1..0000000000000 --- a/packages/aws-cdk/lib/cli-arguments.ts +++ /dev/null @@ -1,1327 +0,0 @@ -// ------------------------------------------------------------------------------------------- -// GENERATED FROM packages/aws-cdk/lib/config.ts. -// Do not edit by hand; all changes will be overwritten at build time from the config file. -// ------------------------------------------------------------------------------------------- -/* eslint-disable @stylistic/max-len */ -import { Command } from './settings'; - -/** - * The structure of the CLI configuration, generated from packages/aws-cdk/lib/config.ts - * - * @struct - */ -export interface CliArguments { - /** - * The CLI command name - */ - readonly _: Command; - - /** - * Global options available to all CLI commands - */ - readonly globalOptions?: GlobalOptions; - - /** - * Lists all stacks in the app - * - * aliases: ls - */ - readonly list?: ListOptions; - - /** - * Synthesizes and prints the CloudFormation template for this stack - * - * aliases: synth - */ - readonly synthesize?: SynthesizeOptions; - - /** - * Deploys the CDK toolkit stack into an AWS environment - */ - readonly bootstrap?: BootstrapOptions; - - /** - * Garbage collect assets. Options detailed here: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk/README.md#cdk-gc - */ - readonly gc?: GcOptions; - - /** - * Deploys the stack(s) named STACKS into your AWS account - */ - readonly deploy?: DeployOptions; - - /** - * Rolls back the stack(s) named STACKS to their last stable state - */ - readonly rollback?: RollbackOptions; - - /** - * Import existing resource(s) into the given STACK - */ - readonly import?: ImportOptions; - - /** - * Shortcut for 'deploy --watch' - */ - readonly watch?: WatchOptions; - - /** - * Destroy the stack(s) named STACKS - */ - readonly destroy?: DestroyOptions; - - /** - * Compares the specified stack with the deployed stack or a local template file, and returns with status 1 if any difference is found - */ - readonly diff?: DiffOptions; - - /** - * Returns all metadata associated with this stack - */ - readonly metadata?: MetadataOptions; - - /** - * Acknowledge a notice so that it does not show up anymore - * - * aliases: ack - */ - readonly acknowledge?: AcknowledgeOptions; - - /** - * Returns a list of relevant notices - */ - readonly notices?: NoticesOptions; - - /** - * Create a new, empty CDK project from a template. - */ - readonly init?: InitOptions; - - /** - * Migrate existing AWS resources into a CDK app - */ - readonly migrate?: MigrateOptions; - - /** - * Manage cached context values - */ - readonly context?: ContextOptions; - - /** - * Opens the reference documentation in a browser - * - * aliases: doc - */ - readonly docs?: DocsOptions; - - /** - * Check your set-up for potential problems - */ - readonly doctor?: DoctorOptions; -} - -/** - * Global options available to all CLI commands - * - * @struct - */ -export interface GlobalOptions { - /** - * REQUIRED WHEN RUNNING APP: command-line for executing your app or a cloud assembly directory (e.g. "node bin/my-app.js"). Can also be specified in cdk.json or ~/.cdk.json - * - * @default - undefined - */ - readonly app?: string; - - /** - * Command-line for a pre-synth build - * - * @default - undefined - */ - readonly build?: string; - - /** - * Add contextual string parameter (KEY=VALUE) - * - * @default - [] - */ - readonly context?: Array; - - /** - * Name or path of a node package that extend the CDK features. Can be specified multiple times - * - * @default - [] - */ - readonly plugin?: Array; - - /** - * Print trace for stack warnings - * - * @default - undefined - */ - readonly trace?: boolean; - - /** - * Do not construct stacks with warnings - * - * @default - undefined - */ - readonly strict?: boolean; - - /** - * Perform context lookups (synthesis fails if this is disabled and context lookups need to be performed) - * - * @default - true - */ - readonly lookups?: boolean; - - /** - * Ignores synthesis errors, which will likely produce an invalid output - * - * @default - false - */ - readonly ignoreErrors?: boolean; - - /** - * Use JSON output instead of YAML when templates are printed to STDOUT - * - * @default - false - */ - readonly json?: boolean; - - /** - * Show debug logs (specify multiple times to increase verbosity) - * - * @default - false - */ - readonly verbose?: number; - - /** - * Debug the CDK app. Log additional information during synthesis, such as creation stack traces of tokens (sets CDK_DEBUG, will slow down synthesis) - * - * @default - false - */ - readonly debug?: boolean; - - /** - * Use the indicated AWS profile as the default environment - * - * @default - undefined - */ - readonly profile?: string; - - /** - * Use the indicated proxy. Will read from HTTPS_PROXY environment variable if not specified - * - * @default - undefined - */ - readonly proxy?: string; - - /** - * Path to CA certificate to use when validating HTTPS requests. Will read from AWS_CA_BUNDLE environment variable if not specified - * - * @default - undefined - */ - readonly caBundlePath?: string; - - /** - * Force trying to fetch EC2 instance credentials. Default: guess EC2 instance status - * - * @default - undefined - */ - readonly ec2creds?: boolean; - - /** - * Include the "AWS::CDK::Metadata" resource in synthesized templates (enabled by default) - * - * @default - undefined - */ - readonly versionReporting?: boolean; - - /** - * Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default) - * - * @default - undefined - */ - readonly pathMetadata?: boolean; - - /** - * Include "aws:asset:*" CloudFormation metadata for resources that uses assets (enabled by default) - * - * @default - undefined - */ - readonly assetMetadata?: boolean; - - /** - * ARN of Role to use when invoking CloudFormation - * - * @default - undefined - */ - readonly roleArn?: string; - - /** - * Copy assets to the output directory (use --no-staging to disable the copy of assets which allows local debugging via the SAM CLI to reference the original source files) - * - * @default - true - */ - readonly staging?: boolean; - - /** - * Emits the synthesized cloud assembly into a directory (default: cdk.out) - * - * @default - undefined - */ - readonly output?: string; - - /** - * Show relevant notices - * - * @default - undefined - */ - readonly notices?: boolean; - - /** - * Removes colors and other style from console output - * - * @default - false - */ - readonly noColor?: boolean; - - /** - * Force CI detection. If CI=true then logs will be sent to stdout instead of stderr - * - * @default - undefined - */ - readonly ci?: boolean; - - /** - * Opt in to unstable features. The flag indicates that the scope and API of a feature might still change. Otherwise the feature is generally production ready and fully supported. Can be specified multiple times. - * - * @default - [] - */ - readonly unstable?: Array; -} - -/** - * Lists all stacks in the app - * - * aliases: ls - * - * @struct - */ -export interface ListOptions { - /** - * Display environment information for each stack - * - * aliases: l - * - * @default - false - */ - readonly long?: boolean; - - /** - * Display stack dependency information for each stack - * - * aliases: d - * - * @default - false - */ - readonly showDependencies?: boolean; - - /** - * Positional argument for list - */ - readonly STACKS?: Array; -} - -/** - * Synthesizes and prints the CloudFormation template for this stack - * - * aliases: synth - * - * @struct - */ -export interface SynthesizeOptions { - /** - * Only synthesize requested stacks, don't include dependencies - * - * aliases: e - * - * @default - undefined - */ - readonly exclusively?: boolean; - - /** - * After synthesis, validate stacks with the "validateOnSynth" attribute set (can also be controlled with CDK_VALIDATION) - * - * @default - true - */ - readonly validation?: boolean; - - /** - * Do not output CloudFormation Template to stdout - * - * aliases: q - * - * @default - false - */ - readonly quiet?: boolean; - - /** - * Positional argument for synthesize - */ - readonly STACKS?: Array; -} - -/** - * Deploys the CDK toolkit stack into an AWS environment - * - * @struct - */ -export interface BootstrapOptions { - /** - * The name of the CDK toolkit bucket; bucket will be created and must not exist - * - * aliases: b toolkit-bucket-name - * - * @default - undefined - */ - readonly bootstrapBucketName?: string; - - /** - * AWS KMS master key ID used for the SSE-KMS encryption - * - * @default - undefined - */ - readonly bootstrapKmsKeyId?: string; - - /** - * Use the example permissions boundary. - * - * aliases: epb - * - * @default - undefined - */ - readonly examplePermissionsBoundary?: boolean; - - /** - * Use the permissions boundary specified by name. - * - * aliases: cpb - * - * @default - undefined - */ - readonly customPermissionsBoundary?: string; - - /** - * Create a Customer Master Key (CMK) for the bootstrap bucket (you will be charged but can customize permissions, modern bootstrapping only) - * - * @default - undefined - */ - readonly bootstrapCustomerKey?: boolean; - - /** - * String which must be unique for each bootstrap stack. You must configure it on your CDK app if you change this from the default. - * - * @default - undefined - */ - readonly qualifier?: string; - - /** - * Block public access configuration on CDK toolkit bucket (enabled by default) - * - * @default - undefined - */ - readonly publicAccessBlockConfiguration?: boolean; - - /** - * Tags to add for the stack (KEY=VALUE) - * - * aliases: t - * - * @default - [] - */ - readonly tags?: Array; - - /** - * Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet) - * - * @default - true - */ - readonly execute?: boolean; - - /** - * The AWS account IDs that should be trusted to perform deployments into this environment (may be repeated, modern bootstrapping only) - * - * @default - [] - */ - readonly trust?: Array; - - /** - * The AWS account IDs that should be trusted to look up values in this environment (may be repeated, modern bootstrapping only) - * - * @default - [] - */ - readonly trustForLookup?: Array; - - /** - * The Managed Policy ARNs that should be attached to the role performing deployments into this environment (may be repeated, modern bootstrapping only) - * - * @default - [] - */ - readonly cloudformationExecutionPolicies?: Array; - - /** - * Always bootstrap even if it would downgrade template version - * - * aliases: f - * - * @default - false - */ - readonly force?: boolean; - - /** - * Toggle CloudFormation termination protection on the bootstrap stacks - * - * @default - undefined - */ - readonly terminationProtection?: boolean; - - /** - * Instead of actual bootstrapping, print the current CLI's bootstrapping template to stdout for customization - * - * @default - false - */ - readonly showTemplate?: boolean; - - /** - * The name of the CDK toolkit stack to create - * - * @default - undefined - */ - readonly toolkitStackName?: string; - - /** - * Use the template from the given file instead of the built-in one (use --show-template to obtain an example) - * - * @default - undefined - */ - readonly template?: string; - - /** - * Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled) - * - * @default - true - */ - readonly previousParameters?: boolean; - - /** - * Positional argument for bootstrap - */ - readonly ENVIRONMENTS?: Array; -} - -/** - * Garbage collect assets. Options detailed here: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk/README.md#cdk-gc - * - * @struct - */ -export interface GcOptions { - /** - * The action (or sub-action) you want to perform. Valid entires are "print", "tag", "delete-tagged", "full". - * - * @default - "full" - */ - readonly action?: string; - - /** - * Specify either ecr, s3, or all - * - * @default - "all" - */ - readonly type?: string; - - /** - * Delete assets that have been marked as isolated for this many days - * - * @default - 0 - */ - readonly rollbackBufferDays?: number; - - /** - * Never delete assets younger than this (in days) - * - * @default - 1 - */ - readonly createdBufferDays?: number; - - /** - * Confirm via manual prompt before deletion - * - * @default - true - */ - readonly confirm?: boolean; - - /** - * The name of the CDK toolkit stack, if different from the default "CDKToolkit" - * - * @default - undefined - */ - readonly bootstrapStackName?: string; - - /** - * Positional argument for gc - */ - readonly ENVIRONMENTS?: Array; -} - -/** - * Deploys the stack(s) named STACKS into your AWS account - * - * @struct - */ -export interface DeployOptions { - /** - * Deploy all available stacks - * - * @default - false - */ - readonly all?: boolean; - - /** - * Do not rebuild asset with the given ID. Can be specified multiple times - * - * aliases: E - * - * @default - [] - */ - readonly buildExclude?: Array; - - /** - * Only deploy requested stacks, don't include dependencies - * - * aliases: e - * - * @default - undefined - */ - readonly exclusively?: boolean; - - /** - * What security-sensitive changes need manual approval - * - * @default - undefined - */ - readonly requireApproval?: string; - - /** - * ARNs of SNS topics that CloudFormation will notify with stack related events. These will be added to ARNs specified with the 'notificationArns' stack property. - * - * @default - undefined - */ - readonly notificationArns?: Array; - - /** - * Tags to add to the stack (KEY=VALUE), overrides tags from Cloud Assembly (deprecated) - * - * aliases: t - * - * @default - [] - */ - readonly tags?: Array; - - /** - * Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet) (deprecated) - * - * @deprecated true - * @default - undefined - */ - readonly execute?: boolean; - - /** - * Name of the CloudFormation change set to create (only if method is not direct) - * - * @default - undefined - */ - readonly changeSetName?: string; - - /** - * How to perform the deployment. Direct is a bit faster but lacks progress information - * - * aliases: m - * - * @default - undefined - */ - readonly method?: string; - - /** - * Indicates if the stack set imports resources that already exist. - * - * @default - false - */ - readonly importExistingResources?: boolean; - - /** - * Always deploy stack even if templates are identical - * - * aliases: f - * - * @default - false - */ - readonly force?: boolean; - - /** - * Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE) - * - * @default - {} - */ - readonly parameters?: Array; - - /** - * Path to file where stack outputs will be written as JSON - * - * aliases: O - * - * @default - undefined - */ - readonly outputsFile?: string; - - /** - * Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled) - * - * @default - true - */ - readonly previousParameters?: boolean; - - /** - * The name of the existing CDK toolkit stack (only used for app using legacy synthesis) - * - * @default - undefined - */ - readonly toolkitStackName?: string; - - /** - * Display mode for stack activity events - * - * @default - undefined - */ - readonly progress?: string; - - /** - * Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. Note: do **not** disable this flag for deployments with resource replacements, as that will always fail - * - * @default - undefined - */ - readonly rollback?: boolean; - - /** - * Attempts to perform a 'hotswap' deployment, but does not fall back to a full deployment if that is not possible. Instead, changes to any non-hotswappable properties are ignored.Do not use this in production environments - * - * @default - undefined - */ - readonly hotswap?: boolean; - - /** - * Attempts to perform a 'hotswap' deployment, which skips CloudFormation and updates the resources directly, and falls back to a full deployment if that is not possible. Do not use this in production environments - * - * @default - undefined - */ - readonly hotswapFallback?: boolean; - - /** - * Continuously observe the project files, and deploy the given stack(s) automatically when changes are detected. Implies --hotswap by default - * - * @default - undefined - */ - readonly watch?: boolean; - - /** - * Show CloudWatch log events from all resources in the selected Stacks in the terminal. 'true' by default, use --no-logs to turn off. Only in effect if specified alongside the '--watch' option - * - * @default - true - */ - readonly logs?: boolean; - - /** - * Maximum number of simultaneous deployments (dependency permitting) to execute. - * - * @default - 1 - */ - readonly concurrency?: number; - - /** - * Whether to build/publish assets in parallel - * - * @default - undefined - */ - readonly assetParallelism?: boolean; - - /** - * Whether to build all assets before deploying the first stack (useful for failing Docker builds) - * - * @default - true - */ - readonly assetPrebuild?: boolean; - - /** - * Whether to deploy if the app contains no stacks - * - * @default - false - */ - readonly ignoreNoStacks?: boolean; - - /** - * Positional argument for deploy - */ - readonly STACKS?: Array; -} - -/** - * Rolls back the stack(s) named STACKS to their last stable state - * - * @struct - */ -export interface RollbackOptions { - /** - * Roll back all available stacks - * - * @default - false - */ - readonly all?: boolean; - - /** - * The name of the CDK toolkit stack the environment is bootstrapped with - * - * @default - undefined - */ - readonly toolkitStackName?: string; - - /** - * Orphan all resources for which the rollback operation fails. - * - * aliases: f - * - * @default - undefined - */ - readonly force?: boolean; - - /** - * Whether to validate the bootstrap stack version. Defaults to 'true', disable with --no-validate-bootstrap-version. - * - * @default - undefined - */ - readonly validateBootstrapVersion?: boolean; - - /** - * Orphan the given resources, identified by their logical ID (can be specified multiple times) - * - * @default - [] - */ - readonly orphan?: Array; - - /** - * Positional argument for rollback - */ - readonly STACKS?: Array; -} - -/** - * Import existing resource(s) into the given STACK - * - * @struct - */ -export interface ImportOptions { - /** - * Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet) - * - * @default - true - */ - readonly execute?: boolean; - - /** - * Name of the CloudFormation change set to create - * - * @default - undefined - */ - readonly changeSetName?: string; - - /** - * The name of the CDK toolkit stack to create - * - * @default - undefined - */ - readonly toolkitStackName?: string; - - /** - * Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. Note: do **not** disable this flag for deployments with resource replacements, as that will always fail - * - * @default - undefined - */ - readonly rollback?: boolean; - - /** - * Do not abort if the template diff includes updates or deletes. This is probably safe but we're not sure, let us know how it goes. - * - * aliases: f - * - * @default - undefined - */ - readonly force?: boolean; - - /** - * If specified, CDK will generate a mapping of existing physical resources to CDK resources to be imported as. The mapping will be written in the given file path. No actual import operation will be performed - * - * aliases: r - * - * @default - undefined - */ - readonly recordResourceMapping?: string; - - /** - * If specified, CDK will use the given file to map physical resources to CDK resources for import, instead of interactively asking the user. Can be run from scripts - * - * aliases: m - * - * @default - undefined - */ - readonly resourceMapping?: string; - - /** - * Positional argument for import - */ - readonly STACK?: string; -} - -/** - * Shortcut for 'deploy --watch' - * - * @struct - */ -export interface WatchOptions { - /** - * Do not rebuild asset with the given ID. Can be specified multiple times - * - * aliases: E - * - * @default - [] - */ - readonly buildExclude?: Array; - - /** - * Only deploy requested stacks, don't include dependencies - * - * aliases: e - * - * @default - undefined - */ - readonly exclusively?: boolean; - - /** - * Name of the CloudFormation change set to create - * - * @default - undefined - */ - readonly changeSetName?: string; - - /** - * Always deploy stack even if templates are identical - * - * aliases: f - * - * @default - false - */ - readonly force?: boolean; - - /** - * The name of the existing CDK toolkit stack (only used for app using legacy synthesis) - * - * @default - undefined - */ - readonly toolkitStackName?: string; - - /** - * Display mode for stack activity events - * - * @default - undefined - */ - readonly progress?: string; - - /** - * Rollback stack to stable state on failure. Defaults to 'true', iterate more rapidly with --no-rollback or -R. Note: do **not** disable this flag for deployments with resource replacements, as that will always fail - * - * @default - undefined - */ - readonly rollback?: boolean; - - /** - * Attempts to perform a 'hotswap' deployment, but does not fall back to a full deployment if that is not possible. Instead, changes to any non-hotswappable properties are ignored.'true' by default, use --no-hotswap to turn off - * - * @default - undefined - */ - readonly hotswap?: boolean; - - /** - * Attempts to perform a 'hotswap' deployment, which skips CloudFormation and updates the resources directly, and falls back to a full deployment if that is not possible. - * - * @default - undefined - */ - readonly hotswapFallback?: boolean; - - /** - * Show CloudWatch log events from all resources in the selected Stacks in the terminal. 'true' by default, use --no-logs to turn off - * - * @default - true - */ - readonly logs?: boolean; - - /** - * Maximum number of simultaneous deployments (dependency permitting) to execute. - * - * @default - 1 - */ - readonly concurrency?: number; - - /** - * Positional argument for watch - */ - readonly STACKS?: Array; -} - -/** - * Destroy the stack(s) named STACKS - * - * @struct - */ -export interface DestroyOptions { - /** - * Destroy all available stacks - * - * @default - false - */ - readonly all?: boolean; - - /** - * Only destroy requested stacks, don't include dependees - * - * aliases: e - * - * @default - undefined - */ - readonly exclusively?: boolean; - - /** - * Do not ask for confirmation before destroying the stacks - * - * aliases: f - * - * @default - undefined - */ - readonly force?: boolean; - - /** - * Positional argument for destroy - */ - readonly STACKS?: Array; -} - -/** - * Compares the specified stack with the deployed stack or a local template file, and returns with status 1 if any difference is found - * - * @struct - */ -export interface DiffOptions { - /** - * Only diff requested stacks, don't include dependencies - * - * aliases: e - * - * @default - undefined - */ - readonly exclusively?: boolean; - - /** - * Number of context lines to include in arbitrary JSON diff rendering - * - * @default - 3 - */ - readonly contextLines?: number; - - /** - * The path to the CloudFormation template to compare with - * - * @default - undefined - */ - readonly template?: string; - - /** - * Do not filter out AWS::CDK::Metadata resources, mangled non-ASCII characters, or the CheckBootstrapVersionRule - * - * @default - false - */ - readonly strict?: boolean; - - /** - * Only diff for broadened security changes - * - * @default - false - */ - readonly securityOnly?: boolean; - - /** - * Fail with exit code 1 in case of diff - * - * @default - undefined - */ - readonly fail?: boolean; - - /** - * Whether to compare against the template with Transforms already processed - * - * @default - false - */ - readonly processed?: boolean; - - /** - * Do not print stack name and default message when there is no diff to stdout - * - * aliases: q - * - * @default - false - */ - readonly quiet?: boolean; - - /** - * Whether to create a changeset to analyze resource replacements. In this mode, diff will use the deploy role instead of the lookup role. - * - * aliases: changeset - * - * @default - true - */ - readonly changeSet?: boolean; - - /** - * Positional argument for diff - */ - readonly STACKS?: Array; -} - -/** - * Returns all metadata associated with this stack - * - * @struct - */ -export interface MetadataOptions { - /** - * Positional argument for metadata - */ - readonly STACK?: string; -} - -/** - * Acknowledge a notice so that it does not show up anymore - * - * aliases: ack - * - * @struct - */ -export interface AcknowledgeOptions { - /** - * Positional argument for acknowledge - */ - readonly ID?: string; -} - -/** - * Returns a list of relevant notices - * - * @struct - */ -export interface NoticesOptions { - /** - * Returns a list of unacknowledged notices - * - * aliases: u - * - * @default - false - */ - readonly unacknowledged?: boolean; -} - -/** - * Create a new, empty CDK project from a template. - * - * @struct - */ -export interface InitOptions { - /** - * The language to be used for the new project (default can be configured in ~/.cdk.json) - * - * aliases: l - * - * @default - undefined - */ - readonly language?: string; - - /** - * List the available templates - * - * @default - undefined - */ - readonly list?: boolean; - - /** - * If true, only generates project files, without executing additional operations such as setting up a git repo, installing dependencies or compiling the project - * - * @default - false - */ - readonly generateOnly?: boolean; - - /** - * Positional argument for init - */ - readonly TEMPLATE?: string; -} - -/** - * Migrate existing AWS resources into a CDK app - * - * @struct - */ -export interface MigrateOptions { - /** - * The name assigned to the stack created in the new project. The name of the app will be based off this name as well. - * - * aliases: n - * - * @default - undefined - */ - readonly stackName?: string; - - /** - * The language to be used for the new project - * - * aliases: l - * - * @default - "typescript" - */ - readonly language?: string; - - /** - * The account to retrieve the CloudFormation stack template from - * - * @default - undefined - */ - readonly account?: string; - - /** - * The region to retrieve the CloudFormation stack template from - * - * @default - undefined - */ - readonly region?: string; - - /** - * The path to the CloudFormation template to migrate. Use this for locally stored templates - * - * @default - undefined - */ - readonly fromPath?: string; - - /** - * Use this flag to retrieve the template for an existing CloudFormation stack - * - * @default - undefined - */ - readonly fromStack?: boolean; - - /** - * The output path for the migrated CDK app - * - * @default - undefined - */ - readonly outputPath?: string; - - /** - * Determines if a new scan should be created, or the last successful existing scan should be used - * options are "new" or "most-recent" - * - * @default - undefined - */ - readonly fromScan?: string; - - /** - * Filters the resource scan based on the provided criteria in the following format: "key1=value1,key2=value2" - * This field can be passed multiple times for OR style filtering: - * filtering options: - * resource-identifier: A key-value pair that identifies the target resource. i.e. {"ClusterName", "myCluster"} - * resource-type-prefix: A string that represents a type-name prefix. i.e. "AWS::DynamoDB::" - * tag-key: a string that matches resources with at least one tag with the provided key. i.e. "myTagKey" - * tag-value: a string that matches resources with at least one tag with the provided value. i.e. "myTagValue" - * - * @default - [] - */ - readonly filter?: Array; - - /** - * Use this flag to zip the generated CDK app - * - * @default - undefined - */ - readonly compress?: boolean; -} - -/** - * Manage cached context values - * - * @struct - */ -export interface ContextOptions { - /** - * The context key (or its index) to reset - * - * aliases: e - * - * @default - undefined - */ - readonly reset?: string; - - /** - * Ignore missing key error - * - * aliases: f - * - * @default - false - */ - readonly force?: boolean; - - /** - * Clear all context - * - * @default - false - */ - readonly clear?: boolean; -} - -/** - * Opens the reference documentation in a browser - * - * aliases: doc - * - * @struct - */ -export interface DocsOptions { - /** - * the command to use to open the browser, using %u as a placeholder for the path of the file to open - * - * aliases: b - * - * @default - undefined - */ - readonly browser?: string; -} - -/** - * Check your set-up for potential problems - * - * @struct - */ -export interface DoctorOptions {} diff --git a/packages/aws-cdk/lib/convert-to-cli-args.ts b/packages/aws-cdk/lib/convert-to-cli-args.ts deleted file mode 100644 index 3fc1b9a2bc541..0000000000000 --- a/packages/aws-cdk/lib/convert-to-cli-args.ts +++ /dev/null @@ -1,256 +0,0 @@ -// ------------------------------------------------------------------------------------------- -// GENERATED FROM packages/aws-cdk/lib/config.ts. -// Do not edit by hand; all changes will be overwritten at build time from the config file. -// ------------------------------------------------------------------------------------------- -/* eslint-disable @stylistic/max-len */ -import { CliArguments, GlobalOptions } from './cli-arguments'; -import { Command } from './settings'; - -// @ts-ignore TS6133 -export function convertToCliArgs(args: any): CliArguments { - const globalOptions: GlobalOptions = { - app: args.app, - build: args.build, - context: args.context, - plugin: args.plugin, - trace: args.trace, - strict: args.strict, - lookups: args.lookups, - ignoreErrors: args.ignoreErrors, - json: args.json, - verbose: args.verbose, - debug: args.debug, - profile: args.profile, - proxy: args.proxy, - caBundlePath: args.caBundlePath, - ec2creds: args.ec2creds, - versionReporting: args.versionReporting, - pathMetadata: args.pathMetadata, - assetMetadata: args.assetMetadata, - roleArn: args.roleArn, - staging: args.staging, - output: args.output, - notices: args.notices, - noColor: args.noColor, - ci: args.ci, - unstable: args.unstable, - }; - let commandOptions; - switch (args._[0] as Command) { - case 'list': - commandOptions = { - long: args.long, - showDependencies: args.showDependencies, - STACKS: args.STACKS, - }; - break; - - case 'synthesize': - commandOptions = { - exclusively: args.exclusively, - validation: args.validation, - quiet: args.quiet, - STACKS: args.STACKS, - }; - break; - - case 'bootstrap': - commandOptions = { - bootstrapBucketName: args.bootstrapBucketName, - bootstrapKmsKeyId: args.bootstrapKmsKeyId, - examplePermissionsBoundary: args.examplePermissionsBoundary, - customPermissionsBoundary: args.customPermissionsBoundary, - bootstrapCustomerKey: args.bootstrapCustomerKey, - qualifier: args.qualifier, - publicAccessBlockConfiguration: args.publicAccessBlockConfiguration, - tags: args.tags, - execute: args.execute, - trust: args.trust, - trustForLookup: args.trustForLookup, - cloudformationExecutionPolicies: args.cloudformationExecutionPolicies, - force: args.force, - terminationProtection: args.terminationProtection, - showTemplate: args.showTemplate, - toolkitStackName: args.toolkitStackName, - template: args.template, - previousParameters: args.previousParameters, - ENVIRONMENTS: args.ENVIRONMENTS, - }; - break; - - case 'gc': - commandOptions = { - action: args.action, - type: args.type, - rollbackBufferDays: args.rollbackBufferDays, - createdBufferDays: args.createdBufferDays, - confirm: args.confirm, - bootstrapStackName: args.bootstrapStackName, - ENVIRONMENTS: args.ENVIRONMENTS, - }; - break; - - case 'deploy': - commandOptions = { - all: args.all, - buildExclude: args.buildExclude, - exclusively: args.exclusively, - requireApproval: args.requireApproval, - notificationArns: args.notificationArns, - tags: args.tags, - execute: args.execute, - changeSetName: args.changeSetName, - method: args.method, - importExistingResources: args.importExistingResources, - force: args.force, - parameters: args.parameters, - outputsFile: args.outputsFile, - previousParameters: args.previousParameters, - toolkitStackName: args.toolkitStackName, - progress: args.progress, - rollback: args.rollback, - hotswap: args.hotswap, - hotswapFallback: args.hotswapFallback, - watch: args.watch, - logs: args.logs, - concurrency: args.concurrency, - assetParallelism: args.assetParallelism, - assetPrebuild: args.assetPrebuild, - ignoreNoStacks: args.ignoreNoStacks, - STACKS: args.STACKS, - }; - break; - - case 'rollback': - commandOptions = { - all: args.all, - toolkitStackName: args.toolkitStackName, - force: args.force, - validateBootstrapVersion: args.validateBootstrapVersion, - orphan: args.orphan, - STACKS: args.STACKS, - }; - break; - - case 'import': - commandOptions = { - execute: args.execute, - changeSetName: args.changeSetName, - toolkitStackName: args.toolkitStackName, - rollback: args.rollback, - force: args.force, - recordResourceMapping: args.recordResourceMapping, - resourceMapping: args.resourceMapping, - STACK: args.STACK, - }; - break; - - case 'watch': - commandOptions = { - buildExclude: args.buildExclude, - exclusively: args.exclusively, - changeSetName: args.changeSetName, - force: args.force, - toolkitStackName: args.toolkitStackName, - progress: args.progress, - rollback: args.rollback, - hotswap: args.hotswap, - hotswapFallback: args.hotswapFallback, - logs: args.logs, - concurrency: args.concurrency, - STACKS: args.STACKS, - }; - break; - - case 'destroy': - commandOptions = { - all: args.all, - exclusively: args.exclusively, - force: args.force, - STACKS: args.STACKS, - }; - break; - - case 'diff': - commandOptions = { - exclusively: args.exclusively, - contextLines: args.contextLines, - template: args.template, - strict: args.strict, - securityOnly: args.securityOnly, - fail: args.fail, - processed: args.processed, - quiet: args.quiet, - changeSet: args.changeSet, - STACKS: args.STACKS, - }; - break; - - case 'metadata': - commandOptions = { - STACK: args.STACK, - }; - break; - - case 'acknowledge': - commandOptions = { - ID: args.ID, - }; - break; - - case 'notices': - commandOptions = { - unacknowledged: args.unacknowledged, - }; - break; - - case 'init': - commandOptions = { - language: args.language, - list: args.list, - generateOnly: args.generateOnly, - TEMPLATE: args.TEMPLATE, - }; - break; - - case 'migrate': - commandOptions = { - stackName: args.stackName, - language: args.language, - account: args.account, - region: args.region, - fromPath: args.fromPath, - fromStack: args.fromStack, - outputPath: args.outputPath, - fromScan: args.fromScan, - filter: args.filter, - compress: args.compress, - }; - break; - - case 'context': - commandOptions = { - reset: args.reset, - force: args.force, - clear: args.clear, - }; - break; - - case 'docs': - commandOptions = { - browser: args.browser, - }; - break; - - case 'doctor': - commandOptions = {}; - break; - } - const cliArguments: CliArguments = { - _: args._[0], - globalOptions, - [args._[0]]: commandOptions, - }; - - return cliArguments; -} From 1c949ef923d4d15719b86d162f5ba8125c0da427 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 19:47:05 -0500 Subject: [PATCH 7/8] fix tests --- packages/aws-cdk/test/cli-arguments.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/aws-cdk/test/cli-arguments.test.ts b/packages/aws-cdk/test/cli-arguments.test.ts index ddcf9d02b6fb3..32ad80da77e84 100644 --- a/packages/aws-cdk/test/cli-arguments.test.ts +++ b/packages/aws-cdk/test/cli-arguments.test.ts @@ -1,11 +1,11 @@ -import { convertConfigToCliArgs, convertYargsToCliArgs } from '../lib/convert-to-cli-args'; +import { convertConfigToUserInput, convertYargsToUserInput } from '../lib/convert-to-user-input'; import { parseCommandLineArguments } from '../lib/parse-command-line-arguments'; describe('yargs', () => { test('yargs object can be converted to cli arguments', async () => { const input = await parseCommandLineArguments(['deploy', '-R', '-v', '--ci']); - const result = convertYargsToCliArgs(input); + const result = convertYargsToUserInput(input); expect(result).toEqual({ _: 'deploy', @@ -70,7 +70,7 @@ describe('yargs', () => { test('positional argument is correctly passed through -- variadic', async () => { const input = await parseCommandLineArguments(['deploy', 'stack1', 'stack2', '-R', '-v', '--ci']); - const result = convertYargsToCliArgs(input); + const result = convertYargsToUserInput(input); expect(result).toEqual({ _: 'deploy', @@ -84,7 +84,7 @@ describe('yargs', () => { test('positional argument is correctly passed through -- single', async () => { const input = await parseCommandLineArguments(['acknowledge', 'id1', '-v', '--ci']); - const result = convertYargsToCliArgs(input); + const result = convertYargsToUserInput(input); expect(result).toEqual({ _: 'acknowledge', @@ -109,7 +109,7 @@ describe('config', () => { }, }; - const result = convertConfigToCliArgs(input); + const result = convertConfigToUserInput(input); expect(result).toEqual({ globalOptions: expect.objectContaining({ From d9f1d350b3c5ddf1707ab18e11848976652be0f6 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy Date: Thu, 9 Jan 2025 20:21:38 -0500 Subject: [PATCH 8/8] jest config --- packages/aws-cdk/jest.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/jest.config.js b/packages/aws-cdk/jest.config.js index f82ca932d08a3..23f1a71b38590 100644 --- a/packages/aws-cdk/jest.config.js +++ b/packages/aws-cdk/jest.config.js @@ -19,8 +19,8 @@ const config = { "/lib/api/aws-auth/sdk.ts", // Files generated by cli-args-gen "/lib/parse-command-line-arguments.ts", - "/lib/cli-arguments.ts", - "/lib/convert-to-cli-args.ts", + "/lib/user-input.ts", + "/lib/convert-to-user-input.ts", ], // We have many tests here that commonly time out