@lf-lang/reactor-ts
Version:
A reactor-oriented programming framework in TypeScript
199 lines (186 loc) • 6.66 kB
text/typescript
import {TimeUnit, TimeValue, Log} from "./internal";
// ---------------------------------------------------------------------//
// Command Line Arguments Helper Functions //
// ---------------------------------------------------------------------//
/**
* Function to convert a string into a LogLevel for command line argument parsing.
* Returns null if the input is malformed.
* @param logging the raw command line argument
*/
export function loggingCLAType(logging: string): Log.LogLevel | null {
if (logging in Log.LogLevel) {
type LevelString = keyof typeof Log.LogLevel;
return Log.LogLevel[logging as LevelString];
} else {
return null;
}
}
/**
* Function to convert a string into a UnitBasedTimeValue for command line argument parsing
* Returns null if the input is malformed.
* @param logging the raw command line argument
*/
export function unitBasedTimeValueCLAType(timeout: string): TimeValue | null {
let duration: number;
let units: TimeUnit;
const wholeTimeoutPattern = /^[0-9]+\s+[a-z]+$/;
if (wholeTimeoutPattern.test(timeout)) {
const durationPattern = /^[0-9]+/;
const unitsPattern = /[a-z]+$/;
const stringDuration = durationPattern.exec(timeout);
if (stringDuration !== null) {
duration = parseInt(stringDuration[0]);
} else {
// Duration is not well formed.
return null;
}
// Test if the units are a valid TimeUnits
const stringUnits = unitsPattern.exec(timeout);
if (stringUnits !== null && stringUnits[0] in TimeUnit) {
type TimeUnitString = keyof typeof TimeUnit;
units = TimeUnit[stringUnits[0] as TimeUnitString];
} else {
// Units are not well formed.
return null;
}
return TimeValue.withUnits(duration, units);
} else {
// Duration and units are not well formed.
return null;
}
}
/**
* Function to convert a string into a boolean for command line argument parsing.
* Returns null if the input is malformed.
* Note that the command-line-arguments module's built in boolean type is
* actually a flag that is either absent or true. https://github.com/75lb/command-line-args/wiki/Notation-rules
* We need this custom boolean parsing because our command line arguments
* are true, false, or absent.
* @param logging the raw command line argument
*/
export function booleanCLAType(bool: string): boolean | null {
if (bool === "true") {
return true;
} else if (bool === "false") {
return false;
} else {
return null;
}
}
/**
* Function to return an argument string as is.
*/
export function stringCLAType(arg: string): string {
return arg;
}
// ---------------------------------------------------------------------//
// Exported CLI support //
// ---------------------------------------------------------------------//
/**
* The type returned by the commandLineArguments function. This type must change
* if the CommandLineOptionDefs changes.
*/
export interface ProcessedCommandLineArgs {
fast: boolean | undefined;
keepalive: boolean | undefined;
advanceMessageInterval: TimeValue | undefined;
timeout: TimeValue | null | undefined;
logging: Log.LogLevel | undefined;
id: string | undefined;
help: boolean;
}
export type CommandLineOptionSpec = Array<{
name: string;
alias?: string;
type: (arg0: string) => unknown;
typeLabel?: string;
description: string;
}>;
/**
* Configuration for command line arguments.
* If this configuration changes, the ProcessedCommandLineArgs type must
* change too.
*/
export const CommandLineOptionDefs: CommandLineOptionSpec = [
{
name: "keepalive",
alias: "k",
type: booleanCLAType,
typeLabel: "{underline [true | false]}",
description:
"Specifies whether to stop execution if there are no events to process. " +
"This defaults to false, meaning that the program will stop executing when " +
"there are no more events on the event queue. If you set this to true, then " +
"the program will keep executing until either the timeout logical time is " +
"reached or the program is externally killed. If you have physical actions, " +
"it usually makes sense to set this to true."
},
{
name: "fast",
alias: "f",
type: booleanCLAType,
typeLabel: "{underline [true | false]}",
description:
"Specifies whether to wait for physical time to match logical time. " +
"The default is false. If this is true, then the program will execute as fast " +
"as possible, letting logical time advance faster than physical time."
},
{
name: "logging",
alias: "l",
type: loggingCLAType,
typeLabel: "{underline [ERROR | WARN | INFO | LOG | DEBUG]}",
description:
"The level of diagnostic messages about execution to print to the " +
"console. A message will print if this parameter is greater than or equal to " +
"the level of the message (ERROR < WARN < INFO < LOG < DEBUG)."
},
{
name: "timeout",
alias: "o",
type: unitBasedTimeValueCLAType,
typeLabel: "{underline '<duration> <units>'}",
description:
"Stop execution when logical time has advanced by the specified <duration>. " +
"The units can be any of nsec, usec, msec, sec, minute, hour, day, week, or the plurals " +
"of those. For the duration and units of a timeout argument to be parsed correctly as a " +
"single value, these should be specified in quotes with no leading or trailing space " +
"'(eg '5 sec')."
},
{
name: "id",
alias: "i",
type: stringCLAType,
typeLabel: "{underline '<string>'}",
description: "The ID of the federation that this reactor will join."
},
{
name: "help",
alias: "h",
type: Boolean,
description:
"Print this usage guide. The program will not execute if this flag is present."
}
];
/**
* Configuration for command line argument usage information.
* Note: The order of the elements in the list is important.
*/
export const CommandLineUsageDefs: Array<{
header: string;
content?: string;
optionList?: CommandLineOptionSpec;
}> = [
{
header: "Command Line Usage for TypeScript Reactors",
content:
"This generated program understands the following command-line arguments, " +
"each of which has a short form (one character) and a long form. " +
"If provided, a command line argument will override whatever value " +
"the corresponding target property had specified in the source .lf file."
},
{
header: "Options",
optionList: CommandLineOptionDefs
}
];