2020-06-07 00:27:02 +08:00
const VERSION = "1.1.2" ;
2020-03-02 21:16:42 +08:00
/ * *
* Some “ list ” response that can be paginated have a different response structure
*
* They have a ` total_count ` key in the response ( search also has ` incomplete_results ` ,
* / i n s t a l l a t i o n / r e p o s i t o r i e s a l s o h a s ` r e p o s i t o r y _ s e l e c t i o n ` ) , a s w e l l a s a k e y w i t h
2020-06-07 00:27:02 +08:00
* the list of the items which name varies from endpoint to endpoint :
*
* - https : //developer.github.com/v3/search/#example (key `items`)
* - https : //developer.github.com/v3/checks/runs/#response-3 (key: `check_runs`)
* - https : //developer.github.com/v3/checks/suites/#response-1 (key: `check_suites`)
* - https : //developer.github.com/v3/apps/installations/#list-repositories (key: `repositories`)
* - https : //developer.github.com/v3/apps/installations/#list-installations-for-a-user (key `installations`)
2020-03-02 21:16:42 +08:00
*
* Octokit normalizes these responses so that paginated results are always returned following
* the same structure . One challenge is that if the list response has only one page , no Link
* header is provided , so this header alone is not sufficient to check wether a response is
2020-06-07 00:27:02 +08:00
* paginated or not . For the exceptions with the namespace , a fallback check for the route
* paths has to be added in order to normalize the response . We cannot check for the total _count
* property because it also exists in the response of Get the combined status for a specific ref .
2020-03-02 21:16:42 +08:00
* /
2020-06-07 00:27:02 +08:00
const REGEX = [
/^\/search\// ,
/^\/repos\/[^/]+\/[^/]+\/commits\/[^/]+\/(check-runs|check-suites)([^/]|$)/ ,
/^\/installation\/repositories([^/]|$)/ ,
/^\/user\/installations([^/]|$)/ ,
/^\/repos\/[^/]+\/[^/]+\/actions\/secrets([^/]|$)/ ,
/^\/repos\/[^/]+\/[^/]+\/actions\/workflows(\/[^/]+\/runs)?([^/]|$)/ ,
/^\/repos\/[^/]+\/[^/]+\/actions\/runs(\/[^/]+\/(artifacts|jobs))?([^/]|$)/
] ;
function normalizePaginatedListResponse ( octokit , url , response ) {
const path = url . replace ( octokit . request . endpoint . DEFAULTS . baseUrl , "" ) ;
const responseNeedsNormalization = REGEX . find ( regex => regex . test ( path ) ) ;
2020-03-02 21:16:42 +08:00
if ( ! responseNeedsNormalization )
2020-06-07 00:27:02 +08:00
return ;
2020-03-02 21:16:42 +08:00
// keep the additional properties intact as there is currently no other way
// to retrieve the same information.
const incompleteResults = response . data . incomplete _results ;
const repositorySelection = response . data . repository _selection ;
const totalCount = response . data . total _count ;
delete response . data . incomplete _results ;
delete response . data . repository _selection ;
delete response . data . total _count ;
const namespaceKey = Object . keys ( response . data ) [ 0 ] ;
const data = response . data [ namespaceKey ] ;
response . data = data ;
if ( typeof incompleteResults !== "undefined" ) {
response . data . incomplete _results = incompleteResults ;
}
if ( typeof repositorySelection !== "undefined" ) {
response . data . repository _selection = repositorySelection ;
}
response . data . total _count = totalCount ;
2020-06-07 00:27:02 +08:00
Object . defineProperty ( response . data , namespaceKey , {
get ( ) {
octokit . log . warn ( ` [@octokit/paginate-rest] "response.data. ${ namespaceKey } " is deprecated for "GET ${ path } ". Get the results directly from "response.data" ` ) ;
return Array . from ( data ) ;
}
} ) ;
2020-03-02 21:16:42 +08:00
}
function iterator ( octokit , route , parameters ) {
2020-06-07 00:27:02 +08:00
const options = octokit . request . endpoint ( route , parameters ) ;
2020-03-02 21:16:42 +08:00
const method = options . method ;
const headers = options . headers ;
let url = options . url ;
return {
[ Symbol . asyncIterator ] : ( ) => ( {
next ( ) {
if ( ! url ) {
return Promise . resolve ( { done : true } ) ;
}
2020-06-07 00:27:02 +08:00
return octokit
. request ( { method , url , headers } )
2020-03-02 21:16:42 +08:00
. then ( ( response ) => {
2020-06-07 00:27:02 +08:00
normalizePaginatedListResponse ( octokit , url , response ) ;
2020-03-02 21:16:42 +08:00
// `response.headers.link` format:
// '<https://api.github.com/users/aseemk/followers?page=2>; rel="next", <https://api.github.com/users/aseemk/followers?page=2>; 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 ] ;
return { value : response } ;
} ) ;
2020-06-07 00:27:02 +08:00
}
} )
2020-03-02 21:16:42 +08:00
} ;
}
function paginate ( octokit , route , parameters , mapFn ) {
if ( typeof parameters === "function" ) {
mapFn = parameters ;
parameters = undefined ;
}
return gather ( octokit , [ ] , iterator ( octokit , route , parameters ) [ Symbol . asyncIterator ] ( ) , mapFn ) ;
}
function gather ( octokit , results , iterator , mapFn ) {
2020-06-07 00:27:02 +08:00
return iterator . next ( ) . then ( result => {
2020-03-02 21:16:42 +08:00
if ( result . done ) {
return results ;
}
let earlyExit = false ;
function done ( ) {
earlyExit = true ;
}
results = results . concat ( mapFn ? mapFn ( result . value , done ) : result . value . data ) ;
if ( earlyExit ) {
return results ;
}
return gather ( octokit , results , iterator , mapFn ) ;
} ) ;
}
/ * *
* @ param octokit Octokit instance
* @ param options Options passed to Octokit constructor
* /
function paginateRest ( octokit ) {
return {
paginate : Object . assign ( paginate . bind ( null , octokit ) , {
2020-06-07 00:27:02 +08:00
iterator : iterator . bind ( null , octokit )
} )
2020-03-02 21:16:42 +08:00
} ;
}
paginateRest . VERSION = VERSION ;
export { paginateRest } ;
//# sourceMappingURL=index.js.map