Skip to content
Open
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 lib/node_modules/@stdlib/_tools/github/get/lib/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
// MODULES //

var logger = require( 'debug' );
var parseHeader = require( 'parse-link-header' );
var hasOwnProp = require( '@stdlib/assert/has-own-property' );
var parseHeader = require( '@stdlib/_tools/github/parse-link-header' );
var request = require( './request.js' );
var flatten = require( './flatten.js' );
var getOptions = require( './options.js' );
Expand Down Expand Up @@ -169,7 +169,7 @@

if ( curr === opts.page ) {
debug( 'First paginated result. Resolving %d remaining page(s).', total-count );
setTimeout( getNext( curr+1, last ), 0 ); // dezalgo'd

Check warning on line 172 in lib/node_modules/@stdlib/_tools/github/get/lib/resolve.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unknown word: "dezalgo'd"
}
done();
}
Expand Down
109 changes: 109 additions & 0 deletions lib/node_modules/@stdlib/_tools/github/parse-link-header/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!--

@license Apache-2.0

Copyright (c) 2026 The Stdlib Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-->

# Parse Link Header

> Parse a Link header.

<section class="usage">

## Usage

```javascript
var parseLinkHeader = require( '@stdlib/_tools/github/parse-link-header' );
```

#### parseLinkHeader( header )

Parses a `Link` header string.

```javascript
var out = parseLinkHeader( '<https://api.github.com/user/repos?page=2&per_page=1>; rel="next"' );
// returns { 'next': { 'url': 'https://api.github.com/user/repos?page=2&per_page=1', 'page': '2', 'per_page': '1', 'rel': 'next' } }
```

If unable to parse a header, the function returns `null`.

```javascript
var out = parseLinkHeader( 'beep; boop' );
// returns null
```

</section>

<!-- /.usage -->

<section class="notes">

## Notes

- The implementation is intended for pragmatic parsing of pagination `Link` headers and is **not** a standards-complete general-purpose parser.

- The function returns `null` if provided a first argument which is not a `string`.

```javascript
var out = parseLinkHeader( null );
// returns null
```

- The function returns `null` for header values longer than `2000` characters.

</section>

<!-- /.notes -->

<section class="examples">

## Examples

<!-- eslint no-undef: "error" -->

```javascript
var parseLinkHeader = require( '@stdlib/_tools/github/parse-link-header' );

var out = parseLinkHeader( '<https://api.github.com/user/repos?page=2&per_page=1>; rel="next", <https://api.github.com/user/repos?page=4&per_page=1>; rel="last"' );
// returns { 'next': {...}, 'last': {...} }

out = parseLinkHeader( '<https://api.github.com/user/repos?page=3>; rel="next prev"; title="next, page"' );
// returns { 'next': {...}, 'prev': {...} }

out = parseLinkHeader( 'beep; boop' );
// returns null
```

</section>

<!-- /.examples -->

<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->

<section class="related">

</section>

<!-- /.related -->

<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->

<section class="links">

</section>

<!-- /.links -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Usage: parseLinkHeader( header )

Parses a Link header and returns a mapping of link relations to parsed
link values.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @license Apache-2.0
*
* Copyright (c) 2026 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var parseLinkHeader = require( './../lib' );


// MAIN //

var out = parseLinkHeader( '<https://api.github.com/user/repos?page=2&per_page=1>; rel="next", <https://api.github.com/user/repos?page=5&per_page=1>; rel="last"' );
console.log( out );

out = parseLinkHeader( '<https://api.github.com/user/repos?page=3>; rel="next prev"; title="next, page"' );
console.log( out );

out = parseLinkHeader( 'beep; boop' );
console.log( out );
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @license Apache-2.0
*
* Copyright (c) 2026 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

/**
* Parse a Link header.
*
* @module @stdlib/_tools/github/parse-link-header
*
* @example
* var parseLinkHeader = require( '@stdlib/_tools/github/parse-link-header' );
*
* var out = parseLinkHeader( '<https://api.github.com/user/repos?page=2>; rel="next"' );
* // returns { 'next': { 'url': 'https://api.github.com/user/repos?page=2', 'page': '2', 'rel': 'next' } }
*/

// MODULES //

var main = require( './main.js' );


// EXPORTS //

module.exports = main;
196 changes: 196 additions & 0 deletions lib/node_modules/@stdlib/_tools/github/parse-link-header/lib/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/**
* @license Apache-2.0
*
* Copyright (c) 2026 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var parseURL = require( 'url' ).parse;
var hasOwnProp = require( '@stdlib/assert/has-own-property' );
var trim = require( '@stdlib/string/base/trim' );
var objectKeys = require( '@stdlib/utils/keys' );


// VARIABLES //

var MAX_LENGTH = 2000;


// FUNCTIONS //

/**
* Splits a link header into individual link values.
*
* @private
* @param {string} str - header string
* @returns {StringArray} link values
*/
function splitValues( str ) {
var values;
var quoted;
var angled;
var start;
var i;

values = [];
start = 0;
quoted = false;
angled = false;

for ( i = 0; i < str.length; i++ ) {
if ( str.charCodeAt( i ) === 34 ) {
quoted = !quoted;
} else if ( quoted === false ) {
if ( str.charCodeAt( i ) === 60 ) {
angled = true;
} else if ( str.charCodeAt( i ) === 62 ) {
angled = false;
} else if ( str.charCodeAt( i ) === 44 && angled === false ) {
values.push( str.substring( start, i ) );
start = i + 1;
}
}
}
values.push( str.substring( start ) );
return values;
}

/**
* Removes wrapping double quotes from a string.
*
* @private
* @param {string} str - input string
* @returns {string} unwrapped string
*/
function unwrap( str ) {
if (
str.length >= 2 &&
str.charCodeAt( 0 ) === 34 &&
str.charCodeAt( str.length-1 ) === 34
) {
return str.substring( 1, str.length-1 );
}
return str;
}

/**
* Parses an individual link header value.
*
* @private
* @param {string} str - link value
* @returns {(Object|null)} parsed link or null
*/
function parseValue( str ) {
var rels;
var out;
var url;
var idx;
var q;
var v;
var k;
var i;

str = trim( str );
if ( str.length === 0 || str.charCodeAt( 0 ) !== 60 ) {
return null;
}
idx = str.indexOf( '>' );
if ( idx < 0 ) {
return null;
}
url = str.substring( 1, idx );
out = {
'url': url
};

q = parseURL( url, true ).query;
for ( k in q ) {
if ( hasOwnProp( q, k ) ) {
out[ k ] = q[ k ];
}
}
str = str.substring( idx+1 );
str = str.split( ';' );

for ( i = 0; i < str.length; i++ ) {
v = trim( str[ i ] );
if ( v.length === 0 ) {
continue;
}
idx = v.indexOf( '=' );
if ( idx < 0 ) {
continue;
}
k = trim( v.substring( 0, idx ) );
v = unwrap( trim( v.substring( idx+1 ) ) );
out[ k ] = v;
}
if ( typeof out.rel !== 'string' || out.rel.length === 0 ) {
return null;
}
rels = out.rel.split( /\s+/ );
return {
'rels': rels,
'value': out
};
}


// MAIN //

/**
* Parses a Link header.
*
* @param {string} header - link header
* @returns {(Object|null)} parsed links or null
*
* @example
* var out = parseLinkHeader( '<https://api.github.com/user/repos?page=2>; rel="next"' );
* // returns { 'next': { 'url': 'https://api.github.com/user/repos?page=2', 'page': '2', 'rel': 'next' } }
*/
function parseLinkHeader( header ) {
var values;
var out;
var obj;
var i;
var j;

if ( typeof header !== 'string' || header.length === 0 || header.length > MAX_LENGTH ) {
return null;
}
values = splitValues( header );
out = {};
for ( i = 0; i < values.length; i++ ) {
obj = parseValue( values[ i ] );
if ( obj === null ) {
continue;
}
for ( j = 0; j < obj.rels.length; j++ ) {
out[ obj.rels[ j ] ] = obj.value;
}
}
if ( objectKeys( out ).length === 0 ) {
return null;
}
return out;
}


// EXPORTS //

module.exports = parseLinkHeader;
Loading