Files
tools/ts_interfaces/versioning.ts

269 lines
6.8 KiB
TypeScript

/**
* @file versioning.ts
* @description Version management interfaces
* Semantic versioning, change tracking, branches, and diff comparison
*/
import type {
TVersionType,
TChangeOperation,
TBranchStatus,
} from './types.js';
// ============================================================================
// SEMANTIC VERSION
// ============================================================================
/**
* Semantic version following major.minor.patch pattern
* For contracts: major = substantial changes, minor = clause additions, patch = wording fixes
*/
export interface ISemanticVersion {
major: number;
minor: number;
patch: number;
label?: 'alpha' | 'beta' | 'rc' | 'final';
}
/**
* Version string type
*/
export type TVersionString = `${number}.${number}.${number}` | `${number}.${number}.${number}-${string}`;
// ============================================================================
// VERSION CHANGES
// ============================================================================
/**
* Represents a single atomic change within a version
*/
export interface IVersionChange {
id: string;
operation: TChangeOperation;
targetPath: string;
targetParagraphId?: string;
previousValue?: string | object;
newValue?: string | object;
characterRange?: {
start: number;
end: number;
};
timestamp: number;
userId: string;
userDisplayName?: string;
changeReason?: string;
}
// ============================================================================
// AMENDMENT
// ============================================================================
/**
* Amendment-specific information
*/
export interface IAmendmentDetails {
amendmentNumber: number;
amendmentType: 'modification' | 'addendum' | 'rider' | 'waiver' | 'extension';
effectiveDate: number;
supersedes: string[];
requiresResigning: boolean;
affectedSections: string[];
}
// ============================================================================
// VERSION
// ============================================================================
/**
* A complete version snapshot
*/
export interface IVersion {
id: string;
version: ISemanticVersion;
versionString: TVersionString;
type: TVersionType;
createdAt: number;
createdBy: string;
createdByDisplayName?: string;
previousVersionId?: string;
changes: IVersionChange[];
contentHash: string;
parentHash?: string;
title?: string;
description?: string;
tags: string[];
isAmendment: boolean;
amendmentDetails?: IAmendmentDetails;
}
// ============================================================================
// VERSION BRANCH
// ============================================================================
/**
* Branch for parallel version development
*/
export interface IVersionBranch {
id: string;
name: string;
description?: string;
createdAt: number;
createdBy: string;
baseVersionId: string;
headVersionId: string;
status: TBranchStatus;
mergedIntoVersionId?: string;
}
// ============================================================================
// VERSION HISTORY
// ============================================================================
/**
* Complete version history for a contract
*/
export interface IVersionHistory {
contractId: string;
currentVersionId: string;
currentVersion: ISemanticVersion;
versions: IVersion[];
branches: IVersionBranch[];
mainBranchId: string;
publishedVersions: string[];
amendmentVersions: string[];
}
// ============================================================================
// VERSION DIFF
// ============================================================================
/**
* Diff summary statistics
*/
export interface IDiffSummary {
insertions: number;
deletions: number;
modifications: number;
paragraphsAffected: string[];
}
/**
* Version comparison result
*/
export interface IVersionDiff {
fromVersionId: string;
toVersionId: string;
fromVersion: ISemanticVersion;
toVersion: ISemanticVersion;
changes: IVersionChange[];
summary: IDiffSummary;
}
// ============================================================================
// ROLLBACK
// ============================================================================
/**
* Rollback request
*/
export interface IRollbackRequest {
targetVersionId: string;
reason: string;
requestedBy: string;
requestedAt: number;
createNewVersion: boolean;
}
// ============================================================================
// FACTORY FUNCTIONS
// ============================================================================
/**
* Create initial version
*/
export function createInitialVersion(userId: string, userDisplayName?: string): IVersion {
const now = Date.now();
return {
id: crypto.randomUUID(),
version: { major: 0, minor: 1, patch: 0 },
versionString: '0.1.0',
type: 'draft',
createdAt: now,
createdBy: userId,
createdByDisplayName: userDisplayName,
changes: [],
contentHash: '',
tags: [],
isAmendment: false,
};
}
/**
* Create empty version history
*/
export function createEmptyVersionHistory(contractId: string, initialVersion: IVersion): IVersionHistory {
const mainBranchId = crypto.randomUUID();
return {
contractId,
currentVersionId: initialVersion.id,
currentVersion: initialVersion.version,
versions: [initialVersion],
branches: [
{
id: mainBranchId,
name: 'main',
createdAt: initialVersion.createdAt,
createdBy: initialVersion.createdBy,
baseVersionId: initialVersion.id,
headVersionId: initialVersion.id,
status: 'active',
},
],
mainBranchId,
publishedVersions: [],
amendmentVersions: [],
};
}
/**
* Increment semantic version
*/
export function incrementVersion(
current: ISemanticVersion,
incrementType: 'major' | 'minor' | 'patch'
): ISemanticVersion {
switch (incrementType) {
case 'major':
return { major: current.major + 1, minor: 0, patch: 0 };
case 'minor':
return { major: current.major, minor: current.minor + 1, patch: 0 };
case 'patch':
return { major: current.major, minor: current.minor, patch: current.patch + 1 };
}
}
/**
* Convert semantic version to string
*/
export function versionToString(version: ISemanticVersion): TVersionString {
const base = `${version.major}.${version.minor}.${version.patch}` as TVersionString;
if (version.label && version.label !== 'final') {
return `${base}-${version.label}` as TVersionString;
}
return base;
}
/**
* Parse version string to semantic version
*/
export function parseVersionString(versionString: string): ISemanticVersion {
const [base, label] = versionString.split('-');
const [major, minor, patch] = base.split('.').map(Number);
return {
major: major || 0,
minor: minor || 0,
patch: patch || 0,
label: label as ISemanticVersion['label'],
};
}