Skip to content

Commit e7ca020

Browse files
committed
Use subcommands for CLI
1 parent d6590c3 commit e7ca020

5 files changed

Lines changed: 122 additions & 134 deletions

File tree

packages/septic/package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
"description": "",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
7-
"bin": {
8-
"septic-lint": "./dist/cli/lint.js",
9-
"septic-format": "./dist/cli/format.js"
10-
},
7+
"bin": "./dist/cli/index.js",
118
"scripts": {
129
"test": "cross-env NODE_ENV=test mocha",
1310
"build": "tsc -b && copyfiles public/**/* dist",

packages/septic/src/cli/format.ts

Lines changed: 49 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,22 @@
1-
#!/usr/bin/env node
2-
import yargs from "yargs";
3-
import { hideBin } from "yargs/helpers";
4-
import {
5-
TextDocument,
6-
TextEdit,
7-
} from "vscode-languageserver-textdocument";
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Equinor ASA
3+
* Licensed under the MIT License. See LICENSE in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import yargs, { CommandModule } from "yargs";
7+
import { TextDocument, TextEdit } from "vscode-languageserver-textdocument";
88
import * as fs from "fs";
99
import * as path from "path";
1010
import { SepticCnfg } from "../cnfg";
1111
import { SepticCnfgFormatter } from "../formatter";
12-
import {
13-
validateFileExists,
14-
createDocumentFromFile,
15-
runCli,
16-
} from "./utils";
12+
import { validateFileExists, createDocumentFromFile } from "./utils";
1713

1814
interface FormatOptions {
1915
file: string;
2016
check?: boolean | undefined;
2117
output?: string | undefined;
2218
}
2319

24-
function parseArguments(): FormatOptions {
25-
const argv = yargs(hideBin(process.argv))
26-
.command("$0 <file>", "Format a Septic config file", (yargs) => {
27-
return yargs.positional("file", {
28-
type: "string",
29-
description: "Path to Septic config file to format",
30-
});
31-
})
32-
.option("check", {
33-
alias: "c",
34-
type: "boolean",
35-
description: "Check if the file is formatted without modifying it",
36-
default: false,
37-
})
38-
.option("output", {
39-
alias: "o",
40-
type: "string",
41-
description:
42-
"Output path for formatted file (default: overwrites input file)",
43-
})
44-
.example("$0 config.cnfg", "Format a config file")
45-
.example(
46-
"$0 config.cnfg --check",
47-
"Check if a config file is formatted",
48-
)
49-
.example(
50-
"$0 config.cnfg --output formatted.cnfg",
51-
"Format and save to a different file",
52-
)
53-
.help()
54-
.parseSync();
55-
56-
if (!argv.file) {
57-
console.error("No file specified for formatting.");
58-
process.exit(1);
59-
}
60-
61-
const options: FormatOptions = {
62-
file: argv.file as string,
63-
check: argv.check,
64-
output: argv.output,
65-
};
66-
67-
return options;
68-
}
69-
7020
function formatSepticConfig(document: TextDocument): TextEdit[] {
7121
const cnfg = new SepticCnfg(document);
7222
cnfg.parse(undefined);
@@ -124,8 +74,7 @@ function checkFormatting(
12474
return originalContent === formattedContent;
12575
}
12676

127-
async function main(): Promise<void> {
128-
const options = parseArguments();
77+
async function handler(options: FormatOptions): Promise<void> {
12978
validateFileExists(options.file);
13079

13180
const document = createDocumentFromFile(options.file);
@@ -161,4 +110,43 @@ async function main(): Promise<void> {
161110
}
162111
}
163112

164-
runCli(main);
113+
export const formatCommand: CommandModule<object, FormatOptions> = {
114+
command: "format <file>",
115+
describe: "Format a Septic config file",
116+
builder: (yargs) => {
117+
return yargs
118+
.positional("file", {
119+
type: "string",
120+
description: "Path to Septic config file to format",
121+
demandOption: true,
122+
})
123+
.option("check", {
124+
alias: "c",
125+
type: "boolean",
126+
description:
127+
"Check if the file is formatted without modifying it",
128+
default: false,
129+
})
130+
.option("output", {
131+
alias: "o",
132+
type: "string",
133+
description:
134+
"Output path for formatted file (default: overwrites input file)",
135+
})
136+
.example("$0 format config.cnfg", "Format a config file")
137+
.example(
138+
"$0 format config.cnfg --check",
139+
"Check if a config file is formatted",
140+
)
141+
.example(
142+
"$0 format config.cnfg --output formatted.cnfg",
143+
"Format and save to a different file",
144+
) as unknown as yargs.Argv<FormatOptions>;
145+
},
146+
handler: (argv) => {
147+
handler(argv).catch((error) => {
148+
console.error("Unexpected error:", error);
149+
process.exit(1);
150+
});
151+
},
152+
};

packages/septic/src/cli/index.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env node
2+
/*---------------------------------------------------------------------------------------------
3+
* Copyright (c) Equinor ASA
4+
* Licensed under the MIT License. See LICENSE in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
import yargs from "yargs";
8+
import { hideBin } from "yargs/helpers";
9+
import { formatCommand } from "./format";
10+
import { lintCommand } from "./lint";
11+
12+
yargs(hideBin(process.argv))
13+
.command(formatCommand)
14+
.command(lintCommand)
15+
.demandCommand(1, "You need to specify a command")
16+
.help()
17+
.version()
18+
.strict()
19+
.parse();

packages/septic/src/cli/lint.ts

Lines changed: 53 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
#!/usr/bin/env node
2-
import yargs from "yargs";
3-
import { hideBin } from "yargs/helpers";
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Equinor ASA
3+
* Licensed under the MIT License. See LICENSE in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import yargs, { CommandModule } from "yargs";
47
import { TextDocument } from "vscode-languageserver-textdocument";
58
import { SepticCnfg } from "../cnfg";
69
import {
@@ -9,64 +12,12 @@ import {
912
SepticDiagnosticLevel,
1013
} from "../diagnostics";
1114
import { SepticMetaInfoProvider } from "../metaInfoProvider";
12-
import { validateFileExists, createDocumentFromFile, runCli } from "./utils";
15+
import { validateFileExists, createDocumentFromFile } from "./utils";
1316

1417
interface LintOptions {
1518
file: string;
1619
ignore?: string[];
17-
version?: string;
18-
}
19-
20-
function parseArguments(): LintOptions {
21-
const availableVersions = SepticMetaInfoProvider.getAvailableVersions();
22-
const versionList = availableVersions.join(", ");
23-
24-
const argv = yargs(hideBin(process.argv))
25-
.command("$0 <file>", "Lint a Septic config file", (yargs) => {
26-
return yargs.positional("file", {
27-
type: "string",
28-
description: "Path to Septic config file to lint",
29-
});
30-
})
31-
.option("ignore", {
32-
alias: "i",
33-
type: "array",
34-
description: "Diagnostic codes to ignore (e.g., W101 E202)",
35-
string: true,
36-
})
37-
.option("septicversion", {
38-
alias: "s",
39-
type: "string",
40-
description: `Septic version to use for linting (available: ${versionList})`,
41-
default: "latest",
42-
})
43-
.example("$0 config.cnfg", "Lint a config file")
44-
.example(
45-
"$0 config.cnfg --ignore W101 W203",
46-
"Lint and ignore specific diagnostic codes",
47-
)
48-
.example(
49-
"$0 config.cnfg --septicversion v3.5",
50-
"Lint using Septic version 3.5",
51-
)
52-
.help()
53-
.parseSync();
54-
55-
if (!argv.file) {
56-
console.error("No file specified for linting.");
57-
process.exit(1);
58-
}
59-
60-
const options: LintOptions = {
61-
file: argv.file as string,
62-
version: argv.septicversion as string,
63-
};
64-
65-
if (argv.ignore) {
66-
options.ignore = argv.ignore as string[];
67-
}
68-
69-
return options;
20+
septicversion?: string;
7021
}
7122

7223
async function lintSepticConfig(
@@ -114,13 +65,12 @@ function printDiagnostics(diagnostics: SepticDiagnostic[], uri: string): void {
11465
}
11566
}
11667

117-
async function main(): Promise<void> {
118-
const options = parseArguments();
68+
async function handler(options: LintOptions): Promise<void> {
11969
validateFileExists(options.file);
12070

12171
// Set the version to use for linting
122-
if (options.version) {
123-
SepticMetaInfoProvider.setVersion(options.version);
72+
if (options.septicversion) {
73+
SepticMetaInfoProvider.setVersion(options.septicversion);
12474
}
12575

12676
const document = createDocumentFromFile(options.file);
@@ -142,4 +92,45 @@ async function main(): Promise<void> {
14292
process.exit(exitCode);
14393
}
14494

145-
runCli(main);
95+
export const lintCommand: CommandModule<object, LintOptions> = {
96+
command: "lint <file>",
97+
describe: "Lint a Septic config file",
98+
builder: (yargs) => {
99+
const availableVersions = SepticMetaInfoProvider.getAvailableVersions();
100+
const versionList = availableVersions.join(", ");
101+
102+
return yargs
103+
.positional("file", {
104+
type: "string",
105+
description: "Path to Septic config file to lint",
106+
demandOption: true,
107+
})
108+
.option("ignore", {
109+
alias: "i",
110+
type: "array",
111+
description: "Diagnostic codes to ignore (e.g., W101 E202)",
112+
string: true,
113+
})
114+
.option("septicversion", {
115+
alias: "s",
116+
type: "string",
117+
description: `Septic version to use for linting (available: ${versionList})`,
118+
default: "latest",
119+
})
120+
.example("$0 lint config.cnfg", "Lint a config file")
121+
.example(
122+
"$0 lint config.cnfg --ignore W101 W203",
123+
"Lint and ignore specific diagnostic codes",
124+
)
125+
.example(
126+
"$0 lint config.cnfg --septicversion v3.5",
127+
"Lint using Septic version 3.5",
128+
) as unknown as yargs.Argv<LintOptions>;
129+
},
130+
handler: (argv) => {
131+
handler(argv).catch((error) => {
132+
console.error("Unexpected error:", error);
133+
process.exit(1);
134+
});
135+
},
136+
};

packages/septic/src/cli/utils.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,3 @@ export function createDocumentFromFile(filePath: string): TextDocument {
2323
fileContent,
2424
);
2525
}
26-
27-
export async function runCli(mainFn: () => Promise<void>): Promise<void> {
28-
mainFn().catch((error) => {
29-
console.error("Unexpected error:", error);
30-
process.exit(1);
31-
});
32-
}

0 commit comments

Comments
 (0)