A private collection of utilities for developing tools to help maintain (AngularJS-related) GitHub repositories.

Downloads in past


110.1.3a year ago6 years agoMinified + gzip package size for @gkalpak/ng-maintain-utils in KB



A private collection of utilities for developing tools to help maintain (AngularJS-related) GitHub repositories.


You should generally not use it. You would use tools built on top of it, for example:

I may use it for building other tools (see above). Here is a brief overview of what's in the box:
  • AbstractCli: Can serve as a base-class for creating a Cli object that can orchestrate the
execution of some type of work, based on a list of "raw" command-line arguments. It can display version info (with --version), show usage instructions (with --usage), outline the commands that need to be executed to complete the task at hand (with --instructions) - a sort of "dry-run", report the beginning/end of execution, etc.
It exposes the following (public) methods:
- getPhases(): Phase[] (abstract): This method must be overwritten and return an array of Phase
objects (to be used for displaying instructions in the "dry-run" mode).
- run(rawArgs: string[], doWork?: ({[key: string]: string}) => any): Promise: Parse the arguments
and take appropriate action (see above).
It also provides a number of "protected" methods, that can be overwritten by sub-classes:
- _displayExperimentalTool(): void - _displayHeader(headerTmpl: string, input: {[key: string]: string}): void - _displayInstructions(phases: Phase[], input: {[key: string]: string}): void - _displayUsage(usageMessage: string): void - _displayVersionInfo(): void - _getAndValidateInput(rawArgs: string[], argSpecs: ArgSpec[]): Promise<{[key: string]: string}> - _insertEmptyLine<T>(value: T, isRejection?: boolean): T|Promise<T> - _theHappyEnd<T>(value: T): T - _theUnhappyEnd(err: any): Promise<any>
- _config_: `Config`
  • ArgSpec/ArgSpec.Unnamed: Represents the specification for a command-line argument. When
applied on a parsed arguments object (such as the ones returned by Utils#parseArgs()) it will extract the corresponding argument's value (either by name (ArgSpec) or by position (ArgSpec.Unnamed)), fall back to a default value if necessary, vaidate the value and assign it to the specified input object under the appropriate key.
- _index_: `number` (`ArgSpec.Unnamed` only)
- _key_: `string`
- _validator_: `(value: any) => boolean`
- _errorCode_: `string`
- _defaultValue?_: `string|boolean`
  • CleanUper: A utility to help coordinate arbitrary tasks with their associated clean-up
The general idea is this: 1. Schedule a task to clean up after something. 2. Do something. 3. ...possibly do other things here... 4. If anything goes wrong, the app will be able to clean up (or show instructions to the user). 5. When cleaning up after something is no longer necessary, unschedule the clean-up task.
Provides the following methods: - cleanUp(listOnly: boolean): Promise: Perform all clean-up tasks (or just list them).
<sub>(Either way, the clean-up task queue is emptied.)</sub>
- getCleanUpPhase(): Phase: Returns a clean-up Phase object (suitable for UiUtils#phase()). - hasTasks(): boolean: Returns whether or not there are any clean-up tasks scheduled. - registerTask(description: string, cb: () => Promise): TaskId: Register a task with the
`CleanUper`. You can use the returned, unique `TaskId` for scheduling/unscheduling the task.
- schedule(taskId: TaskId): void: Schedule a clean-up task. - unschedule(taskId: TaskId): void: Schedule (the last instance of) a clean-up task. - withTask(taskId: TaskId, fn: () => any): Promise: Schedule taskId and execute fn (can also
return a promise). If all goes well, unschedule `taskId`. If an error occurs, leave `taskId`
in the clean-up task queue.
- _logger_: `Logger`
  • Config: Creates a Config object based on the specified messages and argSpecs (falling
back to some default values if necessary). It exposes the following properties:
- argSpecs: A (possibly empty) array of ArgSpec objects. - defaults: A {[argument: string]: string|number} map of default values per command-line
argument keys. <sub>(Automatically extracted for `argSpecs`.)</sub>
- messages: A (possibly nested) {[messageKey: string]: string} map with at least the following
- `usage`
- `instructionsHeaderTmpl`
- `headerTmpl`
- `errors`:
  - `ERROR_unexpected`
- `warnings`:
  - `WARN_experimentalTool`
- versionInfo: A {name: string, version: string} map with values retrieved from the main
module's `package.json` (i.e. the first `package.json` to be found starting from the main file's
directory and moving upwards).
- _messages_: `{[messageKey: string]: string}`
- _argSpecs_: `ArgSpec[]`
  • GitUtils: A collection of Git-related command-wrappers and utilities. Mainly spawns Git
commands in a separate process and (promises to) return the output. Support for commands is added in an "as-needed" basis. Currently, the available commands/utilities include:
- abortAm(): Promise - abortRebase(): Promise - checkout(branch: string): Promise - clean(mode?: string = 'interactive'): Promise - countCommitsSince(commit: string): Promise<number> - createBranch(branch: string): Promise - deleteBranch(branch: string, force?: boolean): Promise - diff(commit: string, noColor?: boolean): Promise - diffWithHighlight(commit: string): Promise - diffWithHighlight2(commit: string): Promise - getCommitMessage(commit: string): Promise<string> - getLastCommitMessage(): Promise<string> - log(oneline?: boolean, count?: number, noDecorate?: boolean): Promise - mergePullRequest(prUrl: string): Promise - pull(branch: string, rebase?: boolean): Promise - push(branch: string): Promise - rebase(commit: string|number, interactive?: boolean): Promise - reset(commit: string, hard?: boolean): Promise - setLastCommitMessage(message: string): Promise - updateLastCommitMessage(getNewMessage: (oldMessage: string) => string): Promise
- _cleanUper_: `CleanUper`
- _utils_: `Utils`
  • GitUtils.DiffHighlighter: Can be used to enhance a diff by highlighting areas of interest.
The general implementation is loosely based on the idea of diff-highlightdiff-highlight, although the matching heuristics and coloring (among other things) are different.
It exposes the underlying streams via:
- getInputStream(): stream.PassThrough - getOutputStream(): stream.PassThrough
Requires: - styles?:
  lineRemoved?: (text: string) => string,
  lineAdded?: (text: string) => string,
  areaRemoved?: (text: string) => string,
  areaAdded?: (text: string) => string
  • GitUtils.DiffHighlighter2: An alternative, API-compatible implementation of
GitUtils.DiffHighlighter. The highlighting is more accurate, as it is able to only highlight the regions that have changed. The main drawback is that it fails to show removed/added empty lines, because of its dependency on Gits --word-diff=plain option.
Similar to GitUtils.DiffHighlighter, it exposes the underlying streams via:
- getInputStream(): stream.PassThrough - getOutputStream(): stream.PassThrough
Requires: - styles?:
  lineRemoved?: (text: string) => string,
  lineAdded?: (text: string) => string,
  areaRemoved?: (text: string) => string,
  areaAdded?: (text: string) => string
  • Logger: A simple helper providing minimal logging utilities. This is mostly used in order to
make it easier to test logging behavior without affecting console methods. Provides the following methods:
- debug(): Delegate to console.debug(). - error(): Delegate to console.error(). - info(): Delegate to console.info(). - log(): Delegate to console.log(). - warn(): Delegate to console.warn().
  • Phase: A simple wrapper for "phase" entities (with validation). A "phase" is a description
of a unit of work, including an ID, a short description, a list of the tasks involved and an error message (or code) specific to this "phase".
- _id_: `string`
- _description_: `string`
- _instructions?_: `string[]`
- _error?_: `string` <sub>(Can be either an error message or an error code.)</sub>
  • UiUtils: A collection of utilities useful for interacting with the user, including:

- askQuestion(): Prompt the user with a question and (promise to) return the answer. - askYesOrNoQuestion(): Prompt the user with a yes-or-no question (e.g. a confirmation) and
(promise to) resolve (for "yes") or reject (for "no").
- offerToCleanUp(): Requests confirmation to perform the scheduled clean-up tasks. If the user
turns the offer down, it will just list the pending tasks instead.
- phase(): It will report the beginning and end of a "phase" (see Phase), do some work and
properly handle possible errors (by means of `reportAndRejectFnGen()`).
- reportAndRejectFnGen(): Generates a callback that will report the specified error (plus any
extra error provided during invokation), will offer to clean up (if there are pending tasks and
not configured otherwise) and return a rejection.
- _logger_: `Logger`
- _cleanUper_: `CleanUper`
- _errorMessages_: `{[errorCode: string]: string}`
  • Utils: A collection of low-level, specific-purpose utilities, including:

- asPromised(): Convert callback-based functions to promise-based. - interpolate(): Replace {{...}} placeholders in a string with values. - parseArgs(): Parse command-line arguments (and remove surrounding quotes). - resetOutputStyleOnExit(): Ensure the output style is reset when a process exists. - spawnAsPromised(): Spawn a sub-shell to run a (series of) command(s) with support for piping. - waitAsPromised(): setTimeout() wrapped in a promise.


The following test-types/modes are available:
  • Code-linting: npm run lint
Lint JavaScript files using ESLint.
  • Unit tests: npm run test-unit
Run all the unit tests once. These tests are quick and suitable to be run on every change.
  • E2E tests: npm run test-e2e
Run all the end-to-end tests once. These test may hit actual API endpoints or perform expensive I/O operations and are considerably slower than unit tests.
  • All tests: npm test / npm run test
Run all of the above tests (code-linting, unit tests, e2e tests). This command is automatically run before npm version and npm publish.
  • "Watch" mode: npm run test-watch
Watch all files and rerun the unit tests whenever something changes. For performance reasons, code-linting and e2e tests are omitted.