New Upstream Release - node-ignore

Ready changes

Summary

Merged new upstream version: 5.2.4 (was: 5.2.1).

Resulting package

Built on 2023-02-08T02:52 (took 3m36s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases node-ignore

Lintian Result

Diff

diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..8b5dce8
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # kaelzhang
+open_collective: node-ignore
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
new file mode 100644
index 0000000..bc6fc65
--- /dev/null
+++ b/.github/workflows/nodejs.yml
@@ -0,0 +1,26 @@
+name: build
+
+on: [push]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        node-version: [12.x, 14.x, 16.x]
+
+    steps:
+    - uses: actions/checkout@v1
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+    - name: npm install, build, and test
+      run: |
+        npm install
+        npm run build --if-present
+        npm test
+      env:
+        CI: true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a1a0f3d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,61 @@
+# test
+test/ts/*.js
+
+# coverage
+coverage
+.nyc_output
+/legacy.js
+
+# yarn
+*.lock
+
+# php files
+index.php
+
+# Numerous always-ignore extensions
+*.bak
+*.patch
+*.diff
+*.err
+*.orig
+*.log
+*.rej
+*.swo
+*.swp
+*.zip
+*.vi
+*~
+*.sass-cache
+package-lock.json
+
+# npm package
+*.tgz
+
+# OS or Editor folders
+.DS_Store
+._*
+.cache
+.project
+.settings
+.tmproj
+*.esproj
+*.sublime-project
+nbproject
+thumbs.db
+*.*-workspace
+
+# Folders to ignore
+.hg
+.svn
+.CVS
+.idea
+node_modules
+old/
+*-old/
+*-notrack/
+no-track/
+build/
+combo/
+reference/
+jscoverage_lib/
+temp/
diff --git a/README.md b/README.md
index aa814e7..50d8882 100644
--- a/README.md
+++ b/README.md
@@ -8,9 +8,9 @@
   </tr>
 </thead><tbody><tr>
   <td colspan="2" align="center">
-    <a href="https://travis-ci.org/kaelzhang/node-ignore">
+    <a href="https://github.com/kaelzhang/node-ignore/actions/workflows/nodejs.yml">
     <img
-      src="https://travis-ci.org/kaelzhang/node-ignore.svg?branch=master"
+      src="https://github.com/kaelzhang/node-ignore/actions/workflows/nodejs.yml/badge.svg"
       alt="Build Status" /></a>
   </td>
   <td align="center">
diff --git a/appveyor.yml b/appveyor.yml
index 1b20e1c..3083318 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -16,7 +16,7 @@ test_script:
   - node --version
   - npm --version
   # run tests
-  - npm run test:only
+  - npm run test:no-coverage
 
 # Don't actually build.
-build: off
+build: false
diff --git a/debian/changelog b/debian/changelog
index 6652d24..507b9e6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+node-ignore (5.2.4-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 08 Feb 2023 02:49:39 -0000
+
 node-ignore (5.2.1-1) unstable; urgency=medium
 
   * Team upload
diff --git a/index.js b/index.js
index d935eb1..a25577f 100644
--- a/index.js
+++ b/index.js
@@ -9,6 +9,7 @@ const EMPTY = ''
 const SPACE = ' '
 const ESCAPE = '\\'
 const REGEX_TEST_BLANK_LINE = /^\s+$/
+const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/
 const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/
 const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/
 const REGEX_SPLITALL_CRLF = /\r?\n/g
@@ -20,10 +21,14 @@ const REGEX_SPLITALL_CRLF = /\r?\n/g
 const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/
 
 const SLASH = '/'
-const KEY_IGNORE = typeof Symbol !== 'undefined'
-  ? Symbol.for('node-ignore')
-  /* istanbul ignore next */
-  : 'node-ignore'
+
+// Do not use ternary expression here, since "istanbul ignore next" is buggy
+let TMP_KEY_IGNORE = 'node-ignore'
+/* istanbul ignore else */
+if (typeof Symbol !== 'undefined') {
+  TMP_KEY_IGNORE = Symbol.for('node-ignore')
+}
+const KEY_IGNORE = TMP_KEY_IGNORE
 
 const define = (object, key, value) =>
   Object.defineProperty(object, key, {value})
@@ -190,18 +195,27 @@ const REPLACERS = [
       : '\\/.+'
   ],
 
-  // intermediate wildcards
+  // normal intermediate wildcards
   [
     // Never replace escaped '*'
     // ignore rule '\*' will match the path '*'
 
     // 'abc.*/' -> go
-    // 'abc.*'  -> skip this rule
-    /(^|[^\\]+)\\\*(?=.+)/g,
+    // 'abc.*'  -> skip this rule,
+    //    coz trailing single wildcard will be handed by [trailing wildcard]
+    /(^|[^\\]+)(\\\*)+(?=.+)/g,
 
     // '*.js' matches '.js'
     // '*.js' doesn't match 'abc'
-    (_, p1) => `${p1}[^\\/]*`
+    (_, p1, p2) => {
+      // 1.
+      // > An asterisk "*" matches anything except a slash.
+      // 2.
+      // > Other consecutive asterisks are considered regular asterisks
+      // > and will match according to the previous rules.
+      const unescaped = p2.replace(/\\\*/g, '[^\\/]*')
+      return p1 + unescaped
+    }
   ],
 
   [
@@ -312,6 +326,7 @@ const isString = subject => typeof subject === 'string'
 const checkPattern = pattern => pattern
   && isString(pattern)
   && !REGEX_TEST_BLANK_LINE.test(pattern)
+  && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)
 
   // > A line starting with # serves as a comment.
   && pattern.indexOf('#') !== 0
@@ -577,7 +592,7 @@ module.exports = factory
 
 // Windows
 // --------------------------------------------------------------
-/* istanbul ignore if  */
+/* istanbul ignore if */
 if (
   // Detect `process` so that it can run in browsers.
   typeof process !== 'undefined'
diff --git a/package.json b/package.json
index 365d713..fe5498d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "ignore",
-  "version": "5.2.1",
+  "version": "5.2.4",
   "description": "Ignore is a manager and filter for .gitignore rules, the one used by eslint, gitbook and many others.",
   "files": [
     "legacy.js",
@@ -19,10 +19,12 @@
     "test:ignore": "npm run tap test/ignore.js",
     "test:others": "npm run tap test/others.js",
     "test:cases": "npm run tap test/*.js -- --coverage",
+    "test:no-coverage": "npm run tap test/*.js -- --no-check-coverage",
     "test:only": "npm run test:lint && npm run test:tsc && npm run test:ts && npm run test:cases",
     "test": "npm run test:only",
     "test:win32": "IGNORE_TEST_WIN32=1 npm run test",
-    "posttest": "tap --coverage-report=html && codecov"
+    "report": "tap --coverage-report=html",
+    "posttest": "npm run report && codecov"
   },
   "repository": {
     "type": "git",
@@ -49,21 +51,21 @@
     "url": "https://github.com/kaelzhang/node-ignore/issues"
   },
   "devDependencies": {
-    "@babel/cli": "^7.8.4",
-    "@babel/core": "^7.9.6",
-    "@babel/preset-env": "^7.9.6",
-    "codecov": "^3.7.0",
-    "debug": "^4.1.1",
-    "eslint": "^7.0.0",
+    "@babel/cli": "^7.19.3",
+    "@babel/core": "^7.20.5",
+    "@babel/preset-env": "^7.20.2",
+    "codecov": "^3.8.2",
+    "debug": "^4.3.4",
+    "eslint": "^8.30.0",
     "eslint-config-ostai": "^3.0.0",
-    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-import": "^2.26.0",
     "mkdirp": "^1.0.4",
     "pre-suf": "^1.1.1",
     "rimraf": "^3.0.2",
     "spawn-sync": "^2.0.0",
-    "tap": "^14.10.7",
+    "tap": "^16.3.2",
     "tmp": "0.2.1",
-    "typescript": "^3.9.3"
+    "typescript": "^4.9.4"
   },
   "engines": {
     "node": ">= 4"
diff --git a/test/fixtures/cases.js b/test/fixtures/cases.js
index 4f75246..09e6336 100644
--- a/test/fixtures/cases.js
+++ b/test/fixtures/cases.js
@@ -22,6 +22,39 @@ const cases = [
   //   }
   // ],
   /////////////////////////////////////////////////////////////////////
+  [
+    'charactor ?',
+    [
+      'foo?bar'
+    ],
+    {
+      'foo/bar': 0,
+      'fooxbar': 1,
+      'fooxxbar': 0
+    }
+  ],
+  [
+    '#57, normal * and normal consecutive *',
+    [
+      '**foo',
+      '*bar',
+      'ba*z',
+      'folder/other-folder/**/**js'
+    ],
+    {
+      'foo': 1,
+      'a/foo': 1,
+      'afoo': 1,
+      'abfoo': 1,
+      'abcfoo': 1,
+      'bar': 1,
+      'abar': 1,
+      'baz': 1,
+      'ba/z': 0,
+      'baaaaaaz': 1,
+      'folder/other-folder/dir/main.js': 1
+    }
+  ],
   [
     '#76 (invalid), comments with no heading whitespace',
     [
@@ -911,6 +944,24 @@ const cases = [
 const IS_WINDOWS = process.platform === 'win32'
 if (!IS_WINDOWS && !process.env.IGNORE_TEST_WIN32) {
   cases.push(
+    [
+      '#81: invalid trailing backslash at the end should not throw, test non-windows env only',
+      [
+        'test\\',
+        'testa\\\\',
+        '\\',
+        'foo/*',
+        // test negative pattern
+        '!foo/test\\'
+      ],
+      {
+        'test': 0,
+        'test\\': 0,
+        'testa\\': 1,
+        '\\': 0,
+        'foo/test\\': 1
+      }
+    ],
     [
       'linux: back slashes on paths',
       [
@@ -974,12 +1025,13 @@ const real_cases = cases_to_test_only.length
   : cases
 
 exports.cases = iteratee => {
-  real_cases.forEach(c => {
-    const description = c[0]
-    const patterns = c[1]
-    const paths_object = c[2]
-    const skip_test_fixture = c[4]
-
+  real_cases.forEach(([
+    description,
+    patterns,
+    paths_object,
+    test_only,
+    skip_test_fixture
+  ]) => {
     // All paths to test
     const paths = Object.keys(paths_object)
 
@@ -993,13 +1045,14 @@ exports.cases = iteratee => {
         expected = expected.map(mapper)
       }
 
-      t.deepEqual(result.sort(), expected.sort())
+      t.same(result.sort(), expected.sort())
     }
 
     iteratee({
       description,
       patterns,
       paths_object,
+      test_only,
       skip_test_fixture,
       paths,
       expected,
diff --git a/test/git-check-ignore.js b/test/git-check-ignore.js
index ccd1716..19d05c7 100644
--- a/test/git-check-ignore.js
+++ b/test/git-check-ignore.js
@@ -1,4 +1,4 @@
-const {test} = require('tap')
+const tap = require('tap')
 const spawn = require('spawn-sync')
 const tmp = require('tmp').dirSync
 const mkdirp = require('mkdirp').sync
@@ -13,6 +13,11 @@ const {
   IS_WINDOWS
 } = require('./fixtures/cases')
 
+const {test} = tap
+
+// This test file is related to dealing with file systems which takes time
+tap.setTimeout(600000)
+
 const touch = (root, file, content) => {
   const dirs = file.split('/')
   const basename = dirs.pop()
diff --git a/test/ignore.js b/test/ignore.js
index dfdbe89..fcf1db4 100755
--- a/test/ignore.js
+++ b/test/ignore.js
@@ -1,4 +1,7 @@
-const {test} = require('tap')
+const {
+  test,
+  only
+} = require('tap')
 
 const ignore = require('..')
 const {
@@ -13,11 +16,16 @@ cases(({
   description,
   patterns,
   paths_object,
+  test_only,
   paths,
   expect_result
 }) => {
+  const tt = test_only
+    ? only
+    : test
+
   checkEnv('IGNORE_ONLY_FILTER')
-  && test(`.filter():        ${description}`, t => {
+  && tt(`.filter():        ${description}`, t => {
     const ig = ignore()
     const result = ig
     .addPattern(patterns)
@@ -28,7 +36,7 @@ cases(({
   })
 
   checkEnv('IGNORE_ONLY_CREATE_FILTER')
-  && test(`.createFilter():  ${description}`, t => {
+  && tt(`.createFilter():  ${description}`, t => {
     const result = paths.filter(
       ignore()
       .addPattern(patterns)
@@ -42,11 +50,11 @@ cases(({
   })
 
   checkEnv('IGNORE_ONLY_IGNORES')
-  && test(`.ignores(path):   ${description}`, t => {
+  && tt(`.ignores(path):   ${description}`, t => {
     const ig = ignore().addPattern(patterns)
 
     Object.keys(paths_object).forEach(path => {
-      t.is(ig.ignores(path), !!paths_object[path], `path: "${path}"`)
+      t.equal(ig.ignores(path), !!paths_object[path], `path: "${path}"`)
     })
     t.end()
   })
@@ -56,7 +64,7 @@ cases(({
   }
 
   checkEnv('IGNORE_ONLY_WIN32')
-  && test(`win32: .filter(): ${description}`, t => {
+  && tt(`win32: .filter(): ${description}`, t => {
     const win_paths = paths.map(make_win32)
 
     const ig = ignore()
diff --git a/test/others.js b/test/others.js
index f317a70..2411b00 100644
--- a/test/others.js
+++ b/test/others.js
@@ -26,8 +26,8 @@ _test('.add(<Ignore>)', t => {
     '.abc/e/e.js'   // included by b, filtered out by a
   ]
 
-  t.deepEqual(a.filter(paths), ['.abc/d/e.js'])
-  t.deepEqual(b.filter(paths), ['.abc/d/e.js', '.abc/e/e.js'])
+  t.same(a.filter(paths), ['.abc/d/e.js'])
+  t.same(b.filter(paths), ['.abc/d/e.js', '.abc/e/e.js'])
   t.end()
 })
 
@@ -41,7 +41,7 @@ _test('fixes babel class', t => {
     return
   }
 
-  t.is('there should be an error', 'no error found')
+  t.equal('there should be an error', 'no error found')
   t.end()
 })
 
@@ -67,8 +67,8 @@ _test('#32', t => {
     '.abc/e/e.js'   // included by b, filtered out by a
   ]
 
-  t.deepEqual(a.filter(paths), ['.abc/d/e.js'])
-  t.deepEqual(b.filter(paths), ['.abc/d/e.js', '.abc/e/e.js'])
+  t.same(a.filter(paths), ['.abc/d/e.js'])
+  t.same(b.filter(paths), ['.abc/d/e.js', '.abc/e/e.js'])
   t.end()
 })
 
@@ -79,9 +79,9 @@ _test('options.ignorecase', t => {
 
   ig.add('*.[jJ][pP]g')
 
-  t.is(ig.ignores('a.jpg'), true)
-  t.is(ig.ignores('a.JPg'), true)
-  t.is(ig.ignores('a.JPG'), false)
+  t.equal(ig.ignores('a.jpg'), true)
+  t.equal(ig.ignores('a.JPg'), true)
+  t.equal(ig.ignores('a.JPG'), false)
   t.end()
 })
 
@@ -94,7 +94,7 @@ _test('special case: internal cache respects ignorecase', t => {
 
   ig.add(rule)
 
-  t.is(ig.ignores('a.JPG'), false)
+  t.equal(ig.ignores('a.JPG'), false)
 
   const ig2 = ignore({
     ignorecase: true
@@ -102,7 +102,7 @@ _test('special case: internal cache respects ignorecase', t => {
 
   ig2.add(rule)
 
-  t.is(ig2.ignores('a.JPG'), true)
+  t.equal(ig2.ignores('a.JPG'), true)
 
   t.end()
 })
@@ -164,7 +164,7 @@ _test('isPathValid', t => {
     )
   }
 
-  t.deepEqual(
+  t.same(
     paths.filter(isPathValid),
     [
       'foo'
@@ -220,7 +220,7 @@ IGNORE_TEST_CASES.forEach(([d, patterns, path, [ignored, unignored]]) => {
       ig.add(patterns)
     }
 
-    t.deepEqual(ig.test(path), {
+    t.same(ig.test(path), {
       ignored, unignored
     })
 
@@ -235,7 +235,7 @@ _test('options.allowRelativePaths', t => {
 
   ig.add('foo')
 
-  t.is(ig.ignores('../foo/bar.js'), true)
+  t.equal(ig.ignores('../foo/bar.js'), true)
 
   t.throws(() => ignore().ignores('../foo/bar.js'))
 

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details