APIs
@haetae/core

@haetae/core

@haetae/core provides every core feature for Haetae.
For instance, it handles config file, store file, and your command's env and run.
If you want to use Haetae by programmatic API, you probably need this package.

Dependents

Installation

Unlike other @haetae/* packages, @haetae/core doesn't have peerDependencies. Just purely installing @haetae/core itself is enough.

💡

Are you developing a library(e.g. plugin) for Haetae?
It might be more suitable to specify @haetae/core as peerDependencies than dependencies.


# As dependencies
npm install @haetae/core
# As devDependencies
npm install --save-dev @haetae/core

API

pkg

Refer to introduction#pkg.

SetCurrentCommandOptions

An argument interface of the function setCurrentCommand.

interface SetCurrentCommandOptions {
  command: string
}

setCurrentCommand

A setter for the current command name, which is a module-level state.
Set it before calling other APIs that require it (as a default parameter).

Type

(options: SetCurrentCommandOptions) => void

Options?

  • command : A name of command to run for current execution.

getCurrentCommand

A getter for the current command name, which is a module-level state.

Type

() => string

defaultConfigFiles

An array of string constants for default config file name.
This is used when the config file path is not given or given as a directory.

Type

[
  'haetae.config.js',
  'haetae.config.mjs',
  'haetae.config.ts',
  'haetae.config.mts',
]

SetConfigFilenameOptions

An argument interface of the function setConfigFilename.

interface SetConfigFilenameOptions {
  filename?: string
  cwd?: string
  checkExistence?: boolean
}

setConfigFilename

A setter for the config file name, which is a module-level state.
Set it before calling other APIs that require a config file.

Type

(options?: SetConfigFilenameOptions) => void

Options?

  • filename? : A config file path.
  • cwd? : A directory to join or start the search from. (default: process.cwd() (opens in a new tab))
  • checkExistence?: Whether to check if filename exists. No effect when filename is not given. (default: true)

When filename is given

filename can be either an absolute or relative path. If relative, filename will be joined with cwd.
If filename does not exist on the filesystem, it throws an error when checkExistence is true.

When filename is not given

It will try finding the config file (one of defaultConfigFiles) by walking up parent directories recursively, starting from cwd.

  • If not found, it throws an error.
  • If multiple files (of defaultConfigFiles) exist,
    • A file closer to cwd is chosen.
    • If distances from cwd are equal, the priority order is the same as defaultConfigFiles.

getConfigFilename


Path Principles

A getter for the config file name, which is a module-level state.

Type

() => string

getConfigDirname


Path Principles

A getter for the config file's directory name, which is a derived module-level state.
Throws an error if the config file is not yet set.

Type

() => string

defaultStoreFile

A string constant for default store file name.
This is used when store file is not given, or given as a directory.

Type

'.haetae/store.json'

SetStoreFilenameOptions

An argument interface of the function setStoreFilename.

interface SetStoreFilenameOptions {
  filename: string
  rootDir?: string
}

setStoreFilename

A setter for the name of the store file, which is a module-level state.
Set the store filename by this setter function, before calling other APIs that require store filename.

💡

Priority against config
Calling this function overrides the config file's storeFile option.
But it does not change the content of the config file (e.g. haetae.config.js) or modify the memoized (by getConfig) config object in memory.

Type

(options: SetStoreFilenameOptions) => void

Options

  • filename : A store file path. If it does not end with '.json', 'store.json' is appended internally. (e.g. '/path/to' becomes '/path/to/store.json')
  • rootDir? : A directory to join with filename when filename is a relative path. (default: getConfigDirname())

getStoreFilename

A getter for the name of the store file, which is a module-level state.

Type

() => string

HaetaeRecord

interface HaetaeRecord<D extends Rec = Rec, E extends Rec = Rec>  {
  data: D
  env: E
  time: number
}

HaetaeStore

interface HaetaeStore<D extends Rec = Rec, E extends Rec = Rec> {
  version: string
  commands: {
    [command: string]: HaetaeRecord<D, E>[]
  }
}

HaetaeCommandEnv

<E extends Rec>() => void | PromiseOr<E>

HaetaePreCommandEnv

type HaetaePreCommandEnv<E extends Rec> =
  | HaetaeCommandEnv<E>
  | PromiseOr<E | void>

HaetaeCommandRun

<D extends Rec>() => void | PromiseOr<D | void>

HaetaePreCommand

interface HaetaePreCommand<D extends Rec, E extends Rec> {
  run: HaetaeCommandRun<D>
  env?: HaetaePreCommandEnv<E>
}

HaetaeCommand

interface HaetaeCommand<D extends Rec, E extends Rec> {
  run: HaetaeCommandRun<D>
  env: HaetaeCommandEnv<E>
}

RootEnv

<E extends Rec>(envFromCommand: E) => PromiseOr<E>

RootRecordData

<A extends Rec, R extends Rec = A>(recordDataFromCommand: A) => PromiseOr<R>

HaetaePreConfig

An interface of user-given config schema.
Also an argument interface of the function configure.

export interface HaetaePreConfig {
  commands: {
    [command: string]: HaetaePreCommand<Rec, Rec>
  }
  env?: RootEnv<Rec>
  recordData?: RootRecordData<Rec>
  recordRemoval?: {
    age?: string | number
    count?: number
  }
  storeFile?: string
}

HaetaeConfig

An interface of normalized config schema.
Also a return type of function configure.

interface HaetaeConfig<D extends Rec, E extends Rec> {
  commands: {
    [command: string]: HaetaeCommand<D, E>
  }
  env: RootEnv<E>
  recordData: RootRecordData<D>
  recordRemoval: {
    age: number
    count: number
  }
  storeFile: string
}

configure


Path Principles

configure validates and transform the user-provided config(e.g. haetae.config.js) into normalized config.

💡

Idempotent function
configure(obj) is eqaul to configure(configure(obj)).
(The only exception is when setStoreFilename is called with different arguments between each call of configure, which is unlikely to happen in real-world scenario.)

Type

<D extends Rec, E extends Rec>(options: HaetaePreConfig) => HaetaeConfig<D, E>

Options

  • commands : Your commands as an object.
  • env? : An env-to-env transformer. (default: (arg) => arg)
  • recordData? : A recordData-to-recordData transformer. (default: (arg) => arg)
  • recordRemoval.age? : Age threshold by milliseconds. Records whose age are older than this value are to be removed when calling addRecord. (default: Number.POSITIVE_INFINITY)
  • recordRemoval.count? : The number of total records to keep. When the number of records becomes larger than this value, old records are removed to satisfy the threshold when calling addRecord. This task is executed after that of recordRemoval.age. (default: Number.POSITIVE_INFINITY)
  • storeFile? : A store file path. Internally, it is used to setStoreFilename({ filename: storeFile }) only if setStoreFilename is never called before. If setStoreFilename is called before calling configure, the option storeFile does not have any effect, even to the result HaetaeConfig object. (default: defaultStoreFile)

Type-check for your config

The below example is 100% valid.
The exported raw json will be processed by configure internally.
But you'd not get a type-check from the IDE.

haetae.config.js
export default { /* ... */ }

With configure, type-check is enabled. Your IDE is Happy! 😊

haetae.config.js
import { core } from 'haetae'
 
export default core.configure({ /* ... */ })

Normalization

Schema of HaetaeConfig (return type) is roughly similar to that of HaetaePreConfig (argument type). The return value is a normalized result of a user-given (argument) config. Omitted options from a user-given config(HaetaePreConfig) are to be set as their default values in HaetaeConfig. The given value of storeFile is replaced by a return value of getStoreFilename().

GetConfigOptions

An argument interface of the function getConfig.

interface GetConfigOptions {
  filename?: string
}

getConfig


Memoized

A function to get config object by config file path.

Type

<D extends Rec, E extends Rec>(options?: GetConfigOptions)
  => Promise<HaetaeConfig<D, E>>

Options?

initNewStore

Initializes an empty store. It just returns an object. It does not save it as a file.

Type

<D extends Rec, E extends Rec>() => HaetaeStore<D, E>

GetStoreOptions

An argument interface of the function getStore.

interface GetStoreOptions {
  filename?: string
  initWhenNotFound?: boolean
}

getStore


Memoized

Type

<D extends Rec, E extends Rec>(options?: GetStoreOptions<D, E>)
  => Promise<HaetaeStore<D, E>>

A function to get store object.

Options?

  • filename? : A path to store file (e.g. '/path/to/.haetae/store.json'). (default: getStoreFilename())
  • initWhenNotFound? : Whether to throw an error or just initialize new store object when filename does not exist in filesystem. If true, initNewStore() is returned, and filesystem is not affected. (default: true)

GetRecordsOptions

An argument interface of the function getRecords.

💡

There're GetRecordsOptions (plural) and GetRecordOptions (singular). Don't confuse!

interface GetRecordsOptions<D extends Rec, E extends Rec> {
  command?: string
  store?: HaetaeStore<D, E>
}

getRecords

A function to get records of the given command from the given store.
undefined is returned when there is no record.

💡

There're getRecords (plural) and getRecord (singular). Don't confuse!

Type

<D extends Rec = Rec, E extends Rec = Rec>(options?: GetRecordsOptions<D, E>)
  => Promise<HaetaeRecord<D, E>[] | undefined>

Options?

ReserveRecordDataOptions

An option interface of the function reserveRecordData.

interface ReserveRecordDataOptions {
  dryRun?: boolean
}

reserveRecordData

A function to reserve Record Data.
This changes module-level state, the Reserved Record Data.
It returns a result of the Reserved Record Data.

Type

<D extends Rec>(recordData: Rec, options?: ReserveRecordDataOptions) => D

Options?

  • dryRun? : If true, the arg recordData is not reserved, but a return value is given as if it's applied. (default: false)

InvokeEnvOptions

An argument interface of the function invokeEnv.

interface InvokeEnvOptions<E extends Rec> {
  command?: string
  config?: HaetaeConfig<Rec, E>
  applyRootEnv?: boolean
}

invokeEnv


Memoized

A function to invoke(execute) user-defined env of the given command.

Type

<E extends Rec>(options?: CommandFromConfig<Rec, E>) => Promise<E>

Options?

  • command? : A command name to invoke env of. (default: getCurrentCommand())
  • config? : A config object. (default: getConfig())
  • applyRootEnv? : Whether to apply root env. (default: true)

InvokeRunOptions

An argument interface of the function invokeRun.

interface InvokeRunOptions<D extends Rec> {
  command?: string
  config?: HaetaeConfig<D, Rec>
  applyReservedRecordData?: boolean
  applyRootRecordData?: boolean
}

invokeRun

A function to invoke (execute) user-defined run of the given command.

Type

<D extends Rec>(options?: CommandFromConfig<D, Rec>) => Promise<D>

Options?

  • command? : A command name to invoke env of. (default: getCurrentCommand())
  • config? : A config object. (default: getConfig())
  • applyReservedRecordData? : Whether to apply reserved Record Data. (default: true)
  • applyRootRecordData? : Whether to apply root Record Data. (default: true)

compareEnvs

A function to compare two resolved env object.
Returns true if they're equal, false otherwise.

Type

(one: Rec, theOther: Rec) => boolean

Arguments

  • one : A resolved env object to compare with theOther.
  • theOther : A resolved env object to compare with one.

GetRecordOptions

An argument interface of a function getRecord.

💡

There're GetRecordsOptions (plural) and GetRecordOptions (singular). Don't confuse!

interface GetRecordOptions<D extends Rec, E extends Rec>
  extends GetRecordsOptions<D, E> {
  env?: PromiseOr<E>
}

getRecord

A function to get a record of a given command from given store, corresponding to the given env.
undefined is returned when there is no record.

💡

There're getRecords (plural) and getRecord (singular). Don't confuse!

Type

<D extends Rec = Rec, E extends Rec = Rec>(options?: GetRecordOptions<D, E>)
  => Promise<HaetaeRecord<D, E> | undefined>

Options?

FormRecordOptions

An argument interface of the function formRecord.

interface FormRecordOptions<D extends Rec, E extends Rec> {
  data?: D
  env?: E
  time?: number
}

formRecord

A function to create a new record object.
This only returns an object, not save it.

Type

<D extends Rec, E extends Rec>(options?: FormRecordOptions<D, E>)
  => Promise<HaetaeRecord<D, E>>

Options?

AddRecordOptions

An argument interface of the function addRecord.

interface AddRecordOptions<D extends Rec, E extends Rec> {
  config?: HaetaeConfig<D, E>
  command?: string
  store?: HaetaeStore<D, E>
  record?: HaetaeRecord<D, E>
}

addRecord

A function to add a new record under the given command to store.

Type

<D extends Rec, E extends Rec>(options?: AddRecordOptions<D, E>)
  => Promise<HaetaeStore<D, E>>

Options?

  • config? : A config object. (default: getConfig())
    • config.recordRemoval.age: Age threshold by milliseconds. Records whose age are older than this value are removed.
    • config.recordRemoval.count: The number of total records to keep. When the number of records becomes larger than this value, old records are removed to satisfy the threshold. This task is executed after that of config.recordRemoval.age.
  • command? : A command name to add record under. (default: getCurrentCommand())
  • store? : A store object. (default: getStore())
  • record? : A new record object to add. (default: formRecord({ data: invokeRun({ command }), env: invokeEnv({ command }) }))

SaveStoreOptions

An argument interface of the function saveStore.

interface SaveStoreOptions {
  filename?: string
  store?: HaetaeStore
}

saveStore

A function to save a store object to a file.
Memoization cache of getStore would be clear automatically.
File IO and Memoization cache clear is done sequentially in a synchronous manner, as a transaction.

Type

(options?: SaveStoreOptions) => Promise<void>

Options?

DeleteStoreOptions

An argument interface of the function deleteStore.

interface DeleteStoreOptions {
  filename?: string
}

deleteStore

A function to delete the entire store by removing the store file.
Memoization cache of getStore would be clear automatically.
File IO and Memoization cache clear is done sequentially in a synchronous manner, as a transaction.

Type

(options?: DeleteStoreOptions) => Promise<void>

Options?