Skip to content

Commit 7ad2e9c

Browse files
feat(cli): support shorthand aliases for languages (#814)
Fixes #748 ## Description Changes Extended the `--language` option values for the `cdk init` and `cdk migrate` commands to support shorthand aliases for language like `ts` and `js`. --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent 5fc1b13 commit 7ad2e9c

File tree

10 files changed

+140
-15
lines changed

10 files changed

+140
-15
lines changed

packages/aws-cdk/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@ $ # List the available template types & languages
7575
$ cdk init --list
7676
Available templates:
7777
* app: Template for a CDK Application
78-
└─ cdk init app --language=[csharp|fsharp|java|javascript|python|typescript]
78+
└─ cdk init app --language=[csharp|cs|fsharp|fs|java|javascript|js|python|py|typescript|ts]
7979
* lib: Template for a CDK Construct Library
8080
└─ cdk init lib --language=typescript
8181
* sample-app: Example CDK Application with some constructs
82-
└─ cdk init sample-app --language=[csharp|fsharp|java|javascript|python|typescript]
82+
└─ cdk init sample-app --language=[csharp|cs|fsharp|fs|java|javascript|js|python|py|typescript|ts]
8383

8484
$ # Create a new library application in typescript
8585
$ cdk init lib --language=typescript

packages/aws-cdk/lib/cli/cli-config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CliHelpers, type CliConfig } from '@aws-cdk/user-input-gen';
44
import * as cdk_from_cfn from 'cdk-from-cfn';
55
import { StackActivityProgress } from '../commands/deploy';
66
import { availableInitLanguages } from '../commands/init';
7+
import { getLanguageAlias } from '../commands/language';
78

89
export const YARGS_HELPERS = new CliHelpers('./util/yargs-helpers');
910

@@ -410,7 +411,13 @@ export async function makeConfig(): Promise<CliConfig> {
410411
description: 'Migrate existing AWS resources into a CDK app',
411412
options: {
412413
'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 },
413-
'language': { type: 'string', default: 'typescript', alias: 'l', desc: 'The language to be used for the new project', choices: cdk_from_cfn.supported_languages() },
414+
'language': {
415+
type: 'string',
416+
default: 'typescript',
417+
alias: 'l',
418+
desc: 'The language to be used for the new project',
419+
choices: [...new Set(cdk_from_cfn.supported_languages().flatMap((lang) => [lang, getLanguageAlias(lang)]))],
420+
},
414421
'account': { type: 'string', desc: 'The account to retrieve the CloudFormation stack template from' },
415422
'region': { type: 'string', desc: 'The region to retrieve the CloudFormation stack template from' },
416423
'from-path': { type: 'string', desc: 'The path to the CloudFormation template to migrate. Use this for locally stored templates' },

packages/aws-cdk/lib/cli/cli-type-registry.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -845,12 +845,17 @@
845845
"desc": "The language to be used for the new project (default can be configured in ~/.cdk.json)",
846846
"choices": [
847847
"csharp",
848+
"cs",
848849
"fsharp",
850+
"fs",
849851
"go",
850852
"java",
851853
"javascript",
854+
"js",
852855
"python",
853-
"typescript"
856+
"py",
857+
"typescript",
858+
"ts"
854859
]
855860
},
856861
"list": {
@@ -901,10 +906,13 @@
901906
"desc": "The language to be used for the new project",
902907
"choices": [
903908
"typescript",
909+
"ts",
904910
"go",
905911
"java",
906912
"python",
907-
"csharp"
913+
"py",
914+
"csharp",
915+
"cs"
908916
]
909917
},
910918
"account": {

packages/aws-cdk/lib/cli/cli.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { ProxyAgentProvider } from './proxy-agent';
3434
import { cdkCliErrorName } from './telemetry/error';
3535
import type { ErrorDetails } from './telemetry/schema';
3636
import { isDeveloperBuildVersion, versionWithBuild, versionNumber } from './version';
37+
import { getLanguageFromAlias } from '../commands/language';
3738

3839
if (!process.stdout.isTTY) {
3940
// Disable chalk color highlighting
@@ -42,6 +43,8 @@ if (!process.stdout.isTTY) {
4243

4344
export async function exec(args: string[], synthesizer?: Synthesizer): Promise<number | void> {
4445
const argv = await parseCommandLineArguments(args);
46+
argv.language = getLanguageFromAlias(argv.language) ?? argv.language;
47+
4548
const cmd = argv._[0];
4649

4750
// if one -v, log at a DEBUG level

packages/aws-cdk/lib/cli/parse-command-line-arguments.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ export function parseCommandLineArguments(args: Array<string>): any {
846846
type: 'string',
847847
alias: 'l',
848848
desc: 'The language to be used for the new project (default can be configured in ~/.cdk.json)',
849-
choices: ['csharp', 'fsharp', 'go', 'java', 'javascript', 'python', 'typescript'],
849+
choices: ['csharp', 'cs', 'fsharp', 'fs', 'go', 'java', 'javascript', 'js', 'python', 'py', 'typescript', 'ts'],
850850
})
851851
.option('list', {
852852
default: undefined,
@@ -892,7 +892,7 @@ export function parseCommandLineArguments(args: Array<string>): any {
892892
type: 'string',
893893
alias: 'l',
894894
desc: 'The language to be used for the new project',
895-
choices: ['typescript', 'go', 'java', 'python', 'csharp'],
895+
choices: ['typescript', 'ts', 'go', 'java', 'python', 'py', 'csharp', 'cs'],
896896
})
897897
.option('account', {
898898
default: undefined,

packages/aws-cdk/lib/commands/init/init.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { IoHelper } from '../../api-private';
88
import { cliRootDir } from '../../cli/root-dir';
99
import { versionNumber } from '../../cli/version';
1010
import { cdkHomeDir, formatErrorMessage, rangeFromSemver } from '../../util';
11+
import { getLanguageAlias } from '../language';
1112

1213
/* eslint-disable @typescript-eslint/no-var-requires */ // Packages don't have @types module
1314
// eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -569,7 +570,9 @@ export async function availableInitLanguages(): Promise<string[]> {
569570
const result = new Set<string>();
570571
for (const template of templates) {
571572
for (const language of template.languages) {
573+
const alias = getLanguageAlias(language);
572574
result.add(language);
575+
alias && result.add(alias);
573576
}
574577
}
575578
return [...result];
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
export const SUPPORTED_LANGUAGES: { name: string; alias: string }[] = [
2+
{ name: 'csharp', alias: 'cs' },
3+
{ name: 'fsharp', alias: 'fs' },
4+
{ name: 'go', alias: 'go' },
5+
{ name: 'java', alias: 'java' },
6+
{ name: 'javascript', alias: 'js' },
7+
{ name: 'python', alias: 'py' },
8+
{ name: 'typescript', alias: 'ts' },
9+
];
10+
11+
/**
12+
* get the language alias from the language name or alias
13+
*
14+
* @example
15+
* getLanguageAlias('typescript') // returns 'ts'
16+
* getLanguageAlias('python') // returns 'py'
17+
*/
18+
export function getLanguageAlias(language: string): string | undefined {
19+
return SUPPORTED_LANGUAGES.find((l) => l.name === language || l.alias === language)?.alias;
20+
}
21+
22+
/**
23+
* get the language name from the language alias or name
24+
*
25+
* @example
26+
* getLanguageFromAlias('ts') // returns 'typescript'
27+
* getLanguageFromAlias('py') // returns 'python'
28+
*/
29+
export function getLanguageFromAlias(alias: string): string | undefined {
30+
return SUPPORTED_LANGUAGES.find((l) => l.alias === alias || l.name === alias)?.name;
31+
}

packages/aws-cdk/test/cli/cli.test.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as cdkToolkitModule from '../../lib/cli/cdk-toolkit';
12
import { exec } from '../../lib/cli/cli';
23
import { CliIoHost } from '../../lib/cli/io-host';
34
import { Configuration } from '../../lib/cli/user-configuration';
@@ -40,14 +41,26 @@ jest.mock('../../lib/api/notices', () => ({
4041
}));
4142

4243
jest.mock('../../lib/cli/parse-command-line-arguments', () => ({
43-
parseCommandLineArguments: jest.fn().mockImplementation((args) => Promise.resolve({
44-
_: ['version'],
45-
verbose: args.includes('-v') ? (
46-
args.filter((arg: string) => arg === '-v').length
47-
) : args.includes('--verbose') ? (
48-
parseInt(args[args.indexOf('--verbose') + 1]) || true
49-
) : undefined,
50-
})),
44+
parseCommandLineArguments: jest.fn().mockImplementation((args) => {
45+
if (args.includes('version')) {
46+
return Promise.resolve({
47+
_: ['version'],
48+
verbose: args.includes('-v')
49+
? args.filter((arg: string) => arg === '-v').length
50+
: args.includes('--verbose')
51+
? parseInt(args[args.indexOf('--verbose') + 1]) || true
52+
: undefined,
53+
});
54+
}
55+
if (args.includes('migrate')) {
56+
return Promise.resolve({
57+
'_': ['migrate'],
58+
'language': 'typescript',
59+
'stack-name': 'sampleStack',
60+
});
61+
}
62+
return Promise.resolve({ _: [] });
63+
}),
5164
}));
5265

5366
describe('exec verbose flag tests', () => {
@@ -97,3 +110,15 @@ describe('exec verbose flag tests', () => {
97110
expect(CliIoHost.instance().logLevel).toBe('trace');
98111
});
99112
});
113+
114+
test('should convert language alias to full language name', async () => {
115+
const migrateSpy = jest.spyOn(cdkToolkitModule.CdkToolkit.prototype, 'migrate').mockResolvedValue();
116+
117+
await exec(['migrate', '--language', 'ts', '--stack-name', 'sampleStack']);
118+
119+
expect(migrateSpy).toHaveBeenCalledWith(
120+
expect.objectContaining({
121+
language: 'typescript',
122+
}),
123+
);
124+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { getLanguageAlias, getLanguageFromAlias } from '../../lib/commands/language';
2+
3+
describe('should get language alias from language name or alias', () => {
4+
test.each([
5+
['csharp', 'cs'],
6+
['cs', 'cs'],
7+
['fsharp', 'fs'],
8+
['fs', 'fs'],
9+
['go', 'go'],
10+
['java', 'java'],
11+
['javascript', 'js'],
12+
['js', 'js'],
13+
['python', 'py'],
14+
['py', 'py'],
15+
['typescript', 'ts'],
16+
['ts', 'ts'],
17+
])('getLanguageAlias(%s) should return %s', (input, expected) => {
18+
expect(getLanguageAlias(input)).toBe(expected);
19+
});
20+
21+
test('when unsupported language is specified, return undefined', () => {
22+
expect(getLanguageAlias('ruby')).toBeUndefined();
23+
});
24+
});
25+
26+
describe('should get language name from language alias or name', () => {
27+
test.each([
28+
['csharp', 'csharp'],
29+
['cs', 'csharp'],
30+
['fsharp', 'fsharp'],
31+
['fs', 'fsharp'],
32+
['go', 'go'],
33+
['java', 'java'],
34+
['javascript', 'javascript'],
35+
['js', 'javascript'],
36+
['python', 'python'],
37+
['py', 'python'],
38+
['typescript', 'typescript'],
39+
['ts', 'typescript'],
40+
])('getLanguageFromAlias(%s) should return %s', (input, expected) => {
41+
expect(getLanguageFromAlias(input)).toBe(expected);
42+
});
43+
44+
test('when unsupported language alias is specified, return undefined', () => {
45+
expect(getLanguageFromAlias('ruby')).toBeUndefined();
46+
});
47+
});

packages/aws-cdk/test/commands/init.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ test('check available init languages', async () => {
724724
const langs = await availableInitLanguages();
725725
expect(langs.length).toBeGreaterThan(0);
726726
expect(langs).toContain('typescript');
727+
expect(langs).toContain('ts');
727728
});
728729

729730
test('exercise printing available templates', async () => {

0 commit comments

Comments
 (0)