OverviewFilesCommitsIssuesDocsReleasesPeers

codetree / test / ignore.test.js

116 lines · javascript ref:
import { test } from 'brittle'
import { mkdirSync, writeFileSync, rmSync, existsSync } from 'fs'
import { join, dirname, resolve } from 'path'
import { fileURLToPath } from 'url'
import { buildIgnoreMatcher } from '../lib/ignore.js'

const HERE = dirname(fileURLToPath(import.meta.url))
const FIXTURE = resolve(HERE, 'fixtures-ignore')

function setupFixture () {
  if (existsSync(FIXTURE)) rmSync(FIXTURE, { recursive: true, force: true })
  mkdirSync(FIXTURE, { recursive: true })
  return FIXTURE
}

function mk (root, relPath, content = '') {
  const full = join(root, relPath)
  mkdirSync(dirname(full), { recursive: true })
  writeFileSync(full, content)
  return full
}

test('ignore: built-in defaults skip node_modules/.git/vendor/etc', (t) => {
  const root = setupFixture()
  const ignore = buildIgnoreMatcher(root)

  t.ok(ignore(join(root, 'node_modules')), 'node_modules hidden')
  t.ok(ignore(join(root, 'node_modules/foo/index.js')), 'file under node_modules hidden')
  t.ok(ignore(join(root, '.git/HEAD')), '.git contents hidden')
  t.ok(ignore(join(root, 'vendor')), 'vendor hidden')
  t.ok(ignore(join(root, 'build/output.js')), 'build hidden')
  t.absent(ignore(join(root, 'src/index.js')), 'src/ not hidden')

  rmSync(root, { recursive: true, force: true })
})

test('ignore: .codetreeignore file at rootDir', (t) => {
  const root = setupFixture()
  mk(root, '.codetreeignore', '# comment line\nsecrets\nclients/*.key\nbackup/\n')
  const ignore = buildIgnoreMatcher(root)

  t.ok(ignore(join(root, 'secrets')), 'pattern "secrets" hides dir')
  t.ok(ignore(join(root, 'foo/secrets/bar.txt')), 'name pattern matches at any depth')
  t.ok(ignore(join(root, 'clients/acme.key')), 'glob pattern works')
  t.ok(ignore(join(root, 'backup')), 'trailing-slash dir pattern')
  t.absent(ignore(join(root, 'public/index.html')), 'unrelated path not hidden')
  t.absent(ignore(join(root, 'clients/readme.md')), 'non-matching glob not hidden')

  rmSync(root, { recursive: true, force: true })
})

test('ignore: .codetree-private marker hides whole subtree', (t) => {
  const root = setupFixture()
  mk(root, 'public/foo.js')
  mk(root, 'private-work/.codetree-private')
  mk(root, 'private-work/src/secret.js')
  mk(root, 'private-work/docs/plan.md')

  const ignore = buildIgnoreMatcher(root)

  t.absent(ignore(join(root, 'public/foo.js')), 'public path visible')
  t.ok(ignore(join(root, 'private-work')), 'marked dir itself hidden')
  t.ok(ignore(join(root, 'private-work/src/secret.js')), 'file deep under marker hidden')
  t.ok(ignore(join(root, 'private-work/docs/plan.md')), 'another file deep under marker hidden')

  rmSync(root, { recursive: true, force: true })
})

test('ignore: --ignore flag patterns', (t) => {
  const root = setupFixture()
  const ignore = buildIgnoreMatcher(root, ['my-custom', 'tmp-*'])

  t.ok(ignore(join(root, 'my-custom')), 'extra pattern applied')
  t.ok(ignore(join(root, 'some/path/my-custom')), 'extra pattern matches at any depth')
  t.ok(ignore(join(root, 'tmp-scratch')), 'glob in extra pattern works')
  t.absent(ignore(join(root, 'normal')), 'unrelated not hidden')

  rmSync(root, { recursive: true, force: true })
})

test('ignore: .codetreeignore + --ignore stack', (t) => {
  const root = setupFixture()
  mk(root, '.codetreeignore', 'from-file\n')
  const ignore = buildIgnoreMatcher(root, ['from-flag'])

  t.ok(ignore(join(root, 'from-file')), 'file pattern applied')
  t.ok(ignore(join(root, 'from-flag')), 'flag pattern applied')
  t.ok(ignore(join(root, 'node_modules')), 'built-in still applied')

  rmSync(root, { recursive: true, force: true })
})

test('ignore: anchored / pattern matches only at root', (t) => {
  const root = setupFixture()
  mk(root, '.codetreeignore', '/top-only\n')
  const ignore = buildIgnoreMatcher(root)

  t.ok(ignore(join(root, 'top-only')), 'anchored matches at root')
  t.ok(ignore(join(root, 'top-only/child.js')), 'contents under anchored also hidden')
  t.absent(ignore(join(root, 'nested/top-only')), 'anchored does NOT match deeper')

  rmSync(root, { recursive: true, force: true })
})

test('ignore: comments and blank lines in .codetreeignore', (t) => {
  const root = setupFixture()
  mk(root, '.codetreeignore', '# this is a comment\n\n  \nlegit\n')
  const ignore = buildIgnoreMatcher(root)

  t.ok(ignore(join(root, 'legit')), 'valid pattern applied')
  t.absent(ignore(join(root, '# this is a comment')), 'comments not treated as patterns')
  t.absent(ignore(join(root, 'unrelated')), 'unrelated not hidden')

  rmSync(root, { recursive: true, force: true })
})