-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add base CLI tool and parsing options
- Loading branch information
Showing
7 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#!/usr/bin/env node | ||
|
||
import { cliRootDir, indent, packageCwd } from '#lib/constants'; | ||
import { logVerboseError, logVerboseInfo } from '#lib/logVerbose'; | ||
import { parseOptionsFile } from '#lib/optionsParser'; | ||
import { existsAsync } from '#lib/promisified'; | ||
import { cyan } from 'colorette'; | ||
import { Command } from 'commander'; | ||
import { readFile } from 'fs/promises'; | ||
import { join } from 'path'; | ||
import { URL } from 'url'; | ||
|
||
const packageFile = new URL('package.json', cliRootDir); | ||
const packageJson = JSON.parse(await readFile(packageFile, 'utf-8')); | ||
|
||
const command = new Command() | ||
.version(packageJson.version) | ||
.argument('<dist-directory>') | ||
.usage(`${cyan('<dist-directory>')}`) | ||
.option('-v, --verbose', 'Print verbose information', false) | ||
.option( | ||
'-e, --external [external...]', | ||
`Repeatable, each will be treated as a new entry. Library or libraries to treat as external in Rollup (see: ${cyan( | ||
'https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency' | ||
)})`, | ||
(value: string, previous: string[]) => previous.concat([value]), | ||
[] | ||
); | ||
|
||
const program = command.parse(process.argv); | ||
const options = await parseOptionsFile(program.opts()); | ||
|
||
const packageJsonPath = join(packageCwd, 'package.json'); | ||
const packageJsonExistsInCwd = await existsAsync(packageJsonPath); | ||
|
||
if (!packageJsonExistsInCwd) { | ||
logVerboseError({ | ||
text: ['Could not find a file named "package.json" in the current working directory. Are you sure this is a NodeJS repository?'], | ||
verbose: options.verbose, | ||
verboseText: ['I detected this current working directory: ', process.cwd()], | ||
exitAfterLog: true | ||
}); | ||
} | ||
|
||
logVerboseInfo([ | ||
'Resolved options: ', | ||
`${indent}verbose: ${JSON.stringify(options.verbose)}`, | ||
`${indent}external: ${JSON.stringify(options.external)}` | ||
]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { join } from 'path'; | ||
import { URL } from 'url'; | ||
|
||
/** The root directory of the CLI tool */ | ||
export const cliRootDir = new URL('../../', import.meta.url); | ||
|
||
/** Current working directory from which the script is called */ | ||
export const packageCwd = process.cwd(); | ||
|
||
/** Path to the config file in proprietary format */ | ||
export const rollupTypeBundlerRcPath = join(packageCwd, '.rollup-type-bundlerrc'); | ||
|
||
/** Path to the config file in .json format */ | ||
export const rollupTypeBundlerRcJsonPath = join(rollupTypeBundlerRcPath, '.json'); | ||
|
||
/** Path to the config file in .yml format */ | ||
export const rollupTypeBundlerRcYmlPath = join(rollupTypeBundlerRcPath, '.yml'); | ||
|
||
/** Path to the config file in .yaml format */ | ||
export const rollupTypeBundlerRcYamlPath = join(rollupTypeBundlerRcPath, '.yaml'); | ||
|
||
/** 4 spaces indent for logging */ | ||
export const indent = ' '.repeat(4); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface Options { | ||
verbose?: boolean; | ||
external?: string[]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { cyan, red } from 'colorette'; | ||
|
||
export function logVerboseError({ text, verbose = false, verboseText = [], exitAfterLog: exitOnLog = false }: LogVerboseErrorOptions) { | ||
let combinedText = text; | ||
|
||
if (verbose) { | ||
combinedText = combinedText.concat(verboseText); | ||
} | ||
|
||
console.error(red(combinedText.join('\n'))); | ||
|
||
if (exitOnLog) { | ||
process.exit(1); | ||
} | ||
} | ||
|
||
export function logVerboseInfo(text: string[], verbose = false) { | ||
if (verbose) { | ||
console.info(cyan(text.join('\n'))); | ||
} | ||
} | ||
|
||
interface LogVerboseErrorOptions { | ||
text: string[]; | ||
verbose?: boolean; | ||
verboseText?: string[]; | ||
exitAfterLog?: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { rollupTypeBundlerRcJsonPath, rollupTypeBundlerRcPath, rollupTypeBundlerRcYamlPath, rollupTypeBundlerRcYmlPath } from '#lib/constants'; | ||
import type { Options } from '#lib/interfaces'; | ||
import { logVerboseError } from '#lib/logVerbose'; | ||
import { existsAsync } from '#lib/promisified'; | ||
import { load } from 'js-yaml'; | ||
import type { PathLike } from 'fs'; | ||
|
||
import { readFile } from 'fs/promises'; | ||
|
||
export async function parseOptionsFile(cliOptions: Options) { | ||
const rollupTypeBundlerRcExists = await existsAsync(rollupTypeBundlerRcPath); | ||
const rollupTypeBundlerRcJsonExists = await existsAsync(rollupTypeBundlerRcJsonPath); | ||
const rollupTypeBundlerRcYmlExists = await existsAsync(rollupTypeBundlerRcYmlPath); | ||
const rollupTypeBundlerRcYamlExists = await existsAsync(rollupTypeBundlerRcYamlPath); | ||
|
||
let options = cliOptions; | ||
|
||
if (rollupTypeBundlerRcYamlExists || rollupTypeBundlerRcYmlExists) { | ||
try { | ||
options = await readYaml(rollupTypeBundlerRcYamlExists ? rollupTypeBundlerRcYamlPath : rollupTypeBundlerRcYmlPath); | ||
} catch (err) { | ||
logVerboseError({ | ||
text: ['Failed to read yaml config file'], | ||
verbose: options.verbose, | ||
verboseText: [ | ||
'Attempted to read options file:', | ||
rollupTypeBundlerRcYamlExists ? rollupTypeBundlerRcYamlPath : rollupTypeBundlerRcYmlPath, | ||
'', | ||
'Full error: ', | ||
err | ||
] | ||
}); | ||
} | ||
} else if (rollupTypeBundlerRcExists || rollupTypeBundlerRcJsonExists) { | ||
try { | ||
options = await readJson(rollupTypeBundlerRcExists ? rollupTypeBundlerRcPath : rollupTypeBundlerRcJsonPath); | ||
} catch (err) { | ||
logVerboseError({ | ||
text: ['Failed to read json config file'], | ||
verbose: options.verbose, | ||
verboseText: [ | ||
'Attempted to read options file:', | ||
rollupTypeBundlerRcExists ? rollupTypeBundlerRcPath : rollupTypeBundlerRcJsonPath, | ||
'', | ||
'Full error: ', | ||
err | ||
] | ||
}); | ||
} | ||
} | ||
|
||
return options; | ||
} | ||
|
||
async function readYaml<T>(pathLike: PathLike) { | ||
return load(await readFile(pathLike, { encoding: 'utf-8' })) as unknown as T; | ||
} | ||
|
||
async function readJson<T>(pathLike: PathLike) { | ||
return JSON.parse(await readFile(pathLike, { encoding: 'utf-8' })) as T; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { exec } from 'child_process'; | ||
import type { PathLike } from 'fs'; | ||
import { lstat } from 'fs/promises'; | ||
import { promisify } from 'util'; | ||
|
||
export const execAsync = promisify(exec); | ||
export const existsAsync = (path: PathLike) => | ||
lstat(path) | ||
.then(() => true) | ||
.catch(() => false); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"extends": "../tsconfig.base.json", | ||
"compilerOptions": { | ||
"rootDir": "./", | ||
"outDir": "../dist", | ||
"composite": true, | ||
"preserveConstEnums": true, | ||
"baseUrl": ".", | ||
"paths": { | ||
"#lib/*": ["./lib/*"], | ||
"#root/*": ["*"] | ||
} | ||
}, | ||
"include": ["."] | ||
} |