import type { Header, Options, Result, SimpleHeader } from './types.ts'; import { isValidString, stringToHeader } from './utils.ts'; /** * Parses given `header` string into an header object. * Basically the same as [.parse](#parse), except that * it only can accept single string and returns a `Header` object. * * _The `parse*` methods are not doing any checking and validation, * so you may want to pass the result to `validateHeader` or `checkHeader`, * or to `validateHeader` with `ret` option set to `true`._ * * @example * import { parseHeader } from 'parse-commit-message'; * * const longCommitMsg = `fix: bar qux * * Awesome body!`; * * const headerObj = parseCommit(longCommitMsg); * console.log(headerObj); * // => { type: 'fix', scope: null, subject: 'bar qux' } * * @name .parseHeader * @param {string} header a header stirng like `'fix(foo): bar baz'` * @param {object} options options to control the header regex and case sensitivity * @param {RegExp|string} options.headerRegex string regular expression or instance of RegExp * @param {boolean} options.caseSensitive whether or not to be case sensitive, defaults to `false` * @returns {Header} a `Header` object like `{ type, scope?, subject }` * @public */ export function parseHeader(header: string, options?: Options): Header { if (!isValidString(header)) { throw new TypeError('expect `header` to be non empty string'); } return stringToHeader(header.trim(), options); } /** * Receives a `header` object, validates it using `validateHeader`, * builds a "header" string and returns it. Method throws if problems found. * Basically the same as [.stringify](#stringify), except that * it only can accept single `Header` object. * * @example * import { stringifyHeader } from 'parse-commit-message'; * * const headerStr = stringifyCommit({ type: 'foo', subject: 'bar qux' }); * console.log(headerStr); // => 'foo: bar qux' * * @name .stringifyHeader * @param {Header|SimpleHeader} header a `Header` object like `{ type, scope?, subject }` or `{ value: string }` * @param {object} options options to control the header regex and case sensitivity * @param {RegExp|string} options.headerRegex string regular expression or instance of RegExp * @param {boolean} options.caseSensitive whether or not to be case sensitive, defaults to `false` * @returns {string} a header stirng like `'fix(foo): bar baz'` * @public */ export function stringifyHeader( header: Header | SimpleHeader, options?: Options, ): `${string}: ${string}` { const res = validateHeader(header, options) as Result
; if (res.error) { throw res.error; } // if SimpleHeader (res.value is like { value: 'chore: foobar' }) // TODO(@tunnckoCore): not sure... /* istanbul ignore next */ if (res.value && typeof res.value === 'object' && 'value' in res.value) { return res.value.value as `${string}: ${string}`; } const { type, scope, subject } = res.value as Header; return `${type}${scope ? `(${scope})` : ''}: ${subject}`.trim() as `${string}: ${string}`; } /** * Validates given `header` object and returns `boolean`. * You may want to pass `ret` to return an object instead of throwing. * Basically the same as [.validate](#validate), except that * it only can accept single `Header` object. * * @example * import { validateHeader } from 'parse-commit-message'; * * const header = { type: 'foo', subject: 'bar qux' }; * * const headerIsValid = validateHeader(header); * console.log(headerIsValid); // => true * * const { value } = validateHeader(header, true); * console.log(value); * // => { * // header: { type: 'foo', scope: null, subject: 'bar qux' }, * // body: 'okey dude', * // footer: null, * // } * * const { error } = validateHeader({ * type: 'bar' * }, true); * * console.log(error); * // => TypeError: header.subject should be non empty string * * @name .validateHeader * @param {Header|SimpleHeader} header a `Header` object like `{ type, scope?, subject }` or `{ value: string }` * @param {object} options options to control the header regex and case sensitivity * @param {RegExp|string} options.headerRegex string regular expression or instance of RegExp * @param {boolean} options.caseSensitive whether or not to be case sensitive, defaults to `false` * @returns {Result} an object like `{ value: Array, error: Error }` * @public */ export function validateHeader(header: Header | SimpleHeader, options?: Options) { const result = {} as Result
; try { result.value = checkHeader(header, options) as Header; } catch (err) { return { error: err } as Result; } return result as Result
; } /** * Receives a `Header` and checks if it is valid. * Basically the same as [.check](#check), except that * it only can accept single `Header` object. * * @example * import { checkHeader } from 'parse-commit-message'; * * try { * checkHeader({ type: 'fix' }); * } catch(err) { * console.log(err); * // => TypeError: header.subject should be non empty string * } * * // throws because can accept only Header objects * checkHeader('foo bar baz'); * checkHeader(123); * checkHeader([]); * checkHeader([{ type: 'foo', subject: 'bar' }]); * * @name .checkHeader * @param {Header|SimpleHeader} header a `Header` object like `{ type, scope?, subject }` or `{ value: string }` * @param {object} options options to control the header regex and case sensitivity * @param {RegExp|string} options.headerRegex string regular expression or instance of RegExp * @param {boolean} options.caseSensitive whether or not to be case sensitive, defaults to `false` * @returns {Header} returns the same as given if no problems, otherwise it will throw. * @public */ export function checkHeader(header: Header | SimpleHeader, options?: Options): Header { if (header && typeof header === 'object' && 'value' in header) { const { value } = header; return stringToHeader(value, options); } // else: we have Header if (!isValidString(header?.type)) { throw new TypeError('header.type should be non empty string'); } if (!isValidString(header?.subject)) { throw new TypeError('header.subject should be non empty string'); } const isValidScope = header && 'scope' in header && header.scope !== null ? isValidString(header.scope) : true; if (!isValidScope) { throw new TypeError('commit.header.scope should be non empty string when given'); } return { scope: null, ...header }; }