Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/index.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export {

export * from "./ranking-history.js";
export * from "./params.js";
export type { NarouParams } from "./narou.js";
export type { ExecuteOptions, NarouParams } from "./narou.js";
export * from "./narou-search-results.js";
export type * from "./narou-ranking-results.js";
export * from "./search-builder.js";
Expand Down
7 changes: 4 additions & 3 deletions src/narou-fetch.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { unzipp } from "./util/unzipp.js";
import NarouNovel from "./narou.js";
import type { NarouParams } from "./narou.js";
import type { ExecuteOptions, NarouParams } from "./narou.js";

type Fetch = typeof fetch;

Expand All @@ -18,7 +18,8 @@ export default class NarouNovelFetch extends NarouNovel {

protected async execute<T>(
params: NarouParams,
endpoint: string
endpoint: string,
options?: ExecuteOptions
): Promise<T> {
const query = { ...params, out: "json" };

Expand All @@ -36,7 +37,7 @@ export default class NarouNovelFetch extends NarouNovel {
}
});

const res = await (this.fetch ?? fetch)(url);
const res = await (this.fetch ?? fetch)(url, options?.fetchOptions);

if (!query.gzip) {
return (await res.json()) as T;
Expand Down
5 changes: 3 additions & 2 deletions src/narou-jsonp.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import NarouNovel from "./narou.js";
import type { NarouParams } from "./narou.js";
import type { ExecuteOptions, NarouParams } from "./narou.js";
import { jsonp } from "./util/jsonp.js";

/**
Expand All @@ -8,7 +8,8 @@ import { jsonp } from "./util/jsonp.js";
export default class NarouNovelJsonp extends NarouNovel {
protected async execute<T>(
params: NarouParams,
endpoint: string
endpoint: string,
_options?: ExecuteOptions
): Promise<T> {
const query = { ...params, out: "jsonp" };
query.gzip = 0;
Expand Down
56 changes: 43 additions & 13 deletions src/narou.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export type NarouParams =
| RankingHistoryParams
| UserSearchParams;

export type ExecuteOptions = {
fetchOptions?: RequestInit;
};

/**
* なろう小説APIへのリクエストを実行する
* @class NarouNovel
Expand All @@ -35,7 +39,8 @@ export default abstract class NarouNovel {
*/
protected abstract execute<T>(
params: NarouParams,
endpoint: string
endpoint: string,
options?: ExecuteOptions
): Promise<T>;

/**
Expand All @@ -46,9 +51,13 @@ export default abstract class NarouNovel {
*/
protected async executeSearch<T extends keyof NarouSearchResult>(
params: SearchParams,
endpoint = "https://api.syosetu.com/novelapi/api/"
endpoint = "https://api.syosetu.com/novelapi/api/",
options?: ExecuteOptions
): Promise<NarouSearchResults<NarouSearchResult, T>> {
return new NarouSearchResults(await this.execute(params, endpoint), params);
return new NarouSearchResults(
await this.execute(params, endpoint, options),
params
);
}

/**
Expand All @@ -58,11 +67,13 @@ export default abstract class NarouNovel {
* @see https://dev.syosetu.com/man/api/
*/
async executeNovel<T extends keyof NarouSearchResult>(
params: SearchParams
params: SearchParams,
options?: ExecuteOptions
): Promise<NarouSearchResults<NarouSearchResult, T>> {
return await this.executeSearch(
params,
"https://api.syosetu.com/novelapi/api/"
"https://api.syosetu.com/novelapi/api/",
options
);
}

Expand All @@ -73,11 +84,13 @@ export default abstract class NarouNovel {
* @see https://dev.syosetu.com/xman/api/
*/
async executeNovel18<T extends keyof NarouSearchResult>(
params: SearchParams
params: SearchParams,
options?: ExecuteOptions
): Promise<NarouSearchResults<NarouSearchResult, T>> {
return await this.executeSearch(
params,
"https://api.syosetu.com/novel18api/api/"
"https://api.syosetu.com/novel18api/api/",
options
);
}

Expand All @@ -87,8 +100,15 @@ export default abstract class NarouNovel {
* @returns ランキング結果
* @see https://dev.syosetu.com/man/rankapi/
*/
async executeRanking(params: RankingParams): Promise<NarouRankingResult[]> {
return await this.execute(params, "https://api.syosetu.com/rank/rankget/");
async executeRanking(
params: RankingParams,
options?: ExecuteOptions
): Promise<NarouRankingResult[]> {
return await this.execute(
params,
"https://api.syosetu.com/rank/rankget/",
options
);
}

/**
Expand All @@ -98,9 +118,14 @@ export default abstract class NarouNovel {
* @see https://dev.syosetu.com/man/rankinapi/
*/
async executeRankingHistory(
params: RankingHistoryParams
params: RankingHistoryParams,
options?: ExecuteOptions
): Promise<RankingHistoryRawResult[]> {
return await this.execute(params, "https://api.syosetu.com/rank/rankin/");
return await this.execute(
params,
"https://api.syosetu.com/rank/rankin/",
options
);
}

/**
Expand All @@ -110,10 +135,15 @@ export default abstract class NarouNovel {
* @see https://dev.syosetu.com/man/userapi/
*/
async executeUserSearch<T extends keyof UserSearchResult>(
params: UserSearchParams
params: UserSearchParams,
options?: ExecuteOptions
): Promise<NarouSearchResults<UserSearchResult, T>> {
return new NarouSearchResults<UserSearchResult, T>(
await this.execute(params, "https://api.syosetu.com/userapi/api/"),
await this.execute(
params,
"https://api.syosetu.com/userapi/api/",
options
),
params
);
}
Expand Down
25 changes: 14 additions & 11 deletions src/ranking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
RankingType,
Fields,
} from "./params.js";
import type NarouNovel from "./narou.js";
import type NarouNovel, { ExecuteOptions } from "./narou.js";
import type { SearchResultFields } from "./narou-search-results.js";
import { addDays, formatDate } from "./util/date.js";

Expand Down Expand Up @@ -111,18 +111,18 @@ export default class RankingBuilder {
* @returns {Promise<NarouRankingResult[]>} ランキング結果の配列
* @see https://dev.syosetu.com/man/rankapi/#output
*/
execute(): Promise<NarouRankingResult[]> {
execute(options?: ExecuteOptions): Promise<NarouRankingResult[]> {
const date = formatDate(this.date$);
this.set({ rtype: `${date}-${this.type$}` });
return this.api.executeRanking(this.params as RankingParams);
return this.api.executeRanking(this.params as RankingParams, options);
}

/**
* ランキングAPIを実行し、取得したNコードを元になろう小説APIで詳細情報を取得して結合します。
*/
async executeWithFields(): Promise<
RankingResult<DefaultSearchResultFields>[]
>;
async executeWithFields(
options?: ExecuteOptions
): Promise<RankingResult<DefaultSearchResultFields>[]>;
/**
* ランキングAPIを実行し、取得したNコードを元になろう小説APIで詳細情報を取得して結合します。
*
Expand All @@ -131,7 +131,8 @@ export default class RankingBuilder {
* @returns {Promise<RankingResult<SearchResultFields<TFields>>[]>} 詳細情報を含むランキング結果の配列
*/
async executeWithFields<TFields extends Fields>(
fields: TFields | TFields[]
fields: TFields | TFields[],
options?: ExecuteOptions
): Promise<RankingResult<SearchResultFields<TFields>>[]>;
/**
* ランキングAPIを実行し、取得したNコードを元になろう小説APIで詳細情報を取得して結合します。
Expand All @@ -141,7 +142,8 @@ export default class RankingBuilder {
*/
async executeWithFields(
fields: never[],
opt: OptionalFields | OptionalFields[]
opt: OptionalFields | OptionalFields[],
options?: ExecuteOptions
): Promise<RankingResult<DefaultSearchResultFields | "weekly_unique">[]>;
/**
* ランキングAPIを実行し、取得したNコードを元になろう小説APIで詳細情報を取得して結合します。
Expand Down Expand Up @@ -169,9 +171,10 @@ export default class RankingBuilder {
TOpt extends OptionalFields | undefined = undefined
>(
fields: TFields | TFields[] = [],
opt?: TOpt
opt?: TOpt,
options?: ExecuteOptions
): Promise<RankingResult<SearchResultFields<TFields>>[]> {
const ranking = await this.execute();
const ranking = await this.execute(options);
const fields$ = Array.isArray(fields)
? fields.length == 0
? []
Expand All @@ -186,7 +189,7 @@ export default class RankingBuilder {
}
builder.ncode(rankingNcodes);
builder.limit(ranking.length);
const result = await builder.execute();
const result = await builder.execute(options);

return ranking.map<
RankingResult<
Expand Down
7 changes: 5 additions & 2 deletions src/search-builder-r18.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
SearchResultR18Fields,
SearchResultOptionalFields,
} from "./narou-search-results.js";
import type { ExecuteOptions } from "./narou.js";
import type {
R18Site,
SearchResultFieldNames,
Expand All @@ -30,8 +31,10 @@ export default class SearchBuilderR18<
* @override
* @returns {Promise<NarouSearchResults>} 検索結果
*/
execute(): Promise<NarouSearchResults<NarouSearchResult, T | TOpt>> {
return this.api.executeNovel18(this.params);
execute(
options?: ExecuteOptions
): Promise<NarouSearchResults<NarouSearchResult, T | TOpt>> {
return this.api.executeNovel18(this.params, options);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions src/search-builder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type NarouNovel from "./narou.js";
import type NarouNovel, { ExecuteOptions } from "./narou.js";
import type {
NarouSearchResult,
SearchResultFields,
Expand Down Expand Up @@ -474,8 +474,10 @@ export abstract class NovelSearchBuilderBase<
* なろう小説APIへの検索リクエストを実行する
* @returns {Promise<NarouSearchResults>} 検索結果
*/
execute(): Promise<NarouSearchResults<NarouSearchResult, T>> {
return this.api.executeNovel(this.params);
execute(options?: ExecuteOptions): Promise<
NarouSearchResults<NarouSearchResult, T>
> {
return this.api.executeNovel(this.params, options);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/user-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
} from "./narou-search-results.js";
import type { UserFields, UserOrder, UserSearchParams } from "./params.js";
import { SearchBuilderBase } from "./search-builder.js";
import type { ExecuteOptions } from "./narou.js";

/**
* なろうユーザ検索API
Expand Down Expand Up @@ -104,7 +105,12 @@ export default class UserSearchBuilder<
* なろう小説APIへのリクエストを実行する
* @returns ランキング
*/
execute(): Promise<NarouSearchResults<UserSearchResult, TField>> {
return this.api.executeUserSearch(this.params as UserSearchParams);
execute(
options?: ExecuteOptions
): Promise<NarouSearchResults<UserSearchResult, TField>> {
return this.api.executeUserSearch(
this.params as UserSearchParams,
options
);
}
}
20 changes: 20 additions & 0 deletions test/narou-fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ describe('NarouNovelFetch', () => {
expect(result).toEqual(mockData);
});

it('should pass fetch options to fetch implementation', async () => {
const customFetchMock = vi.fn().mockResolvedValue({
json: vi.fn().mockResolvedValue(mockData)
});

const narouFetch = new NarouNovelFetch(customFetchMock);

// @ts-expect-error - Accessing protected method for testing
await narouFetch.execute(
{ gzip: 0 },
'https://api.example.com',
{ fetchOptions: { method: 'POST', headers: { 'X-Test': '1' } } }
);

expect(customFetchMock).toHaveBeenCalledWith(
new URL('https://api.example.com/?out=json'),
{ method: 'POST', headers: { 'X-Test': '1' } }
);
});

it('should set gzip to 5 when undefined', async () => {
// URLパラメータをキャプチャするモック
const requestSpy = vi.fn();
Expand Down
Loading