replace jsdoc/src/filter and jsdoc/src/scanner

Plus some semi-related cleanup.
This commit is contained in:
Jeff Williams 2019-02-02 14:42:20 -08:00
parent 85cbed9c0c
commit 32f8aed805
27 changed files with 359 additions and 464 deletions

14
cli.js
View File

@ -266,21 +266,21 @@ module.exports = (() => {
// TODO: docs
cli.scanFiles = () => {
const Filter = require('jsdoc/src/filter').Filter;
const Scanner = require('jsdoc/src/scanner').Scanner;
const makeFilter = require('@jsdoc/util/lib/path').makeFilter;
const walkSync = require('@jsdoc/util/lib/fs').walkSync;
let filter;
let scanner;
env.opts._ = buildSourceList();
// are there any files to scan and parse?
if (env.conf.source && env.opts._.length) {
filter = new Filter(env.conf.source);
scanner = new Scanner();
filter = makeFilter(env.conf.source);
env.sourceFiles = scanner.scan(env.opts._,
(env.opts.recurse ? env.conf.source.maxDepth : undefined), filter);
env.sourceFiles = walkSync(env.opts._, {
depth: env.opts.recurse ? env.conf.source.maxDepth : undefined,
filter: filter
});
}
return cli;

View File

@ -1,6 +1,6 @@
// TODO: docs
/** @module jsdoc/src/astnode */
const cast = require('@jsdoc/util').cast;
const cast = require('@jsdoc/util/lib/cast');
const env = require('jsdoc/env');
const name = require('jsdoc/name');
const Syntax = require('@jsdoc/syntax');

View File

@ -1,63 +0,0 @@
/**
* @module jsdoc/src/filter
*/
const env = require('jsdoc/env');
const path = require('path');
function makeRegExp(config) {
let regExp = null;
if (config) {
regExp = (typeof config === 'string') ? new RegExp(config) : config;
}
return regExp;
}
/**
* @alias module:jsdoc/src/filter.Filter
*/
class Filter {
/**
* @param {Object} opts
* @param {string[]} opts.exclude - Specific files to exclude.
* @param {(string|RegExp)} opts.includePattern
* @param {(string|RegExp)} opts.excludePattern
*/
constructor({exclude, includePattern, excludePattern}) {
this.exclude = exclude && Array.isArray(exclude) ?
exclude.map($ => path.resolve(env.pwd, $)) :
null;
this.includePattern = makeRegExp(includePattern);
this.excludePattern = makeRegExp(excludePattern);
}
/**
* @param {string} filepath - The filepath to check.
* @returns {boolean} Should the given file be included?
*/
isIncluded(filepath) {
let included = true;
filepath = path.resolve(env.pwd, filepath);
if ( this.includePattern && !this.includePattern.test(filepath) ) {
included = false;
}
if ( this.excludePattern && this.excludePattern.test(filepath) ) {
included = false;
}
if (this.exclude) {
this.exclude.forEach(exclude => {
if ( filepath.indexOf(exclude) === 0 ) {
included = false;
}
});
}
return included;
}
}
exports.Filter = Filter;

View File

@ -1,62 +0,0 @@
/**
* @module jsdoc/src/scanner
*/
const EventEmitter = require('events').EventEmitter;
const env = require('jsdoc/env');
const fs = require('fs');
const ls = require('@jsdoc/util').fs.ls;
const logger = require('@jsdoc/logger');
const path = require('path');
/**
* @extends module:events.EventEmitter
*/
class Scanner extends EventEmitter {
constructor() {
super();
}
/**
* Recursively searches the given searchPaths for js files.
* @param {Array.<string>} searchPaths
* @param {number} [depth]
* @fires sourceFileFound
*/
scan(searchPaths = [], depth = 1, filter) {
let currentFile;
let filePaths = [];
searchPaths.forEach($ => {
const filepath = path.resolve( env.pwd, decodeURIComponent($) );
try {
currentFile = fs.statSync(filepath);
}
catch (e) {
logger.error('Unable to find the source file or directory %s', filepath);
return;
}
if ( currentFile.isFile() ) {
filePaths.push(filepath);
}
else {
filePaths = filePaths.concat( ls(filepath, { depth: depth }) );
}
});
filePaths = filePaths.filter($ => filter.isIncluded($));
filePaths = filePaths.filter($ => {
const e = { fileName: $ };
this.emit('sourceFileFound', e);
return !e.defaultPrevented;
});
return filePaths;
}
}
exports.Scanner = Scanner;

View File

@ -3,7 +3,7 @@
* @module jsdoc/tag/dictionary/definitions
*/
const _ = require('lodash');
const commonPrefix = require('@jsdoc/util').path.commonPrefix;
const commonPrefix = require('@jsdoc/util/lib/path').commonPrefix;
const jsdoc = {
env: require('jsdoc/env'),
name: require('jsdoc/name'),

View File

@ -1,7 +1,7 @@
/**
* @module jsdoc/tag/type
*/
const cast = require('@jsdoc/util').cast;
const cast = require('@jsdoc/util/lib/cast');
const catharsis = require('catharsis');
const jsdoc = {
name: require('jsdoc/name'),

View File

@ -4,7 +4,7 @@
const env = require('jsdoc/env');
const fs = require('fs');
const logger = require('@jsdoc/logger');
const ls = require('@jsdoc/util').fs.ls;
const lsSync = require('@jsdoc/util/lib/fs').lsSync;
const path = require('path');
const stripBom = require('strip-bom');
const tutorial = require('jsdoc/tutorial');
@ -98,7 +98,7 @@ exports.addTutorial = current => {
exports.load = filepath => {
let content;
let current;
const files = ls(filepath, {
const files = lsSync(filepath, {
depth: env.opts.recurse ? env.conf.source.maxDepth : 0
});
let name;

1
package-lock.json generated
View File

@ -335,6 +335,7 @@
"@jsdoc/template-original": {
"version": "file:packages/jsdoc-template-original",
"requires": {
"@jsdoc/logger": "file:packages/jsdoc-logger",
"@jsdoc/util": "file:packages/jsdoc-util",
"code-prettify": "^0.1.0",
"color-themes-for-google-code-prettify": "^2.0.4",

View File

@ -3,7 +3,7 @@
*/
const _ = require('lodash');
const cast = require('@jsdoc/util').cast;
const cast = require('@jsdoc/util/lib/cast');
const querystring = require('querystring');
const yargs = require('yargs-parser');

View File

@ -1,10 +1,10 @@
const _ = require('lodash');
const commonPrefix = require('@jsdoc/util').path.commonPrefix;
const commonPrefix = require('@jsdoc/util/lib/path').commonPrefix;
const env = require('jsdoc/env');
const fs = require('fs');
const helper = require('jsdoc/util/templateHelper');
const logger = require('@jsdoc/logger');
const ls = require('@jsdoc/util').fs.ls;
const lsSync = require('@jsdoc/util/lib/fs').lsSync;
const mkdirpSync = require('mkdirp').sync;
const path = require('path');
const taffy = require('taffydb').taffy;
@ -522,7 +522,7 @@ exports.publish = ({doclets, tutorials}, opts) => {
// copy the template's built-in static files to outdir
fromDir = path.join(templatePath, 'static');
staticFiles = ls(fromDir);
staticFiles = lsSync(fromDir);
staticFiles.forEach(fileName => {
const toPath = sourceToDestination(fromDir, fileName, outdir);
@ -532,7 +532,7 @@ exports.publish = ({doclets, tutorials}, opts) => {
});
// copy the fonts used by the template to outdir
staticFiles = ls(path.join(templatePath, 'node_modules/open-sans-fonts/open-sans'));
staticFiles = lsSync(path.join(templatePath, 'node_modules/open-sans-fonts/open-sans'));
staticFiles.forEach(fileName => {
const toPath = path.join(outdir, 'fonts', path.basename(fileName));

View File

@ -1,13 +0,0 @@
/**
* @module @jsdoc/util
*/
const cast = require('./lib/cast');
const fs = require('./lib/fs');
const path = require('./lib/path');
module.exports = {
cast: cast,
fs: fs,
path: path
};

39
packages/jsdoc-util/lib/fs.js Normal file → Executable file
View File

@ -3,17 +3,44 @@
*/
const _ = require('lodash');
const fs = require('fs');
const klaw = require('klaw-sync');
const path = require('path');
exports.ls = ((dir, opts = {}) => {
const walkSync = exports.walkSync = (filepaths, opts = {}) => {
const depth = _.has(opts, 'depth') ? opts.depth : -1;
let filter;
let found = [];
const files = klaw(dir, {
depthLimit: depth,
filter: (f => !path.basename(f.path).startsWith('.')),
nodir: true
if (typeof filepaths === 'string') {
filepaths = [filepaths];
}
if (typeof opts.filter === 'function') {
filter = f => opts.filter.call(null, f.path);
}
filepaths.forEach(f => {
f = path.resolve(f);
if (fs.statSync(f).isFile()) {
found.push({ path: f });
} else {
found = found.concat(
klaw(f, {
depthLimit: depth,
filter: filter,
nodir: true
})
);
}
});
return files.map(f => f.path);
return found.map(f => f.path);
};
exports.lsSync = (dir, opts = {}) => walkSync(dir, {
depth: opts.depth,
filter: (f => !path.basename(f).startsWith('.')),
nodir: true
});

91
packages/jsdoc-util/lib/path.js Normal file → Executable file
View File

@ -1,4 +1,6 @@
/**
* Utility methods for working with filepaths.
*
* @module @jsdoc/util/lib/path
*/
@ -7,7 +9,7 @@ const path = require('path');
function prefixReducer({cwd, previousPath}, current) {
let currentPath;
// if previousPath is a zero-length array, there's no common prefix; move along
// If previousPath is a zero-length array, there's no common prefix.
if (Array.isArray(previousPath) && !previousPath.length) {
return previousPath;
}
@ -15,10 +17,10 @@ function prefixReducer({cwd, previousPath}, current) {
currentPath = path.resolve(cwd, current).split(path.sep) || [];
if (previousPath && currentPath.length) {
// remove chunks that exceed the previous path's length
// Remove chunks that exceed the previous path's length.
currentPath = currentPath.slice(0, previousPath.length);
// if a chunk doesn't match the previous path, remove everything from that chunk on
// If a chunk doesn't match the previous path, remove that chunk and the following chunks.
for (let i = 0, l = currentPath.length; i < l; i++) {
if (currentPath[i] !== previousPath[i]) {
currentPath.splice(i, currentPath.length - i);
@ -70,3 +72,86 @@ exports.commonPrefix = (paths = []) => {
return segments.join(path.sep);
};
/**
* A filter function that is compatible with `Array#map` and similar functions.
*
* @typedef module:@jsdoc/util/lib/path~filter
* @type {function}
* @param {string} filepath - The filepath to test. The filter function resolves the filepath,
* relative to the current working directory, before testing it.
* @returns {boolean} `true` if the filepath meets the conditions of the filter, or `false` if the
* filepath does not meet the conditions.
*/
function makeRegExp(value) {
let regExp = null;
if (typeof value === 'string') {
regExp = new RegExp(value);
} else if (value instanceof RegExp) {
regExp = value;
} else if (value !== undefined) {
throw new TypeError(`Expected string or RegExp, got ${typeof value}`);
}
return regExp;
}
/**
* Create a function that filters filepaths and is suitable for use with methods such as
* {@link Array#filter}. The filter is based on the following inputs:
*
* + An include pattern (a regular expression that matches filepaths that should pass the filter)
* + An exclude pattern (a regular expression that matches filepaths that should not pass the
* filter)
* + An exclude list (an array of values that, if present at the end of a filepath, will always
* cause that filepath to be excluded)
*
* The filter function resolves the filepath, relative to the current working directory, before
* testing it.
*
* @param {Object} opts - Options for the filter function.
* @param {(Array<string>|string)} [opts.exclude] - An array of values (or a single value) that, if
* present at the end of a filepath, will always cause that filepath to be excluded.
* @param {(string|RegExp)} [opts.excludePattern] - A regular expression that matches filepaths to
* exclude, or a string that represents a valid regular expression.
* @param {(string|RegExp)} [opts.includePattern] - A regular expression that matches filepaths to
* include, or a string that represents a valid regular expression.
* @returns {module:@jsdoc/util/lib/path~filter} The filter function.
*/
exports.makeFilter = (({exclude, excludePattern, includePattern}) => {
const cwd = process.cwd();
const excludeRegExp = makeRegExp(excludePattern);
const includeRegExp = makeRegExp(includePattern);
if (typeof exclude === 'string') {
exclude = [exclude];
} else if (exclude !== undefined && exclude !== null && !Array.isArray(exclude)) {
throw new TypeError(`Expected array or string for opts.exclude, got ${typeof exclude}`);
}
return (filepath => {
let included = true;
filepath = path.resolve(cwd, filepath);
if (includeRegExp && !includeRegExp.test(filepath)) {
included = false;
}
if (excludeRegExp && excludeRegExp.test(filepath)) {
included = false;
}
if (exclude && included) {
exclude.forEach(value => {
if (included && filepath.endsWith(value)) {
included = false;
}
});
}
return included;
});
});

0
packages/jsdoc-util/package-lock.json generated Normal file → Executable file
View File

1
packages/jsdoc-util/package.json Normal file → Executable file
View File

@ -2,7 +2,6 @@
"name": "@jsdoc/util",
"version": "1.0.0",
"description": "Utility modules for JSDoc.",
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/jsdoc3/jsdoc"

View File

@ -1,43 +0,0 @@
describe('@jsdoc/util', () => {
const util = require('../..');
it('is an object', () => {
expect(util).toBeObject();
});
it('has a cast method', () => {
expect(util.cast).toBeFunction();
});
it('has an fs object', () => {
expect(util.fs).toBeObject();
});
it('has a path object', () => {
expect(util.path).toBeObject();
});
describe('cast', () => {
it('is ./lib/cast', () => {
const cast = require('../../lib/cast');
expect(util.cast).toBe(cast);
});
});
describe('fs', () => {
it('is ./lib/fs', () => {
const fs = require('../../lib/fs');
expect(util.fs).toBe(fs);
});
});
describe('path', () => {
it('is ./lib/path', () => {
const path = require('../../lib/path');
expect(util.path).toBe(path);
});
});
});

4
packages/jsdoc-util/test/specs/lib/cast.js Normal file → Executable file
View File

@ -1,6 +1,6 @@
const cast = require('../../../lib/cast');
describe('@jsdoc/util/lib/cast', () => {
const cast = require('../../../lib/cast');
it('exists', () => {
expect(cast).toBeFunction();
});

112
packages/jsdoc-util/test/specs/lib/fs.js Normal file → Executable file
View File

@ -3,39 +3,43 @@ describe('@jsdoc/util/lib/fs', () => {
const fsUtil = require('../../../lib/fs');
const path = require('path');
afterEach(() => mockFs.restore());
const cwd = process.cwd();
it('has an ls method', () => {
expect(fsUtil.ls).toBeFunction();
});
function resolvePaths(files) {
return files.map(f => path.join(cwd, f)).sort();
}
describe('ls', () => {
beforeEach(() => {
mockFs({
head: {
eyes: '',
ears: '',
mouth: '',
nose: '',
shoulders: {
knees: {
meniscus: '',
toes: {
phalanx: '',
'.big-toe-phalanx': ''
}
beforeEach(() => {
mockFs({
head: {
eyes: '',
ears: '',
mouth: '',
nose: '',
shoulders: {
knees: {
meniscus: '',
toes: {
phalanx: '',
'.big-toe-phalanx': ''
}
}
}
});
}
});
});
const cwd = process.cwd();
afterEach(() => mockFs.restore());
function resolvePaths(files) {
return files.map(f => path.join(cwd, f)).sort();
}
it('has an lsSync method', () => {
expect(fsUtil.lsSync).toBeFunction();
});
it('has a walkSync method', () => {
expect(fsUtil.walkSync).toBeFunction();
});
describe('lsSync', () => {
const allFiles = resolvePaths([
'head/eyes',
'head/ears',
@ -46,13 +50,13 @@ describe('@jsdoc/util/lib/fs', () => {
]);
it('gets all non-hidden files from all levels by default', () => {
const files = fsUtil.ls(cwd).sort();
const files = fsUtil.lsSync(cwd).sort();
expect(files).toEqual(allFiles);
});
it('limits recursion depth when asked', () => {
const files = fsUtil.ls(cwd, { depth: 1 }).sort();
const files = fsUtil.lsSync(cwd, { depth: 1 }).sort();
expect(files).toEqual(resolvePaths([
'head/eyes',
@ -63,9 +67,63 @@ describe('@jsdoc/util/lib/fs', () => {
});
it('treats a depth of -1 as infinite', () => {
const files = fsUtil.ls('head', { depth: -1 }).sort();
const files = fsUtil.lsSync('head', { depth: -1 }).sort();
expect(files).toEqual(allFiles);
});
});
describe('walkSync', () => {
const allFiles = resolvePaths([
'head/eyes',
'head/ears',
'head/mouth',
'head/nose',
'head/shoulders/knees/meniscus',
'head/shoulders/knees/toes/.big-toe-phalanx',
'head/shoulders/knees/toes/phalanx'
]);
it('gets all files from all levels by default', () => {
const files = fsUtil.walkSync(cwd).sort();
expect(files).toEqual(allFiles);
});
it('limits recursion depth when asked', () => {
const files = fsUtil.walkSync(cwd, { depth: 1 }).sort();
expect(files).toEqual(resolvePaths([
'head/eyes',
'head/ears',
'head/mouth',
'head/nose'
]));
});
it('treats a depth of -1 as infinite', () => {
const files = fsUtil.walkSync('head', { depth: -1 }).sort();
expect(files).toEqual(allFiles);
});
it('works with paths to specific files', () => {
const files = fsUtil.walkSync('head/shoulders/knees/meniscus');
expect(files).toEqual(resolvePaths([
'head/shoulders/knees/meniscus'
]));
});
it('applies the filter if present', () => {
const files = fsUtil.walkSync(
'head/shoulders/knees/toes',
{ filter: f => path.basename(f) !== 'phalanx' }
);
expect(files).toEqual(resolvePaths([
'head/shoulders/knees/toes/.big-toe-phalanx'
]));
});
});
});

139
packages/jsdoc-util/test/specs/lib/path.js Normal file → Executable file
View File

@ -4,18 +4,21 @@ describe('@jsdoc/util/lib/path', () => {
const libPath = require('../../../lib/path');
const isWindows = /^win/.test(os.platform());
const fakeCwd = isWindows ? 'C:\\Users\\jsdoc' : '/Users/jsdoc';
beforeEach(() => {
spyOn(process, 'cwd').and.returnValue(fakeCwd);
});
it('has a commonPrefix method', () => {
expect(libPath.commonPrefix).toBeFunction();
});
it('has a makeFilter method', () => {
expect(libPath.makeFilter).toBeFunction();
});
describe('commonPrefix', () => {
const fakeCwd = isWindows ? 'C:\\Users\\jsdoc' : '/Users/jsdoc';
beforeEach(() => {
spyOn(process, 'cwd').and.returnValue(fakeCwd);
});
it('finds the correct prefix for a single relative path', () => {
const paths = [path.join('foo', 'bar', 'baz', 'qux.js')];
const expected = path.join(fakeCwd, 'foo', 'bar', 'baz');
@ -92,4 +95,128 @@ describe('@jsdoc/util/lib/path', () => {
});
}
});
describe('makeFilter', () => {
it('returns a function', () => {
expect(typeof libPath.makeFilter({})).toBe('function');
});
it('throws on bad input', () => {
expect(() => libPath.makeFilter()).toThrow();
});
describe('exclude', () => {
it('accepts a string', () => {
expect(() => libPath.makeFilter({ exclude: 'foo' })).not.toThrow();
});
it('accepts an array of strings', () => {
expect(() => libPath.makeFilter({ exclude: ['foo', 'bar'] })).not.toThrow();
});
it('throws on invalid types', () => {
expect(() => libPath.makeFilter({ exclude: 7 })).toThrow();
});
it('filters out filepaths that end with excluded values', () => {
const filter = libPath.makeFilter({ exclude: ['nope/nuh-uh.md', 'neverever'] });
const filteredFiles = [
'path/to/some/file.js',
'another/path/nope/nuh-uh.md',
'neverever'
].filter(filter);
expect(filteredFiles).toEqual(['path/to/some/file.js']);
});
it('does not filter out filepaths that contain excluded values in the middle', () => {
const filter = libPath.makeFilter({ exclude: 'to/some' });
const filteredFiles = [
'path/to/some/file.js'
].filter(filter);
expect(filteredFiles).toEqual(['path/to/some/file.js']);
});
it('takes precedence over includePattern', () => {
const filter = libPath.makeFilter({
exclude: ['nope/nuh-uh.md', 'neverever'],
includePattern: '(?:\\.js|\\.md)$'
});
const filteredFiles = [
'path/to/some/file.js',
'another/path/nope/nuh-uh.md',
'neverever'
].filter(filter);
expect(filteredFiles).toEqual(['path/to/some/file.js']);
});
});
describe('excludePattern', () => {
it('accepts a string', () => {
expect(() => libPath.makeFilter({ excludePattern: 'foo' })).not.toThrow();
});
it('accepts a RegExp', () => {
expect(() => libPath.makeFilter({ excludePattern: new RegExp('z') })).not.toThrow();
});
it('throws on invalid types', () => {
expect(() => libPath.makeFilter({ excludePattern: 7 })).toThrow();
});
it('filters out filepaths that match excludePattern', () => {
const filter = libPath.makeFilter({
excludePattern: '(?:nuh.+?\\.md|neverever)$'
});
const filteredFiles = [
'path/to/some/file.js',
'another/path/nope/nuh-uh.md',
'neverever'
].filter(filter);
expect(filteredFiles).toEqual(['path/to/some/file.js']);
});
it('takes precedence over includePattern', () => {
const filter = libPath.makeFilter({
excludePattern: '(?:nuh.+?\\.md|neverever)$',
includePattern: '(?:\\.js|\\.md)$'
});
const filteredFiles = [
'path/to/some/file.js',
'another/path/nope/nuh-uh.md',
'neverever'
].filter(filter);
expect(filteredFiles).toEqual(['path/to/some/file.js']);
});
});
describe('includePattern', () => {
it('accepts a string', () => {
expect(() => libPath.makeFilter({ includePattern: 'foo' })).not.toThrow();
});
it('accepts a RegExp', () => {
expect(() => libPath.makeFilter({ includePattern: new RegExp('z') })).not.toThrow();
});
it('throws on invalid types', () => {
expect(() => libPath.makeFilter({ includePattern: 7 })).toThrow();
});
it('includes only filepaths that match includePattern', () => {
const filter = libPath.makeFilter({ includePattern: '\\.js$' });
const filteredFiles = [
'path/to/some/file.js',
'another/path/nope/nuh-uh.md',
'neverever'
].filter(filter);
expect(filteredFiles).toEqual(['path/to/some/file.js']);
});
});
});
});

View File

View File

View File

View File

View File

View File

View File

@ -1,167 +0,0 @@
describe('jsdoc/src/filter', () => {
const env = require('jsdoc/env');
const filter = require('jsdoc/src/filter');
const path = require('path');
it('should exist', () => {
expect(filter).toBeDefined();
expect(typeof filter).toBe('object');
});
it('should export a "Filter" class', () => {
expect(filter.Filter).toBeDefined();
expect(typeof filter.Filter).toBe('function');
});
describe('Filter', () => {
let myFilter;
const defaultIncludePattern = new RegExp('.+\\.js(doc)?$');
const defaultExcludePattern = new RegExp('(^|\\/|\\\\)_');
beforeEach(() => {
myFilter = new filter.Filter({});
});
it('should have an "exclude" property', () => {
expect(myFilter.exclude).toBeDefined();
});
it('should have an "excludePattern" property', () => {
expect(myFilter.excludePattern).toBeDefined();
});
it('should have an "includePattern" property', () => {
expect(myFilter.includePattern).toBeDefined();
});
it('should have an "isIncluded" method', () => {
expect(myFilter.isIncluded).toBeDefined();
expect(typeof myFilter.isIncluded).toBe('function');
});
describe('exclude', () => {
it('should default to null', () => {
expect(myFilter.exclude).toBe(null);
});
it('should be null if the value passed to the constructor was not an array',
() => {
myFilter = new filter.Filter({
exclude: 'foo'
});
expect(myFilter.exclude).toBe(null);
});
it('should resolve paths relative to the user\'s working directory', () => {
const filename = 'bar.js';
myFilter = new filter.Filter({
exclude: [filename]
});
expect(myFilter.exclude).toEqual([path.resolve(env.pwd, filename)]);
});
});
function testRegExpProperty(name) {
it('should default to null', () => {
expect(myFilter[name]).toBe(null);
});
it('should contain the regexp passed to the constructor', () => {
const regExp = new RegExp('^foo$');
const options = {};
options[name] = regExp;
myFilter = new filter.Filter(options);
expect(myFilter[name]).toBe(regExp);
});
it('should contain a regexp if a string was passed to the constructor', () => {
const regExpString = '^foo$';
const options = {};
options[name] = regExpString;
myFilter = new filter.Filter(options);
expect(myFilter[name] instanceof RegExp).toBe(true);
expect(myFilter[name].source).toBe(regExpString);
});
}
describe( 'excludePattern', testRegExpProperty.bind(jasmine, 'excludePattern') );
describe( 'includePattern', testRegExpProperty.bind(jasmine, 'includePattern') );
describe('isIncluded', () => {
it('should return the correct source files', () => {
let files = [
'yes.js',
'/yes.jsdoc',
'/_nope.js',
'.ignore',
path.normalize(`${env.pwd}/scratch/conf.js`)
];
myFilter = new filter.Filter({
includePattern: defaultIncludePattern,
excludePattern: defaultExcludePattern,
exclude: ['.ignore', 'scratch/conf.js']
});
files = files.filter($ => myFilter.isIncluded($));
expect(files.length).toEqual(2);
expect( files.indexOf('yes.js') ).toBeGreaterThan(-1);
expect( files.indexOf('/yes.jsdoc') ).toBeGreaterThan(-1);
});
it('should be able to exclude specific subdirectories', () => {
let files = [
'yes.js',
'topsecret/nope.js',
'module/yes.js',
'module/topsecret/nope.js'
];
myFilter = new filter.Filter({
includePattern: defaultIncludePattern,
excludePattern: defaultExcludePattern,
exclude: ['topsecret', 'module/topsecret']
});
files = files.filter($ => myFilter.isIncluded($));
expect(files.length).toBe(2);
expect( files.indexOf('yes.js') ).toBeGreaterThan(-1);
expect( files.indexOf('module/yes.js') ).toBeGreaterThan(-1);
});
it('should be able to exclude descendants of excluded subdirectories', () => {
let files = [
'yes.js',
'topsecret/nested/nope.js',
'module/yes.js',
'module/topsecret/nested/nope.js'
];
myFilter = new filter.Filter({
includePattern: defaultIncludePattern,
excludePattern: defaultExcludePattern,
exclude: ['topsecret', 'module/topsecret']
});
files = files.filter($ => myFilter.isIncluded($));
expect(files.length).toBe(2);
expect( files.indexOf('yes.js') ).toBeGreaterThan(-1);
expect( files.indexOf('module/yes.js') ).toBeGreaterThan(-1);
expect( files.indexOf('topsecret/nested/nope.js') ).toBe(-1);
expect( files.indexOf('module/topsecret/nested/nope.js') ).toBe(-1);
});
});
});
});

View File

@ -1,54 +0,0 @@
describe('jsdoc/src/scanner', () => {
const env = require('jsdoc/env');
const path = require('path');
const scanner = require('jsdoc/src/scanner');
const filter = new (require('jsdoc/src/filter').Filter)({
includePattern: new RegExp('.+\\.js(doc)?$'),
excludePattern: new RegExp('(^|\\/|\\\\)_')
});
const sourcePath = path.normalize(`${env.pwd}/test/fixtures/src`);
it('should exist', () => {
expect(scanner).toBeDefined();
expect(typeof scanner).toBe('object');
});
it('should export a "Scanner" class', () => {
expect(scanner.Scanner).toBeDefined();
expect(typeof scanner.Scanner).toBe('function');
});
describe('Scanner', () => {
it('should inherit from EventEmitter', () => {
const EventEmitter = require('events').EventEmitter;
const testScanner = new scanner.Scanner();
expect(testScanner instanceof EventEmitter).toBe(true);
});
it('should have a "scan" method', () => {
const testScanner = new scanner.Scanner();
expect(testScanner.scan).toBeDefined();
expect(typeof testScanner.scan).toBe('function');
});
describe('scan', () => {
it('should return the correct source files', () => {
const testScanner = new scanner.Scanner();
let sourceFiles = testScanner.scan([sourcePath], 3, filter);
sourceFiles = sourceFiles.map($ => path.relative(env.pwd, $));
expect(sourceFiles.length).toEqual(3);
expect( sourceFiles.indexOf(path.join('test', 'fixtures', 'src', 'one.js')) )
.toBeGreaterThan(-1);
expect( sourceFiles.indexOf(path.join('test', 'fixtures', 'src', 'two.js')) )
.toBeGreaterThan(-1);
expect( sourceFiles.indexOf(path.join('test', 'fixtures', 'src', 'dir1', 'three.js')) )
.toBeGreaterThan(-1);
});
});
});
});