terrafaker 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +171 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +5 -0
  6. package/dist/commands/generate/file.d.ts +13 -0
  7. package/dist/commands/generate/file.js +32 -0
  8. package/dist/commands/generate/index.d.ts +7 -0
  9. package/dist/commands/generate/index.js +9 -0
  10. package/dist/commands/generate/repo.d.ts +18 -0
  11. package/dist/commands/generate/repo.js +60 -0
  12. package/dist/commands/gh/clone-repos.d.ts +10 -0
  13. package/dist/commands/gh/clone-repos.js +46 -0
  14. package/dist/commands/gh/delete-repos.d.ts +9 -0
  15. package/dist/commands/gh/delete-repos.js +41 -0
  16. package/dist/commands/gh/index.d.ts +7 -0
  17. package/dist/commands/gh/index.js +10 -0
  18. package/dist/commands/util/format-psv.d.ts +10 -0
  19. package/dist/commands/util/format-psv.js +46 -0
  20. package/dist/commands/util/format-tsv.d.ts +13 -0
  21. package/dist/commands/util/format-tsv.js +33 -0
  22. package/dist/commands/util/index.d.ts +7 -0
  23. package/dist/commands/util/index.js +9 -0
  24. package/dist/constants/aws.d.ts +192 -0
  25. package/dist/constants/aws.js +201 -0
  26. package/dist/constants/gcp.d.ts +88 -0
  27. package/dist/constants/gcp.js +109 -0
  28. package/dist/constants/tags.d.ts +5 -0
  29. package/dist/constants/tags.js +17 -0
  30. package/dist/enums/help-messages.d.ts +4 -0
  31. package/dist/enums/help-messages.js +4 -0
  32. package/dist/enums/providers.d.ts +8 -0
  33. package/dist/enums/providers.js +5 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +1 -0
  36. package/dist/types/object-values.d.ts +2 -0
  37. package/dist/types/object-values.js +1 -0
  38. package/dist/utilities/base-command.d.ts +5 -0
  39. package/dist/utilities/base-command.js +9 -0
  40. package/dist/utilities/flags.d.ts +5 -0
  41. package/dist/utilities/flags.js +21 -0
  42. package/dist/utilities/generators/aws-generators.d.ts +4 -0
  43. package/dist/utilities/generators/aws-generators.js +80 -0
  44. package/dist/utilities/generators/gcp-generators.d.ts +4 -0
  45. package/dist/utilities/generators/gcp-generators.js +69 -0
  46. package/dist/utilities/generators/generator-utils.d.ts +80 -0
  47. package/dist/utilities/generators/generator-utils.js +72 -0
  48. package/dist/utilities/github.d.ts +8 -0
  49. package/dist/utilities/github.js +4 -0
  50. package/dist/utilities/string-utils.d.ts +5 -0
  51. package/dist/utilities/string-utils.js +7 -0
  52. package/oclif.manifest.json +358 -0
  53. package/package.json +82 -0
package/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # terrafaker
2
+
3
+ CLI for easily generating fake terraform files and repos
4
+
5
+ [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
6
+ [![Version](https://img.shields.io/npm/v/terrafaker.svg)](https://npmjs.org/package/terrafaker)
7
+ [![Downloads/week](https://img.shields.io/npm/dw/terrafaker.svg)](https://npmjs.org/package/terrafaker)
8
+
9
+ ## Why this exists
10
+
11
+ This tool mostly exists to quickly seed data for testing out platforms that rely on infrastructure-as-code, like [Infracost](https://www.infracost.io/). If you find it useful, or there's a feature you'd like to see, feel free to open up an [issue](https://github.com/brandongregoryscott/terrafaker/issues).
12
+
13
+ ## Features
14
+
15
+ - Generate individual files
16
+ - Generate git repos with multiple files (and optionally push them to GitHub)
17
+ - Bulk clone and delete generated repos by prefix
18
+
19
+ ### Supported providers and resources
20
+
21
+ - AWS
22
+ - EC2 instances
23
+ - Lambda functions
24
+ - GCP
25
+ - Compute instances
26
+ - Functions
27
+ - TODO: Azure
28
+
29
+ <!-- prettier-ignore-start -->
30
+ <!-- toc -->
31
+ * [terrafaker](#terrafaker)
32
+ * [Usage](#usage)
33
+ * [Commands](#commands)
34
+ <!-- tocstop -->
35
+
36
+ # Usage
37
+
38
+ <!-- usage -->
39
+ ```sh-session
40
+ $ npm install -g terrafaker
41
+ $ terrafaker COMMAND
42
+ running command...
43
+ $ terrafaker (--version)
44
+ terrafaker/0.0.0 darwin-arm64 node-v24.8.0
45
+ $ terrafaker --help [COMMAND]
46
+ USAGE
47
+ $ terrafaker COMMAND
48
+ ...
49
+ ```
50
+ <!-- usagestop -->
51
+
52
+ # Commands
53
+
54
+ <!-- commands -->
55
+ * [`terrafaker generate file`](#terrafaker-generate-file)
56
+ * [`terrafaker generate repo`](#terrafaker-generate-repo)
57
+ * [`terrafaker gh clone-repos`](#terrafaker-gh-clone-repos)
58
+ * [`terrafaker gh delete-repos`](#terrafaker-gh-delete-repos)
59
+ * [`terrafaker help [COMMAND]`](#terrafaker-help-command)
60
+
61
+ ## `terrafaker generate file`
62
+
63
+ Generates a terraform file.
64
+
65
+ ```
66
+ USAGE
67
+ $ terrafaker generate file [--name <value>] [--provider aws|gcp] [--resource-count <value>] [-f] [-q]
68
+
69
+ FLAGS
70
+ -f, --[no-]format Format the output terraform files. Requires `terraform` to be in your $PATH.
71
+ -q, --quiet Suppress the logging output.
72
+ --name=<value> Name for the generated file, which must end in .tf
73
+ --provider=<option> Cloud provider to generate resources for
74
+ <options: aws|gcp>
75
+ --resource-count=<value> [default: 3] Number of resources per file to generate
76
+
77
+ DESCRIPTION
78
+ Generates a terraform file.
79
+ ```
80
+
81
+ _See code: [src/commands/generate/file.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/generate/file.ts)_
82
+
83
+ ## `terrafaker generate repo`
84
+
85
+ Generates repo(s) with multiple terraform files.
86
+
87
+ ```
88
+ USAGE
89
+ $ terrafaker generate repo [--directory <value>] [--count <value>] [--file-count <value>] [--resource-count
90
+ <value>] [--prefix <value>] [--provider aws|gcp] [-f] [--create-remote] [--public] [-q]
91
+
92
+ FLAGS
93
+ -f, --[no-]format Format the output terraform files. Requires `terraform` to be in your $PATH.
94
+ -q, --quiet Suppress the logging output.
95
+ --count=<value> [default: 1] Number of repos to generate
96
+ --create-remote Create and push a remote GitHub repo. Requires the `gh` CLI to be installed. To install,
97
+ run `brew install gh`.
98
+ --directory=<value> [default: .] Directory to generate the repo(s) in
99
+ --file-count=<value> [default: 3] Number of files per repo to generate
100
+ --prefix=<value> [default: tf_] Prefix for repo names, useful for quickly identifying generated content
101
+ --provider=<option> Cloud provider to generate resources for
102
+ <options: aws|gcp>
103
+ --public Whether the remote repo(s) created are public.
104
+ --resource-count=<value> [default: 3] Number of resources per file to generate
105
+
106
+ DESCRIPTION
107
+ Generates repo(s) with multiple terraform files.
108
+ ```
109
+
110
+ _See code: [src/commands/generate/repo.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/generate/repo.ts)_
111
+
112
+ ## `terrafaker gh clone-repos`
113
+
114
+ Clones repos from your Github account, useful for pulling down generated repos for manual modifications. Requires the `gh` CLI to be installed. To install, run `brew install gh`.
115
+
116
+ ```
117
+ USAGE
118
+ $ terrafaker gh clone-repos --prefix <value> [--directory <value>]
119
+
120
+ FLAGS
121
+ --directory=<value> [default: .] Directory to clone the repo(s) in
122
+ --prefix=<value> (required) Prefix for the repos to clone, such as 'tf_'
123
+
124
+ DESCRIPTION
125
+ Clones repos from your Github account, useful for pulling down generated repos for manual modifications. Requires the
126
+ `gh` CLI to be installed. To install, run `brew install gh`.
127
+ ```
128
+
129
+ _See code: [src/commands/gh/clone-repos.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/gh/clone-repos.ts)_
130
+
131
+ ## `terrafaker gh delete-repos`
132
+
133
+ Deletes repos from your Github account, useful for cleaning up generated test data. Requires the `gh` CLI to be installed. To install, run `brew install gh`.
134
+
135
+ ```
136
+ USAGE
137
+ $ terrafaker gh delete-repos --prefix <value>
138
+
139
+ FLAGS
140
+ --prefix=<value> (required) Prefix for the repos to delete, such as 'tf_'
141
+
142
+ DESCRIPTION
143
+ Deletes repos from your Github account, useful for cleaning up generated test data. Requires the `gh` CLI to be
144
+ installed. To install, run `brew install gh`.
145
+
146
+ If the deletion fails, you may need to refresh your CLI permissions with `gh auth refresh -s delete_repo`
147
+ ```
148
+
149
+ _See code: [src/commands/gh/delete-repos.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/gh/delete-repos.ts)_
150
+
151
+ ## `terrafaker help [COMMAND]`
152
+
153
+ Display help for terrafaker.
154
+
155
+ ```
156
+ USAGE
157
+ $ terrafaker help [COMMAND...] [-n]
158
+
159
+ ARGUMENTS
160
+ [COMMAND...] Command to show help for.
161
+
162
+ FLAGS
163
+ -n, --nested-commands Include all nested commands in the output.
164
+
165
+ DESCRIPTION
166
+ Display help for terrafaker.
167
+ ```
168
+
169
+ _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.36/src/commands/help.ts)_
170
+ <!-- commandsstop -->
171
+ <!-- prettier-ignore-end -->
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %*
package/bin/dev.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning
2
+
3
+ import { execute } from "@oclif/core";
4
+
5
+ await execute({ development: true, dir: import.meta.url });
package/bin/run.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\run" %*
package/bin/run.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execute } from "@oclif/core";
4
+
5
+ await execute({ dir: import.meta.url });
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class File extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ provider: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ "resource-count": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
8
+ format: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
13
+ export { File };
@@ -0,0 +1,32 @@
1
+ import { Flags } from "@oclif/core";
2
+ import { BaseCommand } from "../../utilities/base-command.js";
3
+ import { formatFlag, providerFlag, quietFlag, resourceCountFlag, } from "../../utilities/flags.js";
4
+ import { success } from "../../utilities/string-utils.js";
5
+ import { generateFileByProvider, randomProvider, } from "../../utilities/generators/generator-utils.js";
6
+ class File extends BaseCommand {
7
+ static description = "Generates a terraform file.";
8
+ static flags = {
9
+ name: Flags.string({
10
+ description: "Name for the generated file, which must end in .tf",
11
+ }),
12
+ provider: providerFlag,
13
+ "resource-count": resourceCountFlag,
14
+ format: formatFlag,
15
+ quiet: quietFlag,
16
+ };
17
+ async run() {
18
+ const { flags } = await this.parse(File);
19
+ const { name, quiet, format, "resource-count": resourceCount } = flags;
20
+ const provider = flags.provider ?? randomProvider();
21
+ let tfFilename = name ?? "main.tf";
22
+ if (!tfFilename.endsWith(".tf")) {
23
+ tfFilename = `${tfFilename}.tf`;
24
+ }
25
+ const tfg = generateFileByProvider({ provider, resourceCount });
26
+ tfg.write({ format, tfFilename });
27
+ if (!quiet) {
28
+ this.log(success(`Successfully generated ${tfFilename}`));
29
+ }
30
+ }
31
+ }
32
+ export { File };
@@ -0,0 +1,7 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class Generate extends BaseCommand {
3
+ static hidden: boolean;
4
+ static description: string;
5
+ run(): Promise<void>;
6
+ }
7
+ export { Generate };
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ class Generate extends BaseCommand {
3
+ static hidden = true;
4
+ static description = "Commands for generating terraform files.";
5
+ async run() {
6
+ await this.showHelp();
7
+ }
8
+ }
9
+ export { Generate };
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class Repo extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
6
+ count: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
7
+ "file-count": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
8
+ "resource-count": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
9
+ prefix: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ provider: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ format: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ "create-remote": import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ public: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ };
16
+ run(): Promise<void>;
17
+ }
18
+ export { Repo };
@@ -0,0 +1,60 @@
1
+ import { Flags } from "@oclif/core";
2
+ import path from "node:path";
3
+ import { generateRepo, randomProvider, } from "../../utilities/generators/generator-utils.js";
4
+ import { BaseCommand } from "../../utilities/base-command.js";
5
+ import { formatFlag, providerFlag, quietFlag, resourceCountFlag, } from "../../utilities/flags.js";
6
+ import { $ } from "zx";
7
+ import { HelpMessages } from "../../enums/help-messages.js";
8
+ class Repo extends BaseCommand {
9
+ static description = "Generates repo(s) with multiple terraform files.";
10
+ static flags = {
11
+ directory: Flags.string({
12
+ description: "Directory to generate the repo(s) in",
13
+ default: ".",
14
+ }),
15
+ count: Flags.integer({
16
+ description: "Number of repos to generate",
17
+ default: 1,
18
+ }),
19
+ "file-count": Flags.integer({
20
+ description: "Number of files per repo to generate",
21
+ default: 3,
22
+ }),
23
+ "resource-count": resourceCountFlag,
24
+ prefix: Flags.string({
25
+ description: "Prefix for repo names, useful for quickly identifying generated content",
26
+ default: "tf_",
27
+ }),
28
+ provider: providerFlag,
29
+ format: formatFlag,
30
+ "create-remote": Flags.boolean({
31
+ description: `Create and push a remote GitHub repo. ${HelpMessages.RequiresGhCli}`,
32
+ }),
33
+ public: Flags.boolean({
34
+ description: "Whether the remote repo(s) created are public.",
35
+ default: false,
36
+ }),
37
+ quiet: quietFlag,
38
+ };
39
+ async run() {
40
+ const { flags } = await this.parse(Repo);
41
+ const { format, prefix, count, public: isPublic, quiet, "resource-count": resourceCount, "file-count": fileCount, "create-remote": createRemote, } = flags;
42
+ const provider = flags.provider;
43
+ const directory = path.resolve(process.cwd(), flags.directory);
44
+ for (let i = 0; i < count; i++) {
45
+ const { name, path } = await generateRepo({
46
+ directory,
47
+ fileCount,
48
+ format,
49
+ prefix,
50
+ provider: provider ?? randomProvider(),
51
+ resourceCount,
52
+ quiet,
53
+ });
54
+ if (createRemote) {
55
+ await $ `gh repo create ${name} --source ${path} ${isPublic ? "--public" : "--private"} --push`;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ export { Repo };
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class CloneRepos extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
6
+ prefix: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
10
+ export { CloneRepos };
@@ -0,0 +1,46 @@
1
+ import { Flags } from "@oclif/core";
2
+ import { execSync } from "node:child_process";
3
+ import { confirm } from "@inquirer/prompts";
4
+ import { isEmpty } from "lodash-es";
5
+ import path from "node:path";
6
+ import { listRepos, stringifyRepos } from "../../utilities/github.js";
7
+ import { BaseCommand } from "../../utilities/base-command.js";
8
+ import { HelpMessages } from "../../enums/help-messages.js";
9
+ class CloneRepos extends BaseCommand {
10
+ static description = `Clones repos from your Github account, useful for pulling down generated repos for manual modifications. ${HelpMessages.RequiresGhCli}`;
11
+ static flags = {
12
+ directory: Flags.string({
13
+ description: "Directory to clone the repo(s) in",
14
+ default: ".",
15
+ }),
16
+ prefix: Flags.string({
17
+ description: "Prefix for the repos to clone, such as 'tf_'",
18
+ required: true,
19
+ }),
20
+ };
21
+ async run() {
22
+ const { flags } = await this.parse(CloneRepos);
23
+ const { prefix } = flags;
24
+ const allRepos = listRepos();
25
+ const repos = allRepos.filter((repo) => repo.name.startsWith(prefix));
26
+ if (isEmpty(repos)) {
27
+ this.log(`Repos found:\n${stringifyRepos(allRepos)}`);
28
+ this.log(`No repos found with prefix '${prefix}'`);
29
+ this.exit();
30
+ }
31
+ this.log(`Repos to clone:\n${stringifyRepos(repos)}`);
32
+ const confirmation = await confirm({
33
+ message: "Continue with cloning these repos?",
34
+ });
35
+ if (!confirmation) {
36
+ return;
37
+ }
38
+ repos.forEach((repo) => {
39
+ const directory = path.resolve(process.cwd(), flags.directory, repo.name);
40
+ execSync(`gh repo clone ${repo.nameWithOwner} ${directory}`, {
41
+ stdio: "inherit",
42
+ });
43
+ });
44
+ }
45
+ }
46
+ export { CloneRepos };
@@ -0,0 +1,9 @@
1
+ import { Command } from "@oclif/core";
2
+ declare class DeleteRepos extends Command {
3
+ static description: string;
4
+ static flags: {
5
+ prefix: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
6
+ };
7
+ run(): Promise<void>;
8
+ }
9
+ export { DeleteRepos };
@@ -0,0 +1,41 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import { execSync } from "node:child_process";
3
+ import { confirm } from "@inquirer/prompts";
4
+ import { isEmpty } from "lodash-es";
5
+ import { listRepos, stringifyRepos } from "../../utilities/github.js";
6
+ import { HelpMessages } from "../../enums/help-messages.js";
7
+ class DeleteRepos extends Command {
8
+ static description = `Deletes repos from your Github account, useful for cleaning up generated test data. ${HelpMessages.RequiresGhCli}
9
+
10
+ If the deletion fails, you may need to refresh your CLI permissions with \`gh auth refresh -s delete_repo\``;
11
+ static flags = {
12
+ prefix: Flags.string({
13
+ description: "Prefix for the repos to delete, such as 'tf_'",
14
+ required: true,
15
+ }),
16
+ };
17
+ async run() {
18
+ const { flags } = await this.parse(DeleteRepos);
19
+ const { prefix } = flags;
20
+ const allRepos = listRepos();
21
+ const repos = allRepos.filter((repo) => repo.name.startsWith(prefix));
22
+ if (isEmpty(repos)) {
23
+ this.log(`Repos found:\n${stringifyRepos(allRepos)}`);
24
+ this.log(`No repos found with prefix '${prefix}'`);
25
+ this.exit();
26
+ }
27
+ this.log(`Repos to delete:\n${stringifyRepos(repos)}`);
28
+ const confirmation = await confirm({
29
+ message: "Continue with deletion of these repos?",
30
+ });
31
+ if (!confirmation) {
32
+ return;
33
+ }
34
+ repos.forEach((repo) => {
35
+ execSync(`gh repo delete ${repo.nameWithOwner} --yes`, {
36
+ stdio: "inherit",
37
+ });
38
+ });
39
+ }
40
+ }
41
+ export { DeleteRepos };
@@ -0,0 +1,7 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class Gh extends BaseCommand {
3
+ static hidden: boolean;
4
+ static description: string;
5
+ run(): Promise<void>;
6
+ }
7
+ export { Gh };
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ import { HelpMessages } from "../../enums/help-messages.js";
3
+ class Gh extends BaseCommand {
4
+ static hidden = true;
5
+ static description = `Utility commands that wrap the \`gh\` CLI. ${HelpMessages.RequiresGhCli}`;
6
+ async run() {
7
+ await this.showHelp();
8
+ }
9
+ }
10
+ export { Gh };
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class FormatPsv extends BaseCommand {
3
+ static hidden: boolean;
4
+ static description: string;
5
+ static args: {
6
+ psv: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
10
+ export { FormatPsv };
@@ -0,0 +1,46 @@
1
+ import { Args } from "@oclif/core";
2
+ import { compact, first } from "lodash-es";
3
+ import { BaseCommand } from "../../utilities/base-command.js";
4
+ import { stringifySingleLineArray } from "../../utilities/string-utils.js";
5
+ const EXAMPLE_INSTANCE_TYPES = ["m5.large", "m5.xlarge", "m5.2xlarge"];
6
+ class FormatPsv extends BaseCommand {
7
+ static hidden = true;
8
+ static description = "Utility command for formatting a PSV (pipe-separated value) into an array or object with array values. Primarily used for parsing data from the AWS docs.";
9
+ static args = {
10
+ psv: Args.string({
11
+ required: true,
12
+ description: `Pipe-separated value to format into a string array, i.e. '${EXAMPLE_INSTANCE_TYPES.join(" | ")}'.
13
+ If the string is multiple lines, it will be formatted into an object where the key is the first column before a tab, i.e. 'M5\t${EXAMPLE_INSTANCE_TYPES.join(" | ")}'`,
14
+ }),
15
+ };
16
+ async run() {
17
+ const { args } = await this.parse(FormatPsv);
18
+ const { psv } = args;
19
+ const lines = psv.split("\n");
20
+ if (lines.length === 1) {
21
+ const values = splitPsv(first(lines) ?? "");
22
+ this.log(stringifySingleLineArray(values));
23
+ return;
24
+ }
25
+ const value = lines.reduce((accumulated, line) => {
26
+ const [type, psv] = line.split("\t");
27
+ accumulated[type] = splitPsv(psv);
28
+ return accumulated;
29
+ }, {});
30
+ this.log(stringifyObjectWithSingleLineArrays(value));
31
+ }
32
+ }
33
+ const splitPsv = (psv) => compact(psv.split("|").map((value) => value.trim()));
34
+ /**
35
+ * In an effort to reduce the size of the AWS constants file, we're custom stringifying the object
36
+ * to ensure the arrays are a single line.
37
+ */
38
+ const stringifyObjectWithSingleLineArrays = (object) => {
39
+ const lines = ["{"];
40
+ Object.entries(object).forEach(([key, values]) => {
41
+ lines.push(`\t"${key}": ${stringifySingleLineArray(values)},`);
42
+ });
43
+ lines.push("}");
44
+ return lines.join("\n");
45
+ };
46
+ export { FormatPsv };
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class FormatTsv extends BaseCommand {
3
+ static hidden: boolean;
4
+ static description: string;
5
+ static flags: {
6
+ index: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
7
+ };
8
+ static args: {
9
+ tsv: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
13
+ export { FormatTsv };
@@ -0,0 +1,33 @@
1
+ import { Args, Flags } from "@oclif/core";
2
+ import { BaseCommand } from "../../utilities/base-command.js";
3
+ import { stringifySingleLineArray } from "../../utilities/string-utils.js";
4
+ import { compact } from "lodash-es";
5
+ const EXAMPLE = `c4d-standard-2 2 7 No Up to 10 N/A`;
6
+ class FormatTsv extends BaseCommand {
7
+ static hidden = true;
8
+ static description = "Utility command for formatting a TSV (tab-separated value) into an array. Primarily used for parsing data from the GCP docs.";
9
+ static flags = {
10
+ index: Flags.integer({
11
+ char: "i",
12
+ description: "Column index to pull from each line.",
13
+ default: 0,
14
+ }),
15
+ };
16
+ static args = {
17
+ tsv: Args.string({
18
+ required: true,
19
+ description: `Tab-separated value to format into a string array, i.e. '${EXAMPLE}'.
20
+ If the string is multiple lines (which it generally is), the specified column index from each line will be placed in the array.`,
21
+ }),
22
+ };
23
+ async run() {
24
+ const { args, flags } = await this.parse(FormatTsv);
25
+ const { index } = flags;
26
+ const { tsv } = args;
27
+ const lines = tsv.split("\n");
28
+ const values = compact(lines.map((line) => splitTsv(line)[index]));
29
+ this.log(stringifySingleLineArray(values));
30
+ }
31
+ }
32
+ const splitTsv = (tsv) => compact(tsv.split("\t").map((value) => value.trim()));
33
+ export { FormatTsv };
@@ -0,0 +1,7 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ declare class Util extends BaseCommand {
3
+ static hidden: boolean;
4
+ static description: string;
5
+ run(): Promise<void>;
6
+ }
7
+ export { Util };
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from "../../utilities/base-command.js";
2
+ class Util extends BaseCommand {
3
+ static hidden = true;
4
+ static description = "Miscellaneous utility commands.";
5
+ async run() {
6
+ await this.showHelp();
7
+ }
8
+ }
9
+ export { Util };