Skip to content

Commit 9034fd7

Browse files
committed
refactor: extract CLI utilities (parseCliFlags, createLogger) to paths.mjs
Signed-off-by: leocavalcante <leo@cavalcante.dev>
1 parent ebc0a99 commit 9034fd7

5 files changed

Lines changed: 249 additions & 28 deletions

File tree

postinstall.mjs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,26 @@ import { join } from "node:path"
1212

1313
import {
1414
AGENTS_TARGET_DIR,
15+
createLogger,
1516
getAgentsSourceDir,
1617
getErrorMessage,
1718
getPackageRoot,
19+
parseCliFlags,
1820
retryOnTransientError,
1921
validateAgentContent,
2022
} from "./src/paths.mjs"
2123

2224
const packageRoot = getPackageRoot(import.meta.url)
2325
const AGENTS_SOURCE_DIR = getAgentsSourceDir(packageRoot)
2426

25-
/** Check for --dry-run flag in command line arguments */
26-
const DRY_RUN = process.argv.includes("--dry-run")
27+
/** Parse command line flags */
28+
const flags = parseCliFlags(process.argv)
29+
const DRY_RUN = flags.dryRun
30+
const VERBOSE = flags.verbose
2731

28-
/** Check for --verbose flag in command line arguments */
29-
const VERBOSE = process.argv.includes("--verbose")
30-
31-
/**
32-
* Logs verbose output if --verbose flag is set.
33-
* @param {string} message - The message to log
34-
*/
35-
function verbose(message) {
36-
if (VERBOSE) {
37-
console.log(`[VERBOSE] ${message}`)
38-
}
39-
}
32+
/** Create logger with verbose flag */
33+
const logger = createLogger(VERBOSE)
34+
const verbose = logger.verbose
4035

4136
/**
4237
* Validates an agent file by reading and validating its content.

preuninstall.mjs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,25 @@ import { join } from "node:path"
1212

1313
import {
1414
AGENTS_TARGET_DIR,
15+
createLogger,
1516
getAgentsSourceDir,
1617
getErrorMessage,
1718
getPackageRoot,
19+
parseCliFlags,
1820
retryOnTransientError,
1921
} from "./src/paths.mjs"
2022

2123
const packageRoot = getPackageRoot(import.meta.url)
2224
const AGENTS_SOURCE_DIR = getAgentsSourceDir(packageRoot)
2325

24-
/** Check for --dry-run flag in command line arguments */
25-
const DRY_RUN = process.argv.includes("--dry-run")
26+
/** Parse command line flags */
27+
const flags = parseCliFlags(process.argv)
28+
const DRY_RUN = flags.dryRun
29+
const VERBOSE = flags.verbose
2630

27-
/** Check for --verbose flag in command line arguments */
28-
const VERBOSE = process.argv.includes("--verbose")
29-
30-
/**
31-
* Logs verbose output if --verbose flag is set.
32-
* @param {string} message - The message to log
33-
*/
34-
function verbose(message) {
35-
if (VERBOSE) {
36-
console.log(`[VERBOSE] ${message}`)
37-
}
38-
}
31+
/** Create logger with verbose flag */
32+
const logger = createLogger(VERBOSE)
33+
const verbose = logger.verbose
3934

4035
/**
4136
* Main entry point for the preuninstall script.

src/paths.d.mts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,50 @@ export function validateAgentContent(content: string): ValidateAgentContentResul
116116
* @returns True if current version satisfies the required range
117117
*/
118118
export function checkVersionCompatibility(required: string, current: string): boolean
119+
120+
/**
121+
* Parsed command line flags for install/uninstall scripts.
122+
*/
123+
export interface CliFlags {
124+
/** Simulate the operation without making changes */
125+
dryRun: boolean
126+
/** Enable verbose logging output */
127+
verbose: boolean
128+
/** Display help information */
129+
help: boolean
130+
}
131+
132+
/**
133+
* Parses command line flags for install/uninstall scripts.
134+
*
135+
* Recognizes the following flags:
136+
* - `--dry-run`: Simulate the operation without making changes
137+
* - `--verbose`: Enable verbose logging output
138+
* - `--help`: Display help information
139+
*
140+
* @param argv - The command line arguments array (typically process.argv)
141+
* @returns Parsed flags object
142+
*/
143+
export function parseCliFlags(argv: string[]): CliFlags
144+
145+
/**
146+
* Logger object with standard and verbose logging methods.
147+
*/
148+
export interface Logger {
149+
/** Log a message to console */
150+
log: (message: string) => void
151+
/** Log a verbose message (only when verbose mode is enabled) */
152+
verbose: (message: string) => void
153+
}
154+
155+
/**
156+
* Creates a logger object with standard and verbose logging methods.
157+
*
158+
* The logger provides two methods:
159+
* - `log(message)`: Always logs to console.log
160+
* - `verbose(message)`: Only logs when verbose mode is enabled, prefixed with [VERBOSE]
161+
*
162+
* @param verbose - Whether verbose logging is enabled
163+
* @returns Logger object
164+
*/
165+
export function createLogger(verbose: boolean): Logger

src/paths.mjs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,3 +405,66 @@ export function checkVersionCompatibility(required, current) {
405405
if (!rangeVersion) return false
406406
return compareVersions(currentVersion, rangeVersion) === 0
407407
}
408+
409+
/**
410+
* Parses command line flags for install/uninstall scripts.
411+
*
412+
* Recognizes the following flags:
413+
* - `--dry-run`: Simulate the operation without making changes
414+
* - `--verbose`: Enable verbose logging output
415+
* - `--help`: Display help information
416+
*
417+
* @param {string[]} argv - The command line arguments array (typically process.argv)
418+
* @returns {{ dryRun: boolean, verbose: boolean, help: boolean }} Parsed flags
419+
*
420+
* @example
421+
* // Parse process.argv
422+
* const flags = parseCliFlags(process.argv)
423+
* if (flags.help) {
424+
* console.log("Usage: ...")
425+
* process.exit(0)
426+
* }
427+
*
428+
* @example
429+
* // Parse custom arguments
430+
* const flags = parseCliFlags(["node", "script.js", "--verbose", "--dry-run"])
431+
* // flags = { dryRun: true, verbose: true, help: false }
432+
*/
433+
export function parseCliFlags(argv) {
434+
return {
435+
dryRun: argv.includes("--dry-run"),
436+
verbose: argv.includes("--verbose"),
437+
help: argv.includes("--help"),
438+
}
439+
}
440+
441+
/**
442+
* Creates a logger object with standard and verbose logging methods.
443+
*
444+
* The logger provides two methods:
445+
* - `log(message)`: Always logs to console.log
446+
* - `verbose(message)`: Only logs when verbose mode is enabled, prefixed with [VERBOSE]
447+
*
448+
* @param {boolean} verbose - Whether verbose logging is enabled
449+
* @returns {{ log: (message: string) => void, verbose: (message: string) => void }} Logger object
450+
*
451+
* @example
452+
* const logger = createLogger(true)
453+
* logger.log("Installing agents...") // Always prints
454+
* logger.verbose("Source: /path/to/src") // Prints: [VERBOSE] Source: /path/to/src
455+
*
456+
* @example
457+
* const logger = createLogger(false)
458+
* logger.log("Installing agents...") // Prints
459+
* logger.verbose("Source: /path/to/src") // Does nothing (verbose disabled)
460+
*/
461+
export function createLogger(verbose) {
462+
return {
463+
log: (message) => console.log(message),
464+
verbose: (message) => {
465+
if (verbose) {
466+
console.log(`[VERBOSE] ${message}`)
467+
}
468+
},
469+
}
470+
}

tests/paths.test.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import { join } from "node:path"
44
import {
55
AGENTS_TARGET_DIR,
66
checkVersionCompatibility,
7+
createLogger,
78
getAgentsSourceDir,
89
getErrorMessage,
910
getPackageRoot,
1011
isTransientError,
1112
MIN_CONTENT_LENGTH,
13+
parseCliFlags,
1214
parseFrontmatter,
1315
REQUIRED_FRONTMATTER_FIELDS,
1416
REQUIRED_KEYWORDS,
@@ -760,4 +762,123 @@ This is a test agent that handles various tasks.
760762
})
761763
})
762764
})
765+
766+
describe("parseCliFlags", () => {
767+
it("should return all false flags for empty argv", () => {
768+
const result = parseCliFlags([])
769+
expect(result).toEqual({ dryRun: false, verbose: false, help: false })
770+
})
771+
772+
it("should return all false flags for argv without flags", () => {
773+
const result = parseCliFlags(["node", "script.js"])
774+
expect(result).toEqual({ dryRun: false, verbose: false, help: false })
775+
})
776+
777+
it("should detect --dry-run flag", () => {
778+
const result = parseCliFlags(["node", "script.js", "--dry-run"])
779+
expect(result.dryRun).toBe(true)
780+
expect(result.verbose).toBe(false)
781+
expect(result.help).toBe(false)
782+
})
783+
784+
it("should detect --verbose flag", () => {
785+
const result = parseCliFlags(["node", "script.js", "--verbose"])
786+
expect(result.dryRun).toBe(false)
787+
expect(result.verbose).toBe(true)
788+
expect(result.help).toBe(false)
789+
})
790+
791+
it("should detect --help flag", () => {
792+
const result = parseCliFlags(["node", "script.js", "--help"])
793+
expect(result.dryRun).toBe(false)
794+
expect(result.verbose).toBe(false)
795+
expect(result.help).toBe(true)
796+
})
797+
798+
it("should detect multiple flags", () => {
799+
const result = parseCliFlags(["node", "script.js", "--dry-run", "--verbose"])
800+
expect(result.dryRun).toBe(true)
801+
expect(result.verbose).toBe(true)
802+
expect(result.help).toBe(false)
803+
})
804+
805+
it("should detect all flags", () => {
806+
const result = parseCliFlags(["node", "script.js", "--dry-run", "--verbose", "--help"])
807+
expect(result).toEqual({ dryRun: true, verbose: true, help: true })
808+
})
809+
810+
it("should ignore unknown flags", () => {
811+
const result = parseCliFlags(["node", "script.js", "--unknown", "--other"])
812+
expect(result).toEqual({ dryRun: false, verbose: false, help: false })
813+
})
814+
815+
it("should handle flags in any position", () => {
816+
const result = parseCliFlags(["--verbose", "node", "--dry-run", "script.js", "--help"])
817+
expect(result).toEqual({ dryRun: true, verbose: true, help: true })
818+
})
819+
820+
it("should not match partial flag names", () => {
821+
const result = parseCliFlags(["node", "script.js", "--dry-run-test", "--verbosity"])
822+
expect(result.dryRun).toBe(false)
823+
expect(result.verbose).toBe(false)
824+
})
825+
})
826+
827+
describe("createLogger", () => {
828+
it("should return an object with log and verbose methods", () => {
829+
const logger = createLogger(false)
830+
expect(typeof logger.log).toBe("function")
831+
expect(typeof logger.verbose).toBe("function")
832+
})
833+
834+
it("should log messages with log() method", () => {
835+
const originalLog = console.log
836+
const messages: string[] = []
837+
console.log = (msg: string) => messages.push(msg)
838+
839+
const logger = createLogger(false)
840+
logger.log("test message")
841+
842+
console.log = originalLog
843+
expect(messages).toContain("test message")
844+
})
845+
846+
it("should not log verbose messages when verbose is false", () => {
847+
const originalLog = console.log
848+
const messages: string[] = []
849+
console.log = (msg: string) => messages.push(msg)
850+
851+
const logger = createLogger(false)
852+
logger.verbose("verbose message")
853+
854+
console.log = originalLog
855+
expect(messages).toHaveLength(0)
856+
})
857+
858+
it("should log verbose messages with [VERBOSE] prefix when verbose is true", () => {
859+
const originalLog = console.log
860+
const messages: string[] = []
861+
console.log = (msg: string) => messages.push(msg)
862+
863+
const logger = createLogger(true)
864+
logger.verbose("verbose message")
865+
866+
console.log = originalLog
867+
expect(messages).toContain("[VERBOSE] verbose message")
868+
})
869+
870+
it("should log both normal and verbose messages when verbose is true", () => {
871+
const originalLog = console.log
872+
const messages: string[] = []
873+
console.log = (msg: string) => messages.push(msg)
874+
875+
const logger = createLogger(true)
876+
logger.log("normal message")
877+
logger.verbose("verbose message")
878+
879+
console.log = originalLog
880+
expect(messages).toContain("normal message")
881+
expect(messages).toContain("[VERBOSE] verbose message")
882+
})
883+
})
763884
})

0 commit comments

Comments
 (0)