import { isUndefined } from '@sindresorhus/is'; import { CONFIG_VALIDATION } from '../../../constants/error-messages.ts'; import { regEx } from '../../../util/regex.ts'; import { GenericVersioningApi } from '../generic.ts'; import type { VersioningApiConstructor } from '../types.ts'; import type { RegExpVersion } from './types.ts'; export const id = 'regex'; export const displayName = 'Regular Expression'; export const urls = []; export const supportsRanges = false; export class RegExpVersioningApi extends GenericVersioningApi { // config is expected to be overridden by a user-specified RegExp value // sample values: // // * emulates the "semver" configuration: // RegExp('^(?\\d+)\\.(?\\d+)\\.(?\\d+)(-(?.*))?$') // * emulates the "docker" configuration: // RegExp('^(?\\d+)\\.(?\\d+)\\.(?\\d+)(-(?.*))?$') // * matches the versioning approach used by the Python images on DockerHub: // RegExp('^(?\\d+)\\.(?\\d+)\\.(?\\d+)(?[^.-]+)?(-(?.*))?$'); // * matches the versioning approach used by the Bitnami images on DockerHub: // RegExp('^(?\\d+)\\.(?\\d+)\\.(?\\d+)(:?-(?.*-r)(?\\d+))?$'); protected readonly _config: RegExp; constructor(_new_config: string | undefined) { super(); const new_config = _new_config ?? '^(?\\d+)?$'; // without at least one of {major, minor, patch} specified in the regex, // this versioner will not work properly if ( !new_config.includes('') && !new_config.includes('') && !new_config.includes('') ) { const error = new Error(CONFIG_VALIDATION); error.validationSource = new_config; error.validationError = 'regex versioning needs at least one major, minor or patch group defined'; throw error; } // TODO: should we validate the user has not added extra unsupported // capture groups? (#9717) this._config = regEx(new_config); } // convenience method for passing a string into a Version given current config. protected _parse(version: string): RegExpVersion | null { const groups = this._config?.exec(version)?.groups; if (!groups) { return null; } const { major, minor, patch, build, revision, prerelease, compatibility } = groups; const release = [ isUndefined(major) ? 0 : Number.parseInt(major, 10), isUndefined(minor) ? 0 : Number.parseInt(minor, 10), isUndefined(patch) ? 0 : Number.parseInt(patch, 10), ]; if (build) { release.push(Number.parseInt(build, 10)); if (revision) { release.push(Number.parseInt(revision, 10)); } } return { release, prerelease, compatibility, }; } override isCompatible(version: string, current: string): boolean { const parsedVersion = this._parse(version); const parsedCurrent = this._parse(current); return !!( parsedVersion && parsedVersion.compatibility === parsedCurrent?.compatibility ); } } export const api: VersioningApiConstructor = RegExpVersioningApi; export default api;