diff --git a/etc/commitlint/.commitlintrc.js b/etc/commitlint/.commitlintrc.js index 2b0153077ef2..d9c6da1082a1 100644 --- a/etc/commitlint/.commitlintrc.js +++ b/etc/commitlint/.commitlintrc.js @@ -20,6 +20,13 @@ /* eslint-disable stdlib/jsdoc-leading-description-sentence */ +// MODULES // + +var stdlibPlugin = require( './plugins' ); + + +// MAIN // + /** * commitlint configuration. * @@ -27,6 +34,15 @@ */ var config = {}; +/** +* Custom plugins. +* +* @name plugins +* @memberof config +* @type {Array} +*/ +config[ 'plugins' ] = [ stdlibPlugin ]; + /** * Link to commit guidance. * diff --git a/etc/commitlint/plugins/index.js b/etc/commitlint/plugins/index.js new file mode 100644 index 000000000000..cb48f4c899bf --- /dev/null +++ b/etc/commitlint/plugins/index.js @@ -0,0 +1,43 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 packageReferenceFormat = require( '@stdlib/_tools/commitlint/rules/package-reference-format' ); + + +// MAIN // + +/** +* Custom commitlint plugin for stdlib-specific rules. +* +* @name plugin +* @type {Object} +*/ +var plugin = { + 'rules': { + 'package-reference-format': packageReferenceFormat + } +}; + + +// EXPORTS // + +module.exports = plugin; diff --git a/etc/commitlint/rules/index.js b/etc/commitlint/rules/index.js index c3b3b655a598..5f8eee3e13aa 100644 --- a/etc/commitlint/rules/index.js +++ b/etc/commitlint/rules/index.js @@ -363,6 +363,15 @@ rules[ 'signed-off-by' ] = [ 0, 'always' ]; */ rules[ 'trailer-exists' ] = [ 0, 'always', 'Signed-off-by:' ]; +/** +* Require that stdlib package references use backticks and exclude `@stdlib/` prefix. +* +* @name package-reference-format +* @memberof rules +* @type {Array} +*/ +rules[ 'package-reference-format' ] = [ 2, 'always' ]; + // EXPORTS // diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/README.md b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/README.md new file mode 100644 index 000000000000..0b64e25d8878 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/README.md @@ -0,0 +1,143 @@ + + +# package-reference-format + +> [Commitlint rule][commitlint-rules] enforcing that stdlib package references use backticks and exclude the `@stdlib/` prefix. + +
+ +This rule ensures consistent formatting of stdlib package references in commit messages and PR titles: + +1. Package references must be wrapped in backticks (e.g., `` `math/base/special/abs` ``). +2. Package references must NOT include the `@stdlib/` prefix. + +
+ + + +
+ +## Usage + +```javascript +var rule = require( '@stdlib/_tools/commitlint/rules/package-reference-format' ); +``` + +#### rule( parsed, when ) + +[Commitlint rule][commitlint-rules] enforcing that stdlib package references use backticks and exclude the `@stdlib/` prefix. + +```javascript +var parsed = { + 'subject': 'feat: add math/base/special/abs' +}; +var result = rule( parsed, 'always' ); +// returns [ false, 'Package reference `math/base/special/abs` must be wrapped in backticks.' ] +``` + +**Bad**: + +```text +feat: add math/base/special/abs +feat: add `@stdlib/math/base/special/abs` +docs: update stats/maxabs +fix: resolve issue in dists/chi/logpdf +``` + +**Good**: + +```text +feat: add `math/base/special/abs` +docs: update `stats/maxabs` +fix: resolve issue in `dists/chi/logpdf` +docs: fix typo in README +``` + +
+ + + +
+ +## Notes + +- The rule detects package references by matching paths that start with known stdlib namespace segments (e.g., `math`, `stats`, `blas`, `dists`, `special`, etc.). +- The list of namespace segments is stored in `lib/namespace_segments.json` and can be regenerated using the build script. +- Partial paths like `dists/chi/logpdf` or `special/abs` are also detected. +- URLs are excluded from detection to avoid false positives. + +
+ + + +
+ +## Examples + +```javascript +var rule = require( '@stdlib/_tools/commitlint/rules/package-reference-format' ); + +// Valid commit message with backticks: +var parsed = { + 'subject': 'feat: add `math/base/special/abs`' +}; +var result = rule( parsed, 'always' ); +console.log( result ); +// => [ true, '' ] + +// Invalid commit message without backticks: +parsed = { + 'subject': 'feat: add math/base/special/abs' +}; +result = rule( parsed, 'always' ); +console.log( result ); +// => [ false, 'Package reference `math/base/special/abs` must be wrapped in backticks.' ] + +// Invalid commit message with @stdlib/ prefix: +parsed = { + 'subject': 'feat: add `@stdlib/math/base/special/abs`' +}; +result = rule( parsed, 'always' ); +console.log( result ); +// => [ false, 'Package references must not include the `@stdlib/` prefix. Use `pkg/path` instead of `@stdlib/pkg/path`.' ] +``` + +
+ + + + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/examples/index.js b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/examples/index.js new file mode 100644 index 000000000000..576580db7796 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/examples/index.js @@ -0,0 +1,69 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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'; + +var rule = require( './../lib' ); + +// Valid commit message with backticks: +var result = rule({ + 'subject': 'feat: add `math/base/special/abs`' +}, 'always' ); +console.log( 'Valid message:' ); +console.log( result ); +// => [ true, '' ] + +console.log( '' ); + +// Invalid commit message without backticks: +result = rule({ + 'subject': 'feat: add math/base/special/abs' +}, 'always' ); +console.log( 'Invalid message (missing backticks):' ); +console.log( result ); +// => [ false, 'Package reference `math/base/special/abs` must be wrapped in backticks.' ] + +console.log( '' ); + +// Invalid commit message with @stdlib/ prefix: +result = rule({ + 'subject': 'feat: add `@stdlib/math/base/special/abs`' +}, 'always' ); +console.log( 'Invalid message (@stdlib/ prefix):' ); +console.log( result ); +// => [ false, 'Package references must not include the `@stdlib/` prefix. Use `pkg/path` instead of `@stdlib/pkg/path`.' ] + +console.log( '' ); + +// Valid commit message without package references: +result = rule({ + 'subject': 'docs: fix typo in README' +}, 'always' ); +console.log( 'Valid message (no package reference):' ); +console.log( result ); +// => [ true, '' ] + +console.log( '' ); + +// Partial path detection: +result = rule({ + 'subject': 'fix: update dists/chi/logpdf' +}, 'always' ); +console.log( 'Invalid message (partial path without backticks):' ); +console.log( result ); +// => [ false, 'Package reference `dists/chi/logpdf` must be wrapped in backticks.' ] diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/index.js b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/index.js new file mode 100644 index 000000000000..790617b53a1e --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/index.js @@ -0,0 +1,43 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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'; + +/** +* Commitlint rule enforcing that stdlib package references use backticks and exclude the `@stdlib/` prefix. +* +* @module @stdlib/_tools/commitlint/rules/package-reference-format +* +* @example +* var rule = require( '@stdlib/_tools/commitlint/rules/package-reference-format' ); +* +* var parsed = { +* 'subject': 'add math/base/special/abs' +* }; +* var result = rule( parsed, 'always' ); +* // returns [ false, 'Package reference `math/base/special/abs` must be wrapped in backticks.' ] +*/ + +// MODULES // + +var main = require( './main.js' ); + + +// EXPORTS // + +module.exports = main; diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/main.js b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/main.js new file mode 100644 index 000000000000..c43d6837c767 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/main.js @@ -0,0 +1,120 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 format = require( '@stdlib/string/format' ); +var NAMESPACE_SEGMENTS = require( './namespace_segments.json' ); + + +// VARIABLES // + +// Pattern to match `@stdlib/` prefix (which should not be used): +var RE_STDLIB_PREFIX = /@stdlib\//g; + +// Pattern to match text inside backticks: +var RE_BACKTICK_CONTENT = /`[^`]+`/g; + +// Pattern to match URLs (to exclude from package path detection): +var RE_URL = /(?:https?|ftp):\/\/[^\s]+/g; + +/* +* Pattern to match potential stdlib package paths. +* +* Matches paths that: +* - Start with a known stdlib namespace segment +* - Have at least 2 segments (e.g., `math/base` or `dists/chi`) +* - Each segment is lowercase alphanumeric with underscores or hyphens +* +* The namespace segments are loaded from a static JSON file generated from +* `@stdlib/_tools/pkgs/namespaces`. To regenerate: +* +* ```bash +* NODE_PATH=lib/node_modules node -e " +* var ns = require('@stdlib/_tools/pkgs/namespaces').sync(); +* var segments = {}; +* ns.forEach(function(n) { +* var parts = n.replace('@stdlib/', '').split('/'); +* parts.forEach(function(p) { if (p.charAt(0) !== '_') segments[p] = true; }); +* }); +* console.log(JSON.stringify(Object.keys(segments).sort(), null, ' ')); +* " > lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/namespace_segments.json +* ``` +*/ +var RE_PKG_PATH = new RegExp( '\\b((?:' + NAMESPACE_SEGMENTS.join( '|' ) + ')(?:\\/[a-z][a-z0-9_-]*)+)\\b', 'g' ); + + +// MAIN // + +/** +* Rule to enforce stdlib package reference format in commit messages. +* +* ## Notes +* +* - Package references must be wrapped in backticks. +* - Package references must NOT include the `@stdlib/` prefix. +* +* @param {Object} parsed - parsed commit +* @param {string} [when='always'] - condition +* @returns {Array} result +*/ +function packageReferenceFormat( parsed, when ) { + var subjectWithoutBackticks; + var messages; + var subject; + var match; + var valid; + var msg; + + if ( when === 'never' ) { + return [ true, '' ]; + } + messages = []; + subject = parsed.subject || ''; + + // Check for @stdlib/ prefix anywhere in the subject: + RE_STDLIB_PREFIX.lastIndex = 0; + if ( RE_STDLIB_PREFIX.test( subject ) ) { + messages.push( 'Package references must not include the `@stdlib/` prefix. Use `pkg/path` instead of `@stdlib/pkg/path`.' ); + } + + // Remove all backtick-enclosed content to find unquoted package paths: + subjectWithoutBackticks = subject.replace( RE_BACKTICK_CONTENT, '' ); + + // Remove URLs to avoid false positives: + subjectWithoutBackticks = subjectWithoutBackticks.replace( RE_URL, '' ); + + // Check for unquoted package paths starting with known stdlib namespace segments: + RE_PKG_PATH.lastIndex = 0; + match = RE_PKG_PATH.exec( subjectWithoutBackticks ); + while ( match !== null ) { + messages.push( format( 'Package reference `%s` must be wrapped in backticks.', match[ 1 ] ) ); + match = RE_PKG_PATH.exec( subjectWithoutBackticks ); + } + + valid = ( messages.length === 0 ); + msg = messages.join( ' ' ); + return [ valid, msg ]; +} + + +// EXPORTS // + +module.exports = packageReferenceFormat; diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/namespace_segments.json b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/namespace_segments.json new file mode 100644 index 000000000000..baeda16053c9 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/lib/namespace_segments.json @@ -0,0 +1,118 @@ +[ + "arcsine", + "array", + "assert", + "async", + "banded", + "base", + "bench", + "bernoulli", + "beta", + "betaprime", + "bigint", + "binomial", + "blas", + "boolean", + "bradford", + "buffer", + "cauchy", + "chi", + "chisquare", + "cli", + "complex", + "complex128", + "complex64", + "console", + "constants", + "cosine", + "datasets", + "degenerate", + "discrete-uniform", + "distances", + "dists", + "dstructs", + "dsv", + "erlang", + "error", + "eslint", + "exponential", + "ext", + "f", + "fast", + "float16", + "float32", + "float64", + "frechet", + "fs", + "function", + "gamma", + "geometric", + "gumbel", + "hypergeometric", + "incr", + "int16", + "int32", + "int8", + "invgamma", + "iter", + "kumaraswamy", + "lapack", + "laplace", + "levy", + "logistic", + "lognormal", + "math", + "ml", + "namespace", + "napi", + "ndarray", + "negative-binomial", + "net", + "nlp", + "node", + "normal", + "number", + "object", + "ops", + "os", + "pareto-type1", + "path", + "planck", + "plot", + "poisson", + "process", + "proxy", + "random", + "rayleigh", + "regexp", + "repl", + "rules", + "sequences", + "signrank", + "simulate", + "slice", + "sparklines", + "special", + "stats", + "streams", + "strided", + "string", + "studentized-range", + "symbol", + "symmetric", + "symmetric-banded", + "t", + "time", + "tools", + "triangular", + "truncated-normal", + "uint16", + "uint32", + "uint8", + "unicode", + "uniform", + "utils", + "vector", + "wasm", + "weibull" +] diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/package.json b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/package.json new file mode 100644 index 000000000000..94d1da9a7de4 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/package.json @@ -0,0 +1,67 @@ +{ + "name": "@stdlib/_tools/commitlint/rules/package-reference-format", + "version": "0.0.0", + "description": "Commitlint rule enforcing that stdlib package references use backticks and exclude the @stdlib/ prefix.", + "license": "Apache-2.0", + "author": { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + }, + "contributors": [ + { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + } + ], + "bin": {}, + "main": "./lib", + "directories": { + "example": "./examples", + "lib": "./lib", + "scripts": "./scripts", + "test": "./test" + }, + "scripts": { + "build": "node scripts/build.js" + }, + "homepage": "https://github.com/stdlib-js/stdlib", + "repository": { + "type": "git", + "url": "git://github.com/stdlib-js/stdlib.git" + }, + "bugs": { + "url": "https://github.com/stdlib-js/stdlib/issues" + }, + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=0.10.0", + "npm": ">2.7.0" + }, + "os": [ + "aix", + "darwin", + "freebsd", + "linux", + "macos", + "openbsd", + "sunos", + "win32", + "windows" + ], + "keywords": [ + "stdlib", + "tools", + "tool", + "commitlint", + "lint", + "custom", + "rules", + "rule", + "plugin", + "commit", + "message", + "package", + "reference" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/scripts/build.js b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/scripts/build.js new file mode 100644 index 000000000000..eefb5258eb35 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/scripts/build.js @@ -0,0 +1,91 @@ +#!/usr/bin/env node + +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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. +*/ + +/** +* Script to regenerate namespace_segments.json from current stdlib namespaces. +* +* ## Usage +* +* ```bash +* node scripts/build.js +* ``` +*/ + +'use strict'; + +/* eslint-disable no-console, node/no-sync */ + +// MODULES // + +var resolve = require( 'path' ).resolve; +var writeFileSync = require( 'fs' ).writeFileSync; +var objectKeys = require( '@stdlib/utils/keys' ); +var namespaces = require( '@stdlib/_tools/pkgs/namespaces' ).sync; + + +// VARIABLES // + +var OUTPUT_PATH = resolve( __dirname, '..', 'lib', 'namespace_segments.json' ); + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var segments; + var names; + var parts; + var json; + var i; + var j; + + console.log( 'Fetching stdlib namespaces...' ); + names = namespaces(); + + console.log( 'Found %d namespaces.', names.length ); + + // Extract unique namespace segments: + segments = {}; + for ( i = 0; i < names.length; i++ ) { + // Remove @stdlib/ prefix and split into segments: + parts = names[ i ].replace( '@stdlib/', '' ).split( '/' ); + for ( j = 0; j < parts.length; j++ ) { + // Exclude internal tools (starting with underscore): + if ( parts[ j ].charAt( 0 ) !== '_' ) { + segments[ parts[ j ] ] = true; + } + } + } + segments = objectKeys( segments ).sort(); + + console.log( 'Extracted %d unique namespace segments.', segments.length ); + + // Write to JSON file: + json = JSON.stringify( segments, null, ' ' ) + '\n'; + writeFileSync( OUTPUT_PATH, json ); + + console.log( 'Written to: %s', OUTPUT_PATH ); +} + +main(); diff --git a/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/test/test.js b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/test/test.js new file mode 100644 index 000000000000..b28e8271a009 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/commitlint/rules/package-reference-format/test/test.js @@ -0,0 +1,174 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 tape = require( 'tape' ); +var contains = require( '@stdlib/assert/contains' ); +var rule = require( './../lib' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof rule, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function returns `[ true, \'\' ]` when the `when` parameter is `never`', function test( t ) { + var result = rule({ + 'subject': 'add math/base/special/abs' + }, 'never' ); + t.deepEqual( result, [ true, '' ], 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns `[ true, \'\' ]` for valid messages with backtick-wrapped package references', function test( t ) { + var subjects; + var result; + var i; + + subjects = [ + 'feat: add `math/base/special/abs`', + 'docs: update `stats/maxabs`', + 'fix: resolve issue in `blas/base/dasum`', + 'feat: add `constants/float16/nan`', + 'docs: update `dists/chi/logpdf`', + 'feat: add `math/base/special/abs` and `math/base/special/sin`' + ]; + for ( i = 0; i < subjects.length; i++ ) { + result = rule({ + 'subject': subjects[ i ] + }, 'always' ); + t.deepEqual( result, [ true, '' ], 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns `[ true, \'\' ]` for messages without package references', function test( t ) { + var subjects; + var result; + var i; + + subjects = [ + 'docs: fix typo in README', + 'chore: update dependencies', + 'fix: resolve memory leak', + 'feat: add new feature', + 'docs: see http://example.com/foo/bar/baz' + ]; + for ( i = 0; i < subjects.length; i++ ) { + result = rule({ + 'subject': subjects[ i ] + }, 'always' ); + t.deepEqual( result, [ true, '' ], 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns `[ false, ... ]` for messages with unquoted package references', function test( t ) { + var subjects; + var result; + var i; + + subjects = [ + 'feat: add math/base/special/abs', + 'docs: update stats/maxabs', + 'feat: add dists/chi/logpdf', + 'fix: update base/special/abs', + 'docs: fix special/abs' + ]; + for ( i = 0; i < subjects.length; i++ ) { + result = rule({ + 'subject': subjects[ i ] + }, 'always' ); + t.strictEqual( result[ 0 ], false, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns `[ false, ... ]` for messages with `@stdlib/` prefix', function test( t ) { + var result = rule({ + 'subject': 'feat: add `@stdlib/math/base/special/abs`' + }, 'always' ); + t.strictEqual( result[ 0 ], false, 'returns expected value' ); + t.ok( contains( result[ 1 ], '@stdlib/' ), 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns `[ false, ... ]` for messages with multiple errors', function test( t ) { + var result = rule({ + 'subject': 'feat: add math/base/special/abs and @stdlib/stats/base' + }, 'always' ); + t.strictEqual( result[ 0 ], false, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns `[ true, \'\' ]` for generic paths not starting with known namespaces', function test( t ) { + var subjects; + var result; + var i; + + subjects = [ + 'docs: update src/lib/utils', + 'fix: resolve issue in foo/bar/baz', + 'chore: update config/settings/main' + ]; + for ( i = 0; i < subjects.length; i++ ) { + result = rule({ + 'subject': subjects[ i ] + }, 'always' ); + t.deepEqual( result, [ true, '' ], 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns `[ true, \'\' ]` for URLs containing namespace-like paths', function test( t ) { + var subjects; + var result; + var i; + + subjects = [ + 'docs: see http://example.com/math/base/special', + 'docs: update https://github.com/stdlib-js/stdlib', + 'docs: link to ftp://files.example.com/stats/data' + ]; + for ( i = 0; i < subjects.length; i++ ) { + result = rule({ + 'subject': subjects[ i ] + }, 'always' ); + t.deepEqual( result, [ true, '' ], 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns `[ true, \'\' ]` for empty or missing subject', function test( t ) { + var result; + + result = rule({ + 'subject': '' + }, 'always' ); + t.deepEqual( result, [ true, '' ], 'returns expected value' ); + + result = rule( {}, 'always' ); + t.deepEqual( result, [ true, '' ], 'returns expected value' ); + t.end(); +});