diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index dca329bdd..349a79e8d 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -75,11 +75,11 @@ $ # List the available template types & languages $ cdk init --list Available templates: * app: Template for a CDK Application - └─ cdk init app --language=[csharp|fsharp|java|javascript|python|typescript] + └─ cdk init app --language=[csharp|cs|fsharp|fs|java|javascript|js|python|py|typescript|ts] * lib: Template for a CDK Construct Library └─ cdk init lib --language=typescript * sample-app: Example CDK Application with some constructs - └─ cdk init sample-app --language=[csharp|fsharp|java|javascript|python|typescript] + └─ cdk init sample-app --language=[csharp|cs|fsharp|fs|java|javascript|js|python|py|typescript|ts] $ # Create a new library application in typescript $ cdk init lib --language=typescript diff --git a/packages/aws-cdk/lib/cli/cli-config.ts b/packages/aws-cdk/lib/cli/cli-config.ts index 873749f25..edfc827b8 100644 --- a/packages/aws-cdk/lib/cli/cli-config.ts +++ b/packages/aws-cdk/lib/cli/cli-config.ts @@ -4,6 +4,7 @@ import { CliHelpers, type CliConfig } from '@aws-cdk/user-input-gen'; import * as cdk_from_cfn from 'cdk-from-cfn'; import { StackActivityProgress } from '../commands/deploy'; import { availableInitLanguages } from '../commands/init'; +import { getLanguageAlias } from '../commands/language'; export const YARGS_HELPERS = new CliHelpers('./util/yargs-helpers'); @@ -410,7 +411,13 @@ export async function makeConfig(): Promise { description: 'Migrate existing AWS resources into a CDK app', options: { 'stack-name': { type: 'string', alias: 'n', desc: 'The name assigned to the stack created in the new project. The name of the app will be based off this name as well.', requiresArg: true }, - 'language': { type: 'string', default: 'typescript', alias: 'l', desc: 'The language to be used for the new project', choices: cdk_from_cfn.supported_languages() }, + 'language': { + type: 'string', + default: 'typescript', + alias: 'l', + desc: 'The language to be used for the new project', + choices: [...new Set(cdk_from_cfn.supported_languages().flatMap((lang) => [lang, getLanguageAlias(lang)]))], + }, 'account': { type: 'string', desc: 'The account to retrieve the CloudFormation stack template from' }, 'region': { type: 'string', desc: 'The region to retrieve the CloudFormation stack template from' }, 'from-path': { type: 'string', desc: 'The path to the CloudFormation template to migrate. Use this for locally stored templates' }, diff --git a/packages/aws-cdk/lib/cli/cli-type-registry.json b/packages/aws-cdk/lib/cli/cli-type-registry.json index f78fd2fc3..533db4c54 100644 --- a/packages/aws-cdk/lib/cli/cli-type-registry.json +++ b/packages/aws-cdk/lib/cli/cli-type-registry.json @@ -845,12 +845,17 @@ "desc": "The language to be used for the new project (default can be configured in ~/.cdk.json)", "choices": [ "csharp", + "cs", "fsharp", + "fs", "go", "java", "javascript", + "js", "python", - "typescript" + "py", + "typescript", + "ts" ] }, "list": { @@ -901,10 +906,13 @@ "desc": "The language to be used for the new project", "choices": [ "typescript", + "ts", "go", "java", "python", - "csharp" + "py", + "csharp", + "cs" ] }, "account": { diff --git a/packages/aws-cdk/lib/cli/cli.ts b/packages/aws-cdk/lib/cli/cli.ts index e1ba9710a..566167f56 100644 --- a/packages/aws-cdk/lib/cli/cli.ts +++ b/packages/aws-cdk/lib/cli/cli.ts @@ -34,6 +34,7 @@ import { ProxyAgentProvider } from './proxy-agent'; import { cdkCliErrorName } from './telemetry/error'; import type { ErrorDetails } from './telemetry/schema'; import { isDeveloperBuildVersion, versionWithBuild, versionNumber } from './version'; +import { getLanguageFromAlias } from '../commands/language'; if (!process.stdout.isTTY) { // Disable chalk color highlighting @@ -42,6 +43,8 @@ if (!process.stdout.isTTY) { export async function exec(args: string[], synthesizer?: Synthesizer): Promise { const argv = await parseCommandLineArguments(args); + argv.language = getLanguageFromAlias(argv.language) ?? argv.language; + const cmd = argv._[0]; // if one -v, log at a DEBUG level diff --git a/packages/aws-cdk/lib/cli/parse-command-line-arguments.ts b/packages/aws-cdk/lib/cli/parse-command-line-arguments.ts index 1b29c21ee..a61d882ab 100644 --- a/packages/aws-cdk/lib/cli/parse-command-line-arguments.ts +++ b/packages/aws-cdk/lib/cli/parse-command-line-arguments.ts @@ -846,7 +846,7 @@ export function parseCommandLineArguments(args: Array): any { type: 'string', alias: 'l', desc: 'The language to be used for the new project (default can be configured in ~/.cdk.json)', - choices: ['csharp', 'fsharp', 'go', 'java', 'javascript', 'python', 'typescript'], + choices: ['csharp', 'cs', 'fsharp', 'fs', 'go', 'java', 'javascript', 'js', 'python', 'py', 'typescript', 'ts'], }) .option('list', { default: undefined, @@ -892,7 +892,7 @@ export function parseCommandLineArguments(args: Array): any { type: 'string', alias: 'l', desc: 'The language to be used for the new project', - choices: ['typescript', 'go', 'java', 'python', 'csharp'], + choices: ['typescript', 'ts', 'go', 'java', 'python', 'py', 'csharp', 'cs'], }) .option('account', { default: undefined, diff --git a/packages/aws-cdk/lib/commands/init/init.ts b/packages/aws-cdk/lib/commands/init/init.ts index 61666ddc0..4ceb6cb98 100644 --- a/packages/aws-cdk/lib/commands/init/init.ts +++ b/packages/aws-cdk/lib/commands/init/init.ts @@ -8,6 +8,7 @@ import type { IoHelper } from '../../api-private'; import { cliRootDir } from '../../cli/root-dir'; import { versionNumber } from '../../cli/version'; import { cdkHomeDir, formatErrorMessage, rangeFromSemver } from '../../util'; +import { getLanguageAlias } from '../language'; /* eslint-disable @typescript-eslint/no-var-requires */ // Packages don't have @types module // eslint-disable-next-line @typescript-eslint/no-require-imports @@ -569,7 +570,9 @@ export async function availableInitLanguages(): Promise { const result = new Set(); for (const template of templates) { for (const language of template.languages) { + const alias = getLanguageAlias(language); result.add(language); + alias && result.add(alias); } } return [...result]; diff --git a/packages/aws-cdk/lib/commands/language.ts b/packages/aws-cdk/lib/commands/language.ts new file mode 100644 index 000000000..c1833f7fc --- /dev/null +++ b/packages/aws-cdk/lib/commands/language.ts @@ -0,0 +1,31 @@ +export const SUPPORTED_LANGUAGES: { name: string; alias: string }[] = [ + { name: 'csharp', alias: 'cs' }, + { name: 'fsharp', alias: 'fs' }, + { name: 'go', alias: 'go' }, + { name: 'java', alias: 'java' }, + { name: 'javascript', alias: 'js' }, + { name: 'python', alias: 'py' }, + { name: 'typescript', alias: 'ts' }, +]; + +/** + * get the language alias from the language name or alias + * + * @example + * getLanguageAlias('typescript') // returns 'ts' + * getLanguageAlias('python') // returns 'py' + */ +export function getLanguageAlias(language: string): string | undefined { + return SUPPORTED_LANGUAGES.find((l) => l.name === language || l.alias === language)?.alias; +} + +/** + * get the language name from the language alias or name + * + * @example + * getLanguageFromAlias('ts') // returns 'typescript' + * getLanguageFromAlias('py') // returns 'python' + */ +export function getLanguageFromAlias(alias: string): string | undefined { + return SUPPORTED_LANGUAGES.find((l) => l.alias === alias || l.name === alias)?.name; +} diff --git a/packages/aws-cdk/test/cli/cli.test.ts b/packages/aws-cdk/test/cli/cli.test.ts index 53073a947..77f9f87d4 100644 --- a/packages/aws-cdk/test/cli/cli.test.ts +++ b/packages/aws-cdk/test/cli/cli.test.ts @@ -1,3 +1,4 @@ +import * as cdkToolkitModule from '../../lib/cli/cdk-toolkit'; import { exec } from '../../lib/cli/cli'; import { CliIoHost } from '../../lib/cli/io-host'; import { Configuration } from '../../lib/cli/user-configuration'; @@ -40,14 +41,26 @@ jest.mock('../../lib/api/notices', () => ({ })); jest.mock('../../lib/cli/parse-command-line-arguments', () => ({ - parseCommandLineArguments: jest.fn().mockImplementation((args) => Promise.resolve({ - _: ['version'], - verbose: args.includes('-v') ? ( - args.filter((arg: string) => arg === '-v').length - ) : args.includes('--verbose') ? ( - parseInt(args[args.indexOf('--verbose') + 1]) || true - ) : undefined, - })), + parseCommandLineArguments: jest.fn().mockImplementation((args) => { + if (args.includes('version')) { + return Promise.resolve({ + _: ['version'], + verbose: args.includes('-v') + ? args.filter((arg: string) => arg === '-v').length + : args.includes('--verbose') + ? parseInt(args[args.indexOf('--verbose') + 1]) || true + : undefined, + }); + } + if (args.includes('migrate')) { + return Promise.resolve({ + '_': ['migrate'], + 'language': 'typescript', + 'stack-name': 'sampleStack', + }); + } + return Promise.resolve({ _: [] }); + }), })); describe('exec verbose flag tests', () => { @@ -97,3 +110,15 @@ describe('exec verbose flag tests', () => { expect(CliIoHost.instance().logLevel).toBe('trace'); }); }); + +test('should convert language alias to full language name', async () => { + const migrateSpy = jest.spyOn(cdkToolkitModule.CdkToolkit.prototype, 'migrate').mockResolvedValue(); + + await exec(['migrate', '--language', 'ts', '--stack-name', 'sampleStack']); + + expect(migrateSpy).toHaveBeenCalledWith( + expect.objectContaining({ + language: 'typescript', + }), + ); +}); diff --git a/packages/aws-cdk/test/cli/language.test.ts b/packages/aws-cdk/test/cli/language.test.ts new file mode 100644 index 000000000..87e485db5 --- /dev/null +++ b/packages/aws-cdk/test/cli/language.test.ts @@ -0,0 +1,47 @@ +import { getLanguageAlias, getLanguageFromAlias } from '../../lib/commands/language'; + +describe('should get language alias from language name or alias', () => { + test.each([ + ['csharp', 'cs'], + ['cs', 'cs'], + ['fsharp', 'fs'], + ['fs', 'fs'], + ['go', 'go'], + ['java', 'java'], + ['javascript', 'js'], + ['js', 'js'], + ['python', 'py'], + ['py', 'py'], + ['typescript', 'ts'], + ['ts', 'ts'], + ])('getLanguageAlias(%s) should return %s', (input, expected) => { + expect(getLanguageAlias(input)).toBe(expected); + }); + + test('when unsupported language is specified, return undefined', () => { + expect(getLanguageAlias('ruby')).toBeUndefined(); + }); +}); + +describe('should get language name from language alias or name', () => { + test.each([ + ['csharp', 'csharp'], + ['cs', 'csharp'], + ['fsharp', 'fsharp'], + ['fs', 'fsharp'], + ['go', 'go'], + ['java', 'java'], + ['javascript', 'javascript'], + ['js', 'javascript'], + ['python', 'python'], + ['py', 'python'], + ['typescript', 'typescript'], + ['ts', 'typescript'], + ])('getLanguageFromAlias(%s) should return %s', (input, expected) => { + expect(getLanguageFromAlias(input)).toBe(expected); + }); + + test('when unsupported language alias is specified, return undefined', () => { + expect(getLanguageFromAlias('ruby')).toBeUndefined(); + }); +}); diff --git a/packages/aws-cdk/test/commands/init.test.ts b/packages/aws-cdk/test/commands/init.test.ts index 247cad552..1b321ba10 100644 --- a/packages/aws-cdk/test/commands/init.test.ts +++ b/packages/aws-cdk/test/commands/init.test.ts @@ -724,6 +724,7 @@ test('check available init languages', async () => { const langs = await availableInitLanguages(); expect(langs.length).toBeGreaterThan(0); expect(langs).toContain('typescript'); + expect(langs).toContain('ts'); }); test('exercise printing available templates', async () => {