111 lines · 3.8 KB · TypeScript
RawDownload
import * as Cause from "effect/Cause";import * as DateTime from "effect/DateTime";import * as Exit from "effect/Exit";import * as Option from "effect/Option";import * as Result from "effect/Result";import * as Schema from "effect/Schema";import { PositiveInt, TrimmedNonEmptyString } from "@t3tools/contracts";import { decodeJsonResult, formatSchemaError } from "@t3tools/shared/schemaJson"; export interface NormalizedAzureDevOpsPullRequestRecord {  readonly number: number;  readonly title: string;  readonly url: string;  readonly baseRefName: string;  readonly headRefName: string;  readonly state: "open" | "closed" | "merged";  readonly updatedAt: Option.Option<DateTime.Utc>;} const AzureDevOpsPullRequestSchema = Schema.Struct({  pullRequestId: PositiveInt,  title: TrimmedNonEmptyString,  url: Schema.optional(Schema.String),  sourceRefName: TrimmedNonEmptyString,  targetRefName: TrimmedNonEmptyString,  status: Schema.String,  creationDate: Schema.optional(Schema.OptionFromNullOr(Schema.DateTimeUtcFromString)),  closedDate: Schema.optional(Schema.OptionFromNullOr(Schema.DateTimeUtcFromString)),  _links: Schema.optional(    Schema.Struct({      web: Schema.optional(        Schema.Struct({          href: Schema.String,        }),      ),    }),  ),}); function trimOptionalString(value: string | null | undefined): string | null {  const trimmed = value?.trim() ?? "";  return trimmed.length > 0 ? trimmed : null;} function normalizeRefName(refName: string): string {  return refName.trim().replace(/^refs\/heads\//, "");} function normalizeAzureDevOpsPullRequestState(status: string): "open" | "closed" | "merged" {  switch (status.trim().toLowerCase()) {    case "completed":      return "merged";    case "abandoned":      return "closed";    default:      return "open";  }} function normalizeAzureDevOpsPullRequestRecord(  raw: Schema.Schema.Type<typeof AzureDevOpsPullRequestSchema>,): NormalizedAzureDevOpsPullRequestRecord {  return {    number: raw.pullRequestId,    title: raw.title,    url: trimOptionalString(raw._links?.web?.href) ?? trimOptionalString(raw.url) ?? "",    baseRefName: normalizeRefName(raw.targetRefName),    headRefName: normalizeRefName(raw.sourceRefName),    state: normalizeAzureDevOpsPullRequestState(raw.status),    updatedAt: (raw.closedDate ?? Option.none()).pipe(      Option.orElse(() => raw.creationDate ?? Option.none()),    ),  };} const decodeAzureDevOpsPullRequestList = decodeJsonResult(Schema.Array(Schema.Unknown));const decodeAzureDevOpsPullRequest = decodeJsonResult(AzureDevOpsPullRequestSchema);const decodeAzureDevOpsPullRequestEntry = Schema.decodeUnknownExit(AzureDevOpsPullRequestSchema); export const formatAzureDevOpsJsonDecodeError = formatSchemaError; export function decodeAzureDevOpsPullRequestListJson(  raw: string,): Result.Result<  ReadonlyArray<NormalizedAzureDevOpsPullRequestRecord>,  Cause.Cause<Schema.SchemaError>> {  const result = decodeAzureDevOpsPullRequestList(raw);  if (Result.isSuccess(result)) {    const pullRequests: NormalizedAzureDevOpsPullRequestRecord[] = [];    for (const entry of result.success) {      const decodedEntry = decodeAzureDevOpsPullRequestEntry(entry);      if (Exit.isFailure(decodedEntry)) {        continue;      }      pullRequests.push(normalizeAzureDevOpsPullRequestRecord(decodedEntry.value));    }    return Result.succeed(pullRequests);  }  return Result.fail(result.failure);} export function decodeAzureDevOpsPullRequestJson(  raw: string,): Result.Result<NormalizedAzureDevOpsPullRequestRecord, Cause.Cause<Schema.SchemaError>> {  const result = decodeAzureDevOpsPullRequest(raw);  if (Result.isSuccess(result)) {    return Result.succeed(normalizeAzureDevOpsPullRequestRecord(result.success));  }  return Result.fail(result.failure);}