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
1 change: 1 addition & 0 deletions docs/contributing/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Every package in stdlib has, at minimum, the following structure:

```text
benchmark/ benchmarks
include/ public C/C++ header files
docs/ documentation (excluding README)
examples/ examples
lib/ package implementation
Expand Down
39 changes: 39 additions & 0 deletions lib/node_modules/@stdlib/_tools/lint/header-filenames/lib/lint.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

// MODULES //

var basename = require( 'path' ).basename; // TODO: use stdlib module

Check warning on line 23 in lib/node_modules/@stdlib/_tools/lint/header-filenames/lib/lint.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: use stdlib module'
var objectKeys = require( '@stdlib/utils/keys' );
var extname = require( '@stdlib/utils/extname' );
var hasOwnProp = require( '@stdlib/assert/has-own-property' );
Expand All @@ -38,7 +38,8 @@
* @param {StringArray} arr - array of filenames
* @returns {(ObjectArray|EmptyArray)} array of lint errors
*/
function lint( arr ) {

Check failure on line 41 in lib/node_modules/@stdlib/_tools/lint/header-filenames/lib/lint.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Variable declarations inside of function are not ordered by length (in decreasing order)
var packages;
var headers;
var fnames;
var fname;
Expand All @@ -50,10 +51,38 @@
var i;
var j;
var k;
var name;
var include;
var pkg;
var expected;
var packagePath;
var packageNames;

headers = {};
packages = {};
out = [];
for ( i = 0; i < arr.length; i++ ) {
name = arr[ i ].replace( /\\/g, '/' );
if ( name.indexOf( '/include/' ) !== -1 ) {
include = name.substring( 0, name.indexOf( '/include/' )+9 );
pkg = basename( include.substring( 0, include.length-9 ) );
if ( pkg !== '.' && pkg !== '..' && !/^[A-Za-z]:\//.test( name ) ) {
expected = pkg.replace( /-/g, '_' )+'.h';
if ( include.indexOf( '/@stdlib/' ) !== -1 ) {
packagePath = include.substring( include.indexOf( '/@stdlib/' )+9, include.length-9 );
expected = 'stdlib/'+packagePath.slice( 0, -pkg.length )+pkg.replace( /-/g, '_' )+'.h';
}
if ( !packages[ include ] ) {
packages[ include ] = {
'path': include+expected,
'found': false
};
}
if ( name === packages[ include ].path || name === packages[ include ].path.replace( /\\.h$/, '.hpp' ) ) {
packages[ include ].found = true;
}
}
}
fname = basename( arr[ i ] );
ext = extname( fname );
fname = fname.substring( 0, fname.length-ext.length );
Expand Down Expand Up @@ -81,6 +110,16 @@
headers[ ext ][ fname ] = [ arr[ i ] ];
}
}
// Ensure every package has a primary header file...
packageNames = objectKeys( packages );
for ( i = 0; i < packageNames.length; i++ ) {
if ( !packages[ packageNames[ i ] ].found ) {
out.push({
'name': packages[ packageNames[ i ] ].path,
'error': 'missing primary header file.'
});
}
}
// For every basename found multiple times, log a lint error...
exts = objectKeys( headers );
for ( i = 0; i < exts.length; i++ ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ tape( 'the command-line interface prints newline-delimited JSON (NDJSON) if head
t.strictEqual( stdout.toString(), '', 'does not print to `stdout`' );

results = stderr.toString().split( RE_EOL );
t.strictEqual( results.length, 3, 'returns expected number of errors' );
t.strictEqual( results.length, 4, 'returns expected number of errors' );
for ( i = 0; i < results.length-1; i++ ) {
t.strictEqual( isJSON( results[i] ), true, 'returns JSON' );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,63 @@ tape( 'the function returns an empty array if all header base filenames are vali
t.strictEqual( names.length, 0, 'returns expected value' );
t.end();
});

tape( 'the function returns an error if a package is missing its primary header file', function test( t ) {
var names;

names = lint([
'foo/include/private.h'
]);

t.strictEqual( names.length, 1, 'returns one error' );
t.strictEqual( names[ 0 ].name, 'foo/include/foo.h', 'returns expected filename' );
t.strictEqual( names[ 0 ].error, 'missing primary header file.', 'returns expected error' );
t.end();
});

tape( 'the function allows additional header files with arbitrary names', function test( t ) {
var names;

names = lint([
'foo/include/foo.h',
'foo/include/private.h'
]);

t.strictEqual( names.length, 0, 'returns an empty array' );
t.end();
});

tape( 'the function converts hyphens in a package path to underscores when resolving the primary header file', function test( t ) {
var names;

names = lint([
'lib/node_modules/@stdlib/math/base/assert/int32-is-even/include/stdlib/math/base/assert/int32_is_even.h'
]);

t.strictEqual( names.length, 0, 'returns an empty array' );
t.end();
});

tape( 'the function does not convert hyphens in parent package directories when resolving the primary header file', function test( t ) {
var names;

names = lint([
'lib/node_modules/@stdlib/foo-bar/my-package/include/stdlib/foo-bar/my_package.h'
]);

t.strictEqual( names.length, 0, 'returns an empty array' );
t.end();
});

tape( 'the function returns an error if the primary header filename is invalid', function test( t ) {
var names;

names = lint([
'lib/node_modules/@stdlib/foo-bar/my-package/include/stdlib/foo-bar/wrong_name.h'
]);

t.strictEqual( names.length, 1, 'returns one error' );
t.strictEqual( names[ 0 ].name, 'lib/node_modules/@stdlib/foo-bar/my-package/include/stdlib/foo-bar/my_package.h', 'returns expected filename' );
t.strictEqual( names[ 0 ].error, 'missing primary header file.', 'returns expected error' );
t.end();
});
Loading