Skip to content

Commit b98f548

Browse files
committed
feat: rework logger
1 parent 0868ac7 commit b98f548

File tree

13 files changed

+145
-65
lines changed

13 files changed

+145
-65
lines changed

src/app/app.module.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Module } from '@nestjs/common'
2-
import { RunCommand } from '@/commands/run.command'
3-
import { ShowCommand } from '@/commands/show.command'
2+
import { Commands } from '@/commands'
3+
import { LoggerModule } from '@/logger'
44
import { PackageManagerModule } from '@/pkg-manager'
55

66
@Module({
7-
imports: [PackageManagerModule],
8-
providers: [RunCommand, ShowCommand]
7+
imports: [PackageManagerModule, LoggerModule],
8+
providers: [...Commands]
99
})
1010
export class AppModule {}

src/commands/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { RunCommand } from './run.command'
2+
import { ShowCommand } from './show.command'
3+
4+
export const Commands = [RunCommand, ShowCommand]

src/commands/run.command.ts

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { ensureFile } from '@neodx/fs'
2-
import { hasOwn, isNil } from '@neodx/std'
2+
import { hasOwn, isObject } from '@neodx/std'
3+
import { Inject } from '@nestjs/common'
34
import chalk from 'chalk'
45
import { Command, CommandRunner, Option } from 'nest-commander'
56
import { dirname, resolve } from 'node:path'
7+
import { LoggerService } from '@/logger'
68
import type { AbstractPackageManager } from '@/pkg-manager'
79
import { InjectPackageManager } from '@/pkg-manager'
810
import { PackageManager } from '@/pkg-manager/pkg-manager.consts'
911
import type { PackageJson } from '@/shared/json'
1012
import { readJson } from '@/shared/json'
11-
import { addLibraryPrefix } from '@/shared/misc'
13+
import { invariant } from '@/shared/misc'
1214

1315
export interface BaseInitOptions {
1416
args?: string
@@ -23,20 +25,18 @@ export interface BaseInitOptions {
2325
})
2426
export class RunCommand extends CommandRunner {
2527
constructor(
26-
@InjectPackageManager() private readonly manager: AbstractPackageManager
28+
@InjectPackageManager() private readonly manager: AbstractPackageManager,
29+
@Inject(LoggerService) private readonly logger: LoggerService
2730
) {
2831
super()
2932
}
3033

3134
public async run(params: string[], options: BaseInitOptions) {
3235
const [target, project = null] = params
3336

34-
if (!target) {
35-
console.log('no target')
36-
return
37-
}
37+
invariant(target, 'Target is not provided.')
3838

39-
const startTime = Date.now()
39+
const timeEnd = this.logger.time()
4040

4141
let packageJsonPath = resolve(process.cwd(), 'package.json')
4242

@@ -47,28 +47,24 @@ export class RunCommand extends CommandRunner {
4747
(workspace) => workspace.name === project
4848
)
4949

50-
if (!projectMeta) {
51-
// TODO improve errors rewrite to class
52-
throw new Error(
53-
`Project ${chalk.cyan(project)} not found. Please ensure it exists.`
54-
)
55-
}
50+
invariant(
51+
projectMeta,
52+
`Project ${project} not found. Please ensure it exists.`
53+
)
5654

5755
packageJsonPath = resolve(projectMeta.location, 'package.json')
5856
}
5957

6058
await ensureFile(packageJsonPath)
6159

62-
const pkg = (await readJson(packageJsonPath)) as PackageJson
60+
const pkg = await readJson<PackageJson>(packageJsonPath)
6361

6462
const projectName = project ?? pkg.name ?? 'root'
6563

66-
if (isNil(pkg.scripts) || !hasOwn(pkg.scripts, target)) {
67-
// TODO improve errors
68-
throw new Error(
69-
`Could not find target ${chalk.cyan(target)} in project ${chalk.white(projectName)}.`
70-
)
71-
}
64+
invariant(
65+
isObject(pkg.scripts) && hasOwn(pkg.scripts, target),
66+
`Could not find target ${chalk.cyan(target)} in project ${chalk.white(projectName)}.`
67+
)
7268

7369
const command = this.manager.createRunCommand({
7470
target,
@@ -86,15 +82,13 @@ export class RunCommand extends CommandRunner {
8682

8783
await this.manager.exec(command, { stdio: 'inherit', cwd })
8884
} catch (error) {
89-
console.log(error)
85+
this.logger.error(
86+
`Error occurred while executing a command via ${this.manager.agent} agent.`
87+
)
88+
this.logger.error(error)
9089
}
9190

92-
// TODO: improve logger
93-
console.info(
94-
addLibraryPrefix(
95-
`Successfully ran target ${chalk.cyan(target)} for project ${chalk.white(project ?? pkg.name)} (${Date.now() - startTime} ms)`
96-
)
97-
)
91+
timeEnd(`Successfully ran target ${target} for project ${projectName}`)
9892
}
9993

10094
@Option({
@@ -106,9 +100,7 @@ export class RunCommand extends CommandRunner {
106100

107101
const isValid = args.match(/^--\w+=\w+$/)
108102

109-
if (!isValid) {
110-
throw new Error('not valid')
111-
}
103+
invariant(isValid, "The 'args' parameter is invalid. ")
112104

113105
return args
114106
}

src/commands/show.command.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { serializeJson } from '@neodx/fs'
1+
import { Inject } from '@nestjs/common'
22
import chalk from 'chalk'
33
import {
44
CliUtilityService,
55
Command,
66
CommandRunner,
77
Option
88
} from 'nest-commander'
9+
import { LoggerService } from '@/logger'
910
import type { AbstractPackageManager } from '@/pkg-manager'
1011
import { InjectPackageManager } from '@/pkg-manager'
11-
import { addLibraryPrefix } from '@/shared/misc'
1212

1313
export interface ShowCommandOptions {
1414
json?: boolean
@@ -22,6 +22,7 @@ export interface ShowCommandOptions {
2222
export class ShowCommand extends CommandRunner {
2323
constructor(
2424
@InjectPackageManager() private readonly manager: AbstractPackageManager,
25+
@Inject(LoggerService) private readonly logger: LoggerService,
2526
private readonly utilityService: CliUtilityService
2627
) {
2728
super()
@@ -32,16 +33,13 @@ export class ShowCommand extends CommandRunner {
3233
const workspaces = await this.manager.getWorkspaces()
3334

3435
if (options.json) {
35-
const serializedJson = serializeJson(workspaces)
36-
console.info(serializedJson)
36+
this.logger.serialize(workspaces)
3737
return
3838
}
3939

4040
for (const workspace of workspaces) {
41-
console.info(
42-
addLibraryPrefix(
43-
`${chalk.cyan(workspace.name)} - ${chalk.white(workspace.location)}`
44-
)
41+
this.logger.log(
42+
`${chalk.cyan(workspace.name)} - ${chalk.white(workspace.location)}`
4543
)
4644
}
4745
}

src/logger/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './logger.consts'
2+
export { LoggerModule } from './logger.module'
3+
export { LoggerService } from './logger.service'

src/logger/logger.consts.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import chalk from 'chalk'
2+
3+
export const ERROR_PREFIX = chalk.inverse(chalk.bold(chalk.red(' ERROR ')))
4+
export const LIBRARY_PREFIX = `${chalk.cyan('>')} ${chalk.inverse(chalk.bold(chalk.cyanBright(' GX ')))}`

src/logger/logger.module.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Global, Module } from '@nestjs/common'
2+
import { LoggerService } from '@/logger/logger.service'
3+
4+
@Global()
5+
@Module({
6+
providers: [LoggerService],
7+
exports: [LoggerService]
8+
})
9+
export class LoggerModule {}

src/logger/logger.service.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { serializeJson } from '@neodx/fs'
2+
import { isTypeOfString } from '@neodx/std'
3+
import { Injectable } from '@nestjs/common'
4+
import chalk from 'chalk'
5+
import { ERROR_PREFIX, LIBRARY_PREFIX } from '@/logger/logger.consts'
6+
7+
@Injectable()
8+
export class LoggerService {
9+
public get errorPrefix() {
10+
return ERROR_PREFIX
11+
}
12+
13+
public get libraryPrefix() {
14+
return LIBRARY_PREFIX
15+
}
16+
17+
public warn(msg: string) {
18+
console.warn(chalk.bold(chalk.yellow(msg)))
19+
}
20+
21+
public error(msg: unknown) {
22+
if (isTypeOfString(msg)) {
23+
console.error(`\n ${this.errorPrefix} ${chalk.bold(chalk.red(msg))}\n`)
24+
} else if (msg instanceof Error && msg.stack) {
25+
console.error(chalk.bold(chalk.red(msg.stack)))
26+
} else {
27+
console.error(chalk.bold(chalk.red(msg)))
28+
}
29+
}
30+
31+
public info(msg: unknown) {
32+
if (isTypeOfString(msg)) {
33+
console.info(`\n${this.libraryPrefix} ${chalk.bold(msg)}\n`)
34+
} else console.info(msg)
35+
}
36+
37+
public time(method = this.log) {
38+
const startTime = Date.now()
39+
40+
return (msg: string) => {
41+
method(`${msg} (${Date.now() - startTime} ms)`)
42+
}
43+
}
44+
45+
public serialize(msg: unknown, method = this.log) {
46+
method(serializeJson(msg))
47+
}
48+
49+
public log(msg: string) {
50+
console.log(msg)
51+
}
52+
53+
public debug(msg: string) {
54+
console.debug(msg)
55+
}
56+
57+
public fatal(msg: string) {
58+
console.error(msg)
59+
}
60+
}

src/pkg-manager/managers/bun.pkg-manager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class BunPackageManager extends AbstractPackageManager {
2020
}
2121

2222
public async getWorkspaces(): Promise<WorkspaceProject[]> {
23-
const packageJson = await readJson('package.json')
23+
const packageJson = await readJson<PackageJson>('package.json')
2424

2525
if (!packageJson) return []
2626

src/pkg-manager/pkg-manager.factory.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { cmdExists } from '@antfu/ni'
21
import { ensureFile, scan } from '@neodx/fs'
32
import { isTypeOfString, uniq, values } from '@neodx/std'
43
import chalk from 'chalk'
54
import { execaCommand as $ } from 'execa'
65
import { basename, resolve } from 'node:path'
6+
import { LoggerService } from '@/logger'
77
import type { AbstractPackageManager } from '@/pkg-manager/managers/abstract.pkg-manager'
88
import { YarnBerryPackageManager } from '@/pkg-manager/managers/yarn-berry.pkg-manager'
99
import {
@@ -12,9 +12,12 @@ import {
1212
} from '@/pkg-manager/pkg-manager.consts'
1313
import type { PackageJson } from '@/shared/json'
1414
import { readJson } from '@/shared/json'
15-
import { addLibraryPrefix } from '@/shared/misc'
15+
import { invariant } from '@/shared/misc'
16+
import { cmdExists } from '@/shared/sh'
1617

1718
export class PackageManagerFactory {
19+
private static logger = new LoggerService()
20+
1821
public static async detect(): Promise<AbstractPackageManager> {
1922
let programmaticAgent: PackageManager
2023

@@ -33,7 +36,7 @@ export class PackageManagerFactory {
3336

3437
await ensureFile(packageJsonPath)
3538

36-
const pkg = (await readJson(packageJsonPath)) as PackageJson
39+
const pkg = await readJson<PackageJson>(packageJsonPath)
3740

3841
if (isTypeOfString(pkg.packageManager)) {
3942
const [name, version] = pkg.packageManager.replace(/^\^/, '').split('@')
@@ -59,16 +62,12 @@ export class PackageManagerFactory {
5962
programmaticAgent === matcher.name
6063
)
6164

62-
if (!match) {
63-
throw new Error('Unable to detect a package manager.')
64-
}
65+
invariant(match, 'Unable to detect a package manager.')
6566

6667
if (!cmdExists(match.name)) {
67-
console.warn(addLibraryPrefix(`${match.name} is not installed.`))
68-
console.info(
69-
addLibraryPrefix(
70-
`Attempting to install ${chalk.cyan(match.name)} globally...`
71-
)
68+
this.logger.warn(`${match.name} is not installed.`)
69+
this.logger.info(
70+
`Attempting to install ${chalk.cyan(match.name)} globally...`
7271
)
7372

7473
await $(`npm i -g ${match.name}`, {

0 commit comments

Comments
 (0)