diff --git a/src/compose-paginate.ts b/src/compose-paginate.ts new file mode 100644 index 00000000..a68f72e8 --- /dev/null +++ b/src/compose-paginate.ts @@ -0,0 +1,4 @@ +import { paginate } from "./paginate"; +import { iterator } from "./iterator"; + +export const composePaginateRest = Object.assign(paginate, { iterator }); diff --git a/src/index.ts b/src/index.ts index 78d40e93..02c6ab39 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,12 @@ -import { VERSION } from "./version"; +import { Octokit } from "@octokit/core"; +import { VERSION } from "./version"; import { paginate } from "./paginate"; import { iterator } from "./iterator"; import { PaginateInterface } from "./types"; -export { PaginateInterface } from "./types"; -import { Octokit } from "@octokit/core"; +export { PaginateInterface } from "./types"; +export { composePaginateRest } from "./compose-paginate"; /** * @param octokit Octokit instance diff --git a/src/iterator.ts b/src/iterator.ts index eeb33ac9..0c5061ef 100644 --- a/src/iterator.ts +++ b/src/iterator.ts @@ -4,7 +4,6 @@ import { normalizePaginatedListResponse } from "./normalize-paginated-list-respo import { EndpointOptions, RequestInterface, - OctokitResponse, RequestParameters, Route, } from "./types"; @@ -25,24 +24,20 @@ export function iterator( return { [Symbol.asyncIterator]: () => ({ - next() { - if (!url) { - return Promise.resolve({ done: true }); - } + async next() { + if (!url) return { done: true }; - return requestMethod({ method, url, headers }) - .then(normalizePaginatedListResponse) + const response = await requestMethod({ method, url, headers }); + const normalizedResponse = normalizePaginatedListResponse(response); - .then((response: OctokitResponse) => { - // `response.headers.link` format: - // '; rel="next", ; rel="last"' - // sets `url` to undefined if "next" URL is not present or `link` header is not set - url = ((response.headers.link || "").match( - /<([^>]+)>;\s*rel="next"/ - ) || [])[1]; + // `response.headers.link` format: + // '; rel="next", ; rel="last"' + // sets `url` to undefined if "next" URL is not present or `link` header is not set + url = ((normalizedResponse.headers.link || "").match( + /<([^>]+)>;\s*rel="next"/ + ) || [])[1]; - return { value: response }; - }); + return { value: normalizedResponse }; }, }), }; diff --git a/test/compose-paginate.test.ts b/test/compose-paginate.test.ts new file mode 100644 index 00000000..c87a702f --- /dev/null +++ b/test/compose-paginate.test.ts @@ -0,0 +1,78 @@ +import fetchMock from "fetch-mock"; +import { Octokit } from "@octokit/core"; +import { restEndpointMethods } from "@octokit/plugin-rest-endpoint-methods"; + +import { composePaginateRest } from "../src"; + +const ORG1 = { id: 1 }; +const ORG2 = { id: 2 }; + +test("composePaginateRest(octokit, route)", async () => { + const mock = fetchMock + .sandbox() + .get("https://api.github.com/orgs/octokit/repos?per_page=1", { + body: [ORG1], + headers: { + link: + '; rel="next"', + "X-GitHub-Media-Type": "github.v3; format=json", + }, + }) + .get("https://pagination-test.com/orgs/octokit/repos?page=2&per_page=1", { + body: [ORG2], + headers: {}, + }); + + const octokit = new Octokit({ + request: { + fetch: mock, + }, + }); + + const organizations = await composePaginateRest( + octokit, + "GET /orgs/:org/repos", + { + org: "octokit", + per_page: 1, + } + ); + expect(organizations).toStrictEqual([ORG1, ORG2]); +}); + +test("composePaginateRest.iterator(octokit, route)", () => { + const mock = fetchMock + .sandbox() + .getOnce("https://api.github.com/organizations", { + body: [ORG1], + headers: { + link: '; rel="next"', + "X-GitHub-Media-Type": "github.v3; format=json", + }, + }) + .getOnce("https://pagination-test.com/organizations?since=2", { + body: [ORG2], + headers: {}, + }); + + const octokit = new Octokit({ + request: { + fetch: mock, + }, + }); + + const iterator = composePaginateRest + .iterator(octokit, "GET /organizations") + [Symbol.asyncIterator](); + + return iterator + .next() + .then((result: any) => { + expect(result.value.data[0].id).toEqual(1); + + return iterator.next(); + }) + .then((result: any) => { + expect(result.value.data[0].id).toEqual(2); + }); +}); diff --git a/test/smoke.test.ts b/test/smoke.test.ts index 7d55caf7..619af8f7 100644 --- a/test/smoke.test.ts +++ b/test/smoke.test.ts @@ -1,9 +1,9 @@ import { Octokit } from "@octokit/core"; -import { paginateRest } from "../src"; +import { paginateRest, composePaginateRest } from "../src"; describe("Smoke test", () => { - it("is a function", () => { + it("paginateRest", () => { expect(paginateRest).toBeInstanceOf(Function); }); @@ -11,6 +11,10 @@ describe("Smoke test", () => { expect(paginateRest.VERSION).toEqual("0.0.0-development"); }); + it("composePaginateRest", () => { + expect(composePaginateRest).toBeInstanceOf(Function); + }); + it("Loads plugin", () => { const TestOctokit = Octokit.plugin(paginateRest); const testOctokit = new TestOctokit();