• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nikelborm / fetch-github-folder / 14926633763

09 May 2025 10:11AM UTC coverage: 85.29% (-0.05%) from 85.344%
14926633763

push

github

nikelborm
quick save: Fri May  9 13:11:20 MSK 2025

77 of 84 branches covered (91.67%)

Branch coverage included in aggregate %.

584 of 691 relevant lines covered (84.52%)

4.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.76
/src/getPathContents/parseGitLFSObjectEither.ts
1
import { type Either, gen, isRight, left, mapLeft } from 'effect/Either';
1✔
2
import { ParseError } from 'effect/ParseResult';
1✔
3
import {
1✔
4
  decodeUnknownEither,
5
  NonEmptyTrimmedString,
6
  NumberFromString,
7
  Struct,
8
} from 'effect/Schema';
9
import { outdent } from 'outdent';
1✔
10
import {
1✔
11
  type TaggedErrorClass,
12
  buildTaggedErrorClassVerifyingCause,
13
} from '../TaggedErrorVerifyingCause.ts';
14

15
export const parseGitLFSObjectEither = ({
1✔
16
  contentAsBuffer,
4✔
17
  expectedContentSize,
4✔
18
}: {
4✔
19
  contentAsBuffer: Buffer<ArrayBuffer>;
20
  expectedContentSize: number;
21
}) =>
22
  gen(function* () {
4✔
23
    // gitLFS info usually is no longer than MAX_GIT_LFS_INFO_SIZE bytes
24
    const contentAsString = contentAsBuffer
4✔
25
      .subarray(0, MAX_GIT_LFS_INFO_SIZE)
4✔
26
      .toString('utf8');
4✔
27

28
    const parsingResult = mapLeft(
4✔
29
      decodeGitLFSInfoSchema(contentAsString.match(gitLFSInfoRegexp)?.groups),
4✔
30
      cause =>
4✔
31
        new FailedToParseGitLFSInfoError(cause, {
3✔
32
          partOfContentThatCouldBeGitLFSInfo: contentAsString,
3✔
33
        }),
3✔
34
    );
4✔
35

36
    const matchedByRegexpAndParsedByEffectSchema = isRight(parsingResult);
4✔
37
    const doesSizeFromGitLFSInfoAlignWithExpectedContentSize =
4✔
38
      isRight(parsingResult) &&
4✔
39
      parsingResult.right.size === expectedContentSize;
1✔
40

41
    const shouldFailIfItIsNotGitLFS =
4✔
42
      contentAsBuffer.byteLength !== expectedContentSize;
4✔
43

44
    const isThisAGitLFSObject =
4✔
45
      matchedByRegexpAndParsedByEffectSchema &&
4✔
46
      doesSizeFromGitLFSInfoAlignWithExpectedContentSize;
1✔
47

48
    if (isThisAGitLFSObject)
4✔
49
      return {
4✔
50
        gitLFSObjectIdSha256: parsingResult.right.oidSha256,
1✔
51
        gitLFSVersion: parsingResult.right.version,
1✔
52
      } as const;
1✔
53

54
    if (shouldFailIfItIsNotGitLFS)
3✔
55
      return yield* left(
4!
56
        new InconsistentExpectedAndRealContentSizeError({
×
57
          actual: contentAsBuffer.byteLength,
×
58
          expected: expectedContentSize,
×
59
          gitLFSInfo: parsingResult,
×
60
        }),
×
61
      );
✔
62

63
    return 'This is not a git LFS object' as const;
3✔
64
  });
3✔
65

66
// there are some responses that look like
67
// `version https://git-lfs.github.com/spec/v1
68
// oid sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
69
// size 128
70
// `
71
// and the only variable thing in it is the size at the end, and I assume
72
// that supported file size is not greater than 100 GB
73
const MAX_GIT_LFS_INFO_SIZE = 137;
1✔
74
// Don't add regexp /g modifier, it breaks match groups
75
const gitLFSInfoRegexp =
1✔
76
  /^version (?<version>https:\/\/git-lfs\.github\.com\/spec\/v1)\noid sha256:(?<oidSha256>[0-9a-f]{64})\nsize (?<size>[1-9]\d{0,11})\n$/m;
1✔
77

78
const GitLFSInfoSchema = Struct({
1✔
79
  version: NonEmptyTrimmedString,
1✔
80
  oidSha256: NonEmptyTrimmedString,
1✔
81
  size: NumberFromString,
1✔
82
});
1✔
83

84
const decodeGitLFSInfoSchema = decodeUnknownEither(GitLFSInfoSchema, {
1✔
85
  exact: true,
1✔
86
});
1✔
87

88
// Extracting to a separate type is required by JSR, so that consumers of the
89
// library will have much faster type inference
90
export type FailedToParseGitLFSInfoErrorClass = TaggedErrorClass<{
91
  ErrorName: 'FailedToParseGitLFSInfoError';
92
  ExpectedCauseClass: typeof ParseError;
93
  DynamicContext: { partOfContentThatCouldBeGitLFSInfo: string };
94
}>;
95

96
const _1: FailedToParseGitLFSInfoErrorClass =
1✔
97
  buildTaggedErrorClassVerifyingCause<{
1✔
98
    partOfContentThatCouldBeGitLFSInfo: string;
99
  }>()(
1✔
100
    'FailedToParseGitLFSInfoError',
1✔
101
    `Failed to parse git LFS announcement`,
1✔
102
    ParseError,
1✔
103
  );
1✔
104

105
export class FailedToParseGitLFSInfoError extends _1 {}
1✔
106

107
type InconsistentSizesDynamicContext = {
108
  actual: number;
109
  expected: number;
110
  gitLFSInfo: Either<
111
    Readonly<{
112
      version: string;
113
      oidSha256: string;
114
      size: number;
115
    }>,
116
    InstanceType<FailedToParseGitLFSInfoErrorClass>
117
  >;
118
};
119

120
// Extracting to a separate type is required by JSR, so that consumers of the
121
// library will have much faster type inference
122

123
export const _2: TaggedErrorClass<{
1✔
124
  ErrorName: 'InconsistentExpectedAndRealContentSizeError';
125
  StaticContext: { comment: string };
126
  DynamicContext: InconsistentSizesDynamicContext;
127
}> = buildTaggedErrorClassVerifyingCause<InconsistentSizesDynamicContext>()(
1✔
128
  'InconsistentExpectedAndRealContentSizeError',
1✔
129
  ctx =>
1✔
130
    `Got file with size ${ctx.actual} bytes while expecting ${ctx.expected} bytes`,
1✔
131
  void 0,
1✔
132
  {
1✔
133
    comment: outdent({ newline: ' ' })`
1✔
134
      If we weren't successful in parsing it as git LFS object
135
      announcement using RegExp and Effect.Schema, we just do a basic size
136
      consistency check. The check implements the second marker of it
137
      being a Git LFS object as a backup to checking does "content" look
138
      like a Git LFS object. If GitHub API's "size" field is different
139
      from actual size of "content" field, it means either our schema with
140
      regexp fucked up, or GitHub API did. If it doesn't throw, it means
141
      there's no reason to assume it's a Git LFS object.
142
    `,
143
  },
1✔
144
);
1✔
145

146
export class InconsistentExpectedAndRealContentSizeError extends _2 {}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc