diff --git a/lib/lc/client.ts b/lib/lc/client.ts index 95d803f..c7435b3 100644 --- a/lib/lc/client.ts +++ b/lib/lc/client.ts @@ -1,46 +1,24 @@ -import type { Question } from "lc-dailies/lib/api/mod.ts"; +import type { + LCClientInterface, + LCQuestion, + LCSubmission, +} from "./client_interface.ts"; import { makeQuestionURL } from "./urls.ts"; import { gql } from "./gql.ts"; -/** - * LCQuestion is an alias interface for a Leetcode question. - */ -export type LCQuestion = Question; - -/** - * LCSubmission is the representation of Leetcode's recent submission per user. - */ -export interface LCSubmission { - /** - * id is the id details of the submission. - */ - id: string; - - /** - * name is the name of the question of the submission. - */ - name: string; - - /** - * title is the title of the question of the submission. - */ - title: string; - - /** - * timestamp is the time the submission was submitted. - */ - timestamp: string; -} - /** * LCClient is the client for Leetcode. */ -export class LCClient { +export class LCClient implements LCClientInterface { + constructor( + private readonly fetch: typeof window.fetch = window.fetch.bind(window), + ) {} + /** * verifyUser verifies the user by username. */ public async verifyUser(username: string): Promise { - const response = await fetch(`https://leetcode.com/${username}/`); + const response = await this.fetch(`https://leetcode.com/${username}/`); return response.status === 200; } @@ -142,7 +120,7 @@ export class LCClient { */ .then((json) => json.data.recentAcSubmissionList - .map(( + ?.map(( acSubmission: { id: string; title: string; @@ -154,7 +132,7 @@ export class LCClient { name: acSubmission.titleSlug, title: acSubmission.title, timestamp: acSubmission.timestamp, - })) + })) ?? [] ); } } diff --git a/lib/lc/client_interface.ts b/lib/lc/client_interface.ts new file mode 100644 index 0000000..7a67d74 --- /dev/null +++ b/lib/lc/client_interface.ts @@ -0,0 +1,64 @@ +import type { Question } from "lc-dailies/lib/api/mod.ts"; + +/** + * LCQuestion is an alias interface for a Leetcode question. + */ +export type LCQuestion = Question; + +/** + * LCSubmission is the representation of Leetcode's recent submission per user. + */ +export interface LCSubmission { + /** + * id is the id details of the submission. + */ + id: string; + + /** + * name is the name of the question of the submission. + */ + name: string; + + /** + * title is the title of the question of the submission. + */ + title: string; + + /** + * timestamp is the time the submission was submitted. + */ + timestamp: string; +} + +/** + * LCClientInterface is the client interface for Leetcode. + */ +export interface LCClientInterface { + /** + * verifyUser verifies the user by username. + */ + verifyUser(username: string): Promise; + + /** + * getDailyQuestion gets the daily question from Leetcode. + */ + getDailyQuestion(): Promise; + + /** + * listDailyQuestions gets the last `amount` of daily questions from Leetcode since `asOfYear` and `asOfMonth`. + */ + listDailyQuestions( + limit: number, + asOfYear: number, + asOfMonth: number, + ): Promise; + + /** + * getRecentAcceptedSubmissions gets the recent accepted submissions from + * Leetcode by username. + */ + getRecentAcceptedSubmissions( + username: string, + limit?: number, + ): Promise; +} diff --git a/lib/lc/fake_client.ts b/lib/lc/fake_client.ts index d4d22bc..7775e4d 100644 --- a/lib/lc/fake_client.ts +++ b/lib/lc/fake_client.ts @@ -1,4 +1,8 @@ -import type { LCClient, LCQuestion, LCSubmission } from "./client.ts"; +import type { + LCClientInterface, + LCQuestion, + LCSubmission, +} from "./client_interface.ts"; export const FAKE_LC_USERNAME = "fake_lc_username"; export const FAKE_LC_QUESTION_NAME = "fake_lc_question_name"; @@ -29,7 +33,7 @@ export const FAKE_RECENT_SUBMISSIONS: LCSubmission[] = [ /** * FakeLCClient is a fake implementation of LCClient. */ -export class FakeLCClient implements LCClient { +export class FakeLCClient implements LCClientInterface { public verifyUser(username: string): Promise { return Promise.resolve(username === FAKE_LC_USERNAME); } diff --git a/lib/lc/mod.ts b/lib/lc/mod.ts index a786f1b..77239a1 100644 --- a/lib/lc/mod.ts +++ b/lib/lc/mod.ts @@ -1,2 +1,3 @@ +export * from "./client_interface.ts"; export * from "./client.ts"; export * from "./urls.ts"; diff --git a/lib/leaderboard/denokv/denokv_leaderboard_client.ts b/lib/leaderboard/denokv/denokv_leaderboard_client.ts index 82fa03d..275fd23 100644 --- a/lib/leaderboard/denokv/denokv_leaderboard_client.ts +++ b/lib/leaderboard/denokv/denokv_leaderboard_client.ts @@ -2,7 +2,7 @@ import { DAY, ulid, WEEK } from "lc-dailies/deps.ts"; import type * as api from "lc-dailies/lib/api/mod.ts"; import type { LeaderboardClient } from "lc-dailies/lib/leaderboard/mod.ts"; import { sync } from "lc-dailies/lib/leaderboard/mod.ts"; -import { LCClient } from "lc-dailies/lib/lc/mod.ts"; +import type { LCClientInterface } from "lc-dailies/lib/lc/mod.ts"; /** * DenoKvLeaderboardClient is the client for the leaderboard. @@ -16,7 +16,7 @@ export class DenoKvLeaderboardClient implements LeaderboardClient { /** * lc is the Leetcode client. */ - private readonly lc: LCClient, + private readonly lc: LCClientInterface, /** * restartMS is the milliseconds to restart the leaderboard. * diff --git a/lib/leaderboard/sync.ts b/lib/leaderboard/sync.ts index 5ded446..6b7e179 100644 --- a/lib/leaderboard/sync.ts +++ b/lib/leaderboard/sync.ts @@ -1,6 +1,6 @@ import { SECOND, WEEK } from "lc-dailies/deps.ts"; import type * as api from "lc-dailies/lib/api/mod.ts"; -import type { LCClient } from "lc-dailies/lib/lc/mod.ts"; +import type { LCClientInterface } from "lc-dailies/lib/lc/mod.ts"; import { calculateScores, makeDefaultCalculateScoresOptions, @@ -23,7 +23,7 @@ export interface SyncOptions { /** * lcClient is the Leetcode client. */ - lcClient: LCClient; + lcClient: LCClientInterface; /** * questionsFetchAmount is the amount of questions to fetch from Leetcode.