Skip to content

Commit

Permalink
fix(cli): avoid global side effect, improve tests
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jun 18, 2022
1 parent e9cd7bb commit 710b3ce
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 148 deletions.
37 changes: 37 additions & 0 deletions packages/cli/src/cli-start.ts
@@ -0,0 +1,37 @@
import { cac } from 'cac'
import { version } from '../package.json'
import type { CliOptions } from './types'
import { build } from './index'

export async function startCli(cwd = process.cwd(), argv = process.argv, options: CliOptions = {}) {
const cli = cac('unocss')

cli
.command('[...patterns]', 'Glob patterns', {
ignoreOptionDefaultValue: true,
})
.option('-o, --out-file <file>', 'Output file', {
default: cwd,
})
.option('-c, --config [file]', 'Config file')
.option('-w, --watch', 'Watch for file changes')
.action(async (patterns: Array<string>, flags) => {
Object.assign(options, {
cwd,
...flags,
})

if (patterns)
options.patterns = patterns

await build(options)
})

cli.help()
cli.version(version)

// Parse CLI args without running the command to
// handle command errors globally
cli.parse(argv, { run: false })
await cli.runMatchedCommand()
}
42 changes: 2 additions & 40 deletions packages/cli/src/cli.ts
@@ -1,42 +1,4 @@
import { cac } from 'cac'
import { version } from '../package.json'
import { startCli } from './cli-start'
import { handleError } from './errors'
import type { CliOptions } from './types'
import { build } from './index'

const name = 'unocss'

async function main(options: CliOptions = {}) {
const cli = cac(name)

cli
.command('[...patterns]', 'Glob patterns', {
ignoreOptionDefaultValue: true,
})
.option('-o, --out-file <file>', 'Output file', {
default: process.cwd(),
})
.option('-c, --config [file]', 'Config file')
.option('-w, --watch', 'Watch for file changes')
.action(async (patterns: Array<string>, flags) => {
Object.assign(options, {
...flags,
})

if (patterns)
options.patterns = patterns

await build(options)
})

cli.help()

cli.version(version)

// Parse CLI args without running the command to
// handle command errors globally
cli.parse(process.argv, { run: false })
await cli.runMatchedCommand()
}

main().catch(handleError)
startCli().catch(handleError)
57 changes: 27 additions & 30 deletions packages/cli/src/index.ts
Expand Up @@ -5,37 +5,13 @@ import consola from 'consola'
import { cyan, dim, green } from 'colorette'
import { debounce } from 'perfect-debounce'
import { createGenerator, toArray } from '@unocss/core'
import type { UnoGenerator } from '@unocss/core'
import { loadConfig } from '@unocss/config'
import { version } from '../package.json'
import { PrettyError, handleError } from './errors'
import { defaultConfig } from './config'
import type { CliOptions, ResolvedCliOptions } from './types'

const name = 'unocss'
let uno: UnoGenerator

const fileCache = new Map<string, string>()

const getAbsolutePath = (file: string) => resolve(process.cwd(), file)

export async function generate(options: ResolvedCliOptions) {
const outFile = options.outFile ?? getAbsolutePath('uno.css')
const { css, matched } = await uno.generate([...fileCache].join('\n'))

const dir = dirname(outFile)
if (!existsSync(dir))
await fs.mkdir(dir, { recursive: true })
await fs.writeFile(outFile, css, 'utf-8')

if (!options.watch) {
consola.success(
`${[...matched].length} utilities generated to ${cyan(
relative(process.cwd(), outFile),
)}\n`,
)
}
}

export async function resolveOptions(options: CliOptions) {
if (!options.patterns?.length) {
Expand All @@ -48,19 +24,21 @@ export async function resolveOptions(options: CliOptions) {
}

export async function build(_options: CliOptions) {
const fileCache = new Map<string, string>()

const cwd = _options.cwd || process.cwd()
const options = await resolveOptions(_options)
const { config, sources: configSources } = await loadConfig(process.cwd(), options.config)
const { config, sources: configSources } = await loadConfig(cwd, options.config)

uno = createGenerator(
const uno = createGenerator(
config,
defaultConfig,
)

const files = await fg(options.patterns)
const files = await fg(options.patterns, { cwd, absolute: true })
await Promise.all(
files.map(async (file) => {
const absolutePath = getAbsolutePath(file)
fileCache.set(absolutePath, await fs.readFile(absolutePath, 'utf8'))
fileCache.set(file, await fs.readFile(file, 'utf8'))
}),
)

Expand All @@ -86,6 +64,7 @@ export async function build(_options: CliOptions) {
ignoreInitial: true,
ignorePermissionErrors: true,
ignored,
cwd,
})

if (configSources.length)
Expand All @@ -99,7 +78,7 @@ export async function build(_options: CliOptions) {
else {
consola.log(`${green(type)} ${dim(file)}`)

const absolutePath = getAbsolutePath(file)
const absolutePath = resolve(cwd, file)
if (type.startsWith('unlink'))
fileCache.delete(absolutePath)
else
Expand All @@ -120,4 +99,22 @@ export async function build(_options: CliOptions) {
await generate(options)

startWatcher()

async function generate(options: ResolvedCliOptions) {
const outFile = resolve(options.cwd || process.cwd(), options.outFile ?? 'uno.css')
const { css, matched } = await uno.generate([...fileCache].join('\n'))

const dir = dirname(outFile)
if (!existsSync(dir))
await fs.mkdir(dir, { recursive: true })
await fs.writeFile(outFile, css, 'utf-8')

if (!options.watch) {
consola.success(
`${[...matched].length} utilities generated to ${cyan(
relative(process.cwd(), outFile),
)}\n`,
)
}
}
}
1 change: 1 addition & 0 deletions packages/cli/src/types.ts
Expand Up @@ -2,6 +2,7 @@
declare type MarkRequired<T, RK extends keyof T> = Exclude<T, RK> & Required<Pick<T, RK>>

export interface CliOptions {
cwd?: string
patterns?: Array<string>
outFile?: string
watch?: boolean
Expand Down
1 change: 1 addition & 0 deletions packages/inspector/client/auto-imports.d.ts
Expand Up @@ -148,6 +148,7 @@ declare global {
const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
const useInterval: typeof import('@vueuse/core')['useInterval']
Expand Down
2 changes: 1 addition & 1 deletion packages/vscode/package.json
@@ -1,6 +1,6 @@
{
"publisher": "antfu",
"name": "unocss",
"name": "@unocss/vscode",
"displayName": "UnoCSS",
"version": "0.39.2",
"private": true,
Expand Down
60 changes: 36 additions & 24 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 710b3ce

Please sign in to comment.