Skip to content

Commit

Permalink
feat: Configuration files may export arrays.
Browse files Browse the repository at this point in the history
  • Loading branch information
darkobits committed Jan 8, 2024
1 parent ce56932 commit 06319d8
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 23 deletions.
1 change: 0 additions & 1 deletion nr.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { withDefaultPackageScripts } from '@darkobits/ts';


export default withDefaultPackageScripts(({ command, script, isCI }) => {
script('test.smoke', [[
command.node('import.test.js', { cwd: './tests/fixtures/esm/' }),
Expand Down
26 changes: 16 additions & 10 deletions src/bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import { script, scripts, matchScript, printScriptInfo } from 'lib/scripts';
import { task, tasks, printTaskInfo } from 'lib/tasks';
import { parseError, heroLog } from 'lib/utils';

import type { CLIArguments, UserConfigurationFn } from 'etc/types';
import type { CLIArguments, UserConfigurationExport } from 'etc/types';


const chalk = log.chalk;


cli.command<CLIArguments, UserConfigurationFn>({
cli.command<CLIArguments, UserConfigurationExport>({
command: '* [query]',
description: 'Run the script matched by the provided query.',
config: {
Expand Down Expand Up @@ -65,7 +65,7 @@ cli.command<CLIArguments, UserConfigurationFn>({
command.epilogue(chalk.gray('For full usage instructions, see https://github.com/darkobits/nr'));
},
handler: async saffronContext => {
const { argv, config, configIsEmpty, configPath } = saffronContext;
const { argv, config: userConfigExport, configIsEmpty, configPath } = saffronContext;

try {
if (!configPath) throw new Error([
Expand All @@ -77,15 +77,21 @@ cli.command<CLIArguments, UserConfigurationFn>({
throw new Error(`Configuration file at ${chalk.green(configPath)} is empty.`);

// If the configuration file did not default-export a function, bail.
if (typeof config !== 'function') throw new TypeError(
`Expected default export of file at ${chalk.green(configPath)} to be of type "function", got "${typeof config}".`
if (typeof userConfigExport !== 'function' && !Array.isArray(userConfigExport)) throw new TypeError(
`Expected default export of file at ${chalk.green(configPath)} to be of type "function" or "Array", got "${typeof userConfigExport}".`
);

// Invoke the user's configuration function with the necessary context.
// This function should create at least 1 command, task, or script.
await config({ command, script, task, isCI });

// If the user's configuration function did not register anything, this is
// Invoke the user's configuration function(s) with the necessary context.
// The result should create at least 1 non-empty script.
if (typeof userConfigExport === 'function') {
await userConfigExport({ command, script, task, isCI });
} else if (Array.isArray(userConfigExport)) {
for await (const userConfigFn of userConfigExport) {
await userConfigFn({ command, script, task, isCI });
}
}

// If the user's configuration file did not register anything, this is
// likely an error; bail.
if (commands.size === 0 && tasks.size === 0 && scripts.size === 0) throw new Error(
`Configuration file ${chalk.green(configPath)} did not register any commands, tasks, or scripts.`
Expand Down
8 changes: 8 additions & 0 deletions src/etc/types/UserConfigurationExport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { UserConfigurationFn } from './UserConfigurationFn';

/**
* The value default-exported from a user's configuration file may be either a
* single function or an array of functions, each of which will be passed a
* context object.
*/
export type UserConfigurationExport = UserConfigurationFn | Array<UserConfigurationFn>;
1 change: 1 addition & 0 deletions src/etc/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type { CommandThunk } from './CommandThunk';

export type { UserConfigurationFn } from './UserConfigurationFn';
export type { UserConfigurationFnContext } from './UserConfigurationFnContext';
export type { UserConfigurationExport } from './UserConfigurationExport';

export type { Instruction, InstructionSet } from './Instruction';
export type { Thunk } from './Thunk';
Expand Down
11 changes: 5 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import type { UserConfigurationFn } from 'etc/types';
import type { UserConfigurationExport } from 'etc/types';


/**
* Optional helper for users who prefer to have typed configuration files.
*/
export function defineConfig(userConfigFactory: UserConfigurationFn): UserConfigurationFn {
return async context => userConfigFactory(context);
export default function defineConfig(userConfigArgument: UserConfigurationExport): UserConfigurationExport {
return Array.isArray(userConfigArgument)
? userConfigArgument.map(userConfigurationFn => async context => userConfigurationFn(context))
: async context => userConfigArgument(context);
}


export default defineConfig;


export * from 'etc/types';
4 changes: 2 additions & 2 deletions src/lib/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import type {
CommandOptions,
CommandOptionsNode,
CommandThunk,
UserConfigurationFn
UserConfigurationExport
} from 'etc/types';


Expand Down Expand Up @@ -122,7 +122,7 @@ function unParseArguments(args: CommandArguments | undefined, preserveArgumentCa
/**
* Prints all available commands.
*/
export function printCommandInfo(context: SaffronHandlerContext<CLIArguments, UserConfigurationFn>) {
export function printCommandInfo(context: SaffronHandlerContext<CLIArguments, UserConfigurationExport>) {
const allCommands = Array.from(commands.values());

if (allCommands.length === 0) {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
import type { SaffronHandlerContext } from '@darkobits/saffron';
import type {
CLIArguments,
UserConfigurationFn,
UserConfigurationExport,
ScriptOptions,
Instruction,
InstructionSet,
Expand Down Expand Up @@ -195,7 +195,7 @@ function validateInstructions(instructions: InstructionSet) {
* is in the users $PATH and can be invoked directly, or if the user needs to
* use `npx`.
*/
export function printScriptInfo(context: SaffronHandlerContext<CLIArguments, UserConfigurationFn>) {
export function printScriptInfo(context: SaffronHandlerContext<CLIArguments, UserConfigurationExport>) {
const allScripts = Array.from(scripts.values());

if (allScripts.length === 0) {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { getPackageNameFromCallsite, getPrefixedInstructionName } from 'lib/util
import type { SaffronHandlerContext } from '@darkobits/saffron';
import type {
CLIArguments,
UserConfigurationFn,
UserConfigurationExport,
TaskDescriptor,
TaskFn,
TaskOptions,
Expand All @@ -31,7 +31,7 @@ export const tasks = new Map<string, TaskDescriptor>();
/**
* Prints all available tasks.
*/
export function printTaskInfo(context: SaffronHandlerContext<CLIArguments, UserConfigurationFn>) {
export function printTaskInfo(context: SaffronHandlerContext<CLIArguments, UserConfigurationExport>) {
const allTasks = Array.from(tasks.values());

if (allTasks.length === 0) {
Expand Down

0 comments on commit 06319d8

Please sign in to comment.