mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
replace jsdoc/src/filter and jsdoc/src/scanner
Plus some semi-related cleanup.
This commit is contained in:
parent
85cbed9c0c
commit
32f8aed805
14
cli.js
14
cli.js
@ -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;
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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'),
|
||||
|
||||
@ -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'),
|
||||
|
||||
@ -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
1
package-lock.json
generated
@ -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",
|
||||
|
||||
@ -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');
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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
39
packages/jsdoc-util/lib/fs.js
Normal file → Executable 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
91
packages/jsdoc-util/lib/path.js
Normal file → Executable 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
0
packages/jsdoc-util/package-lock.json
generated
Normal file → Executable file
1
packages/jsdoc-util/package.json
Normal file → Executable file
1
packages/jsdoc-util/package.json
Normal file → Executable 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"
|
||||
|
||||
@ -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
4
packages/jsdoc-util/test/specs/lib/cast.js
Normal file → Executable 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
112
packages/jsdoc-util/test/specs/lib/fs.js
Normal file → Executable 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
139
packages/jsdoc-util/test/specs/lib/path.js
Normal file → Executable 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']);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
0
test/fixtures/src/_dir2/four.js
vendored
0
test/fixtures/src/_dir2/four.js
vendored
0
test/fixtures/src/_ignored.js
vendored
0
test/fixtures/src/_ignored.js
vendored
0
test/fixtures/src/dir1/three.js
vendored
0
test/fixtures/src/dir1/three.js
vendored
0
test/fixtures/src/ignored.txt
vendored
0
test/fixtures/src/ignored.txt
vendored
0
test/fixtures/src/one.js
vendored
0
test/fixtures/src/one.js
vendored
0
test/fixtures/src/two.js
vendored
0
test/fixtures/src/two.js
vendored
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user