From aa5802b41e0a762068773afeeec4fc8772c2b7cc Mon Sep 17 00:00:00 2001 From: Samuel Steffl Date: Fri, 22 May 2015 08:21:30 -0700 Subject: [PATCH 1/9] upgraded paths globbing --- lib/project.js | 2 +- lib/utils.js | 120 +++++-------------------------------------------- lib/yuidoc.js | 85 +++++------------------------------ package.json | 1 + 4 files changed, 24 insertions(+), 184 deletions(-) diff --git a/lib/project.js b/lib/project.js index 31d66922..e1f13a85 100644 --- a/lib/project.js +++ b/lib/project.js @@ -47,7 +47,7 @@ YUI.add('project', function (Y) { } options.paths = Y.validatePaths(options.paths, options.ignorePaths); - +debugger; if (!options.paths.length) { Y.log('Paths argument was empty', 'warn', 'yuidoc'); Y.showHelp(); diff --git a/lib/utils.js b/lib/utils.js index 328a409e..1ee6faac 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -6,7 +6,8 @@ 'use strict'; var path = require('path'), - minimatch = require('minimatch'), + glob = require('glob'), + minimatch = require('minimatch'), fs = require('graceful-fs'); /** @@ -336,119 +337,22 @@ YUI.add('utils', function (Y) { Y.getProjectData = getProjectData; - - /** - * Walks the tree from this dir and returns all the subdirs - * @method getDirs - * @param {String} dir The dir to begin at - * @return {Array} The array of directories.. - */ - var getDirs = function (dir) { - var dirs = fs.readdirSync(dir), - paths = []; - - dirs.forEach(function (d) { - var _dir = path.join(dir, d), - stat = fs.lstatSync(_dir); - - if (stat.isDirectory()) { - if (_dir.indexOf('.') !== 0) { - paths = [].concat(paths, _dir, getDirs(_dir)); - } - } - }); - - return paths; - }; - - Y.getDirs = getDirs; - /** * Make sure all the paths passed are directories and that they are not in the ignore list. * @method validatePaths * @param {Array} paths The array of paths to validate * @param {String} [ignore=false] A string to call `.indexOf` on a path to determine if it should be ignored */ - var validatePaths = function (paths, ignore) { - var newpaths = []; - //Shortcut the *, . & ./ shortcuts that shall globbing fixes for us - if (paths === '*' || paths === '.' || paths === './') { - paths = [process.cwd()]; - } - - // Ensure that we always have an array of some kind. - paths = paths || []; - if (!Y.Lang.isArray(paths)) { - paths = [paths]; - } - paths.forEach(function (validatePath) { - var glob = validatePath || ''; - - if (process.platform === 'win32') { - glob = validatePath.replace(/\//g, '\\\\'); - } - - var glob_paths = getDirs('.'), - is_globbed = false; - - glob_paths.forEach(function (dir) { - //Don't scan things in node_modules - if (dir.indexOf('node_modules') > -1) { - return; - } - if (minimatch(dir, glob, { - period: true - })) { - newpaths.push(dir); - is_globbed = true; - } - }); - - if (!is_globbed && (Y.Files.isDirectory(glob))) { - //If minimatch fails, check to see if it's a relative directory - // if it is, add it directly - newpaths.push(glob); - } - }); - - paths = newpaths; - paths.forEach(function (newPath) { - try { - if (!Y.Files.isDirectory(newPath)) { - throw ('Path not a directory: ' + newPath); - } - } catch (e) { - throw new Error(e.message); - } - }); - - if (!paths || !paths.forEach) { - throw ('Paths should be an array of paths'); - } - - if (ignore) { - if (!(ignore instanceof Array)) { - ignore = [ignore]; - } - var p = [], - shouldIgnore = false; - - paths.forEach(function (v) { - shouldIgnore = false; - ignore.forEach(function (i) { - if (!shouldIgnore && v.indexOf(i) !== -1) { - shouldIgnore = true; - } - }); - if (!shouldIgnore) { - p.push(v); - } - }); - paths = p; - } - - paths = paths.sort(); - return paths; + var validatePaths = function(paths, ignore) { + ignore = [].concat(ignore || []); + return [].concat(paths || process.cwd()) + .reduce(function(paths, path){ return paths.concat(glob.sync(path)); }, []) + .filter(function(path){ + return !ignore.filter(function(ignoreGlob){ return minimatch(path, ignoreGlob); }).length; + }) + .filter(function(path, i, paths){ + return !paths.slice(i+1).filter(function(path2){ return path === path2; }).length; + }); }; Y.validatePaths = validatePaths; diff --git a/lib/yuidoc.js b/lib/yuidoc.js index 3c6cc91a..188eb0e8 100755 --- a/lib/yuidoc.js +++ b/lib/yuidoc.js @@ -86,13 +86,6 @@ YUI.add('yuidoc', function (Y) { * @private */ this.filemap = {}; - /** - * Holder for the list of directories we are processing. - * @property dirmap - * @type Object - * @private - */ - this.dirmap = {}; /** * Internal holder for configuration options. @@ -138,87 +131,30 @@ YUI.add('yuidoc', function (Y) { }, /** - * Walks the paths and parses the directory contents - * @method walk - * @private - */ - walk: function () { - Y.each(this.options.paths, function (dir) { - this.parsedir(dir); - }, this); - }, - - /** - * Walks the passed directory and grabs all the files recursively. - * @method parsedir - * @param {String} dir The directory to parse the contents of. - * @private - */ - parsedir: function (dir) { - if (!Y.Files.isDirectory(dir)) { - throw ('Can not find directory: ' + dir); - } - - var allfiles = fs.readdirSync(dir), - stats, - files = [], - fullpath, self = this; - - if (dir in self.options.excludes) { - return; - } - - allfiles = allfiles.sort(); - - Y.each(allfiles, function (filename) { - if (!(filename in self.options.excludes)) { - fullpath = path.join(dir, filename); - - stats = fs.statSync(fullpath); - - if (stats.isDirectory() && !self.options.norecurse) { - self.parsedir(fullpath); - } else { - files.push(filename); - } - } - }); - - if (!(dir in self.options.excludes)) { - this.parsefiles(dir, files); - } - }, - - /** - * Gathers all the file data and populates the filemap and dirmap hashes. + * Gathers all the file data and populates the filemap and. * @method parsefiles - * @param {String} dir The directory to start from. * @param {Array} files List of files to parse. * @private */ - parsefiles: function (dir, files) { + parsefiles: function (files) { var self = this; files = files.sort(); Y.each(files, function (filename) { var ext = path.extname(filename), - text, - fullpath; + text; if (ext) { if (ext in self.options.extensions) { - fullpath = path.join(dir, filename); - - if (Y.Files.exists(fullpath)) { + if (Y.Files.exists(filename)) { self.filecount++; - text = fs.readFileSync(fullpath, Y.charset); + text = fs.readFileSync(filename, Y.charset); - self.filemap[fullpath] = text.replace(/\r?\n|\r/g, '\n'); - self.dirmap[fullpath] = dir; - self.getSelleck(fullpath); + self.filemap[filename] = text.replace(/\r?\n|\r/g, '\n'); + self.getSelleck(filename); } else { - Y.log('File skipped: ' + fullpath, 'warn', 'yuidoc'); + Y.log('File skipped: ' + filename, 'warn', 'yuidoc'); } } } @@ -390,12 +326,11 @@ YUI.add('yuidoc', function (Y) { this.starttime = new Date().getTime(); this._processConfig(); - this.walk(); + this.parsefiles(this.options.paths); var json = this.writeJSON(new Y.DocParser({ syntaxtype: this.options.syntaxtype, - filemap: this.filemap, - dirmap: this.dirmap + filemap: this.filemap }).parse()); if (this.options.lint) { diff --git a/package.json b/package.json index 116adff2..c2c48877 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ }, "dependencies": { "express": "^4.12.3", + "glob": "^5.0.7", "graceful-fs": "2.x", "markdown-it": "^4.1.0", "minimatch": "^2.0.1", From 1a59d5f3e8aaa1a28ebf26dbd2b40f36fb7b01c4 Mon Sep 17 00:00:00 2001 From: vagrant Date: Fri, 22 May 2015 17:25:42 +0000 Subject: [PATCH 2/9] relevent tests passed --- lib/project.js | 2 +- lib/utils.js | 22 +- output/api/api.js | 27 - output/api/assets/css/external-small.png | Bin 491 -> 0 bytes output/api/assets/css/logo.png | Bin 7143 -> 0 bytes output/api/assets/css/main.css | 783 -- output/api/assets/favicon.ico | Bin 5430 -> 0 bytes output/api/assets/img/spinner.gif | Bin 2685 -> 0 bytes output/api/assets/index.html | 10 - output/api/assets/js/api-filter.js | 52 - output/api/assets/js/api-list.js | 251 - output/api/assets/js/api-search.js | 98 - output/api/assets/js/apidocs.js | 370 - output/api/assets/js/yui-prettify.js | 17 - .../api/assets/vendor/prettify/CHANGES.html | 130 - output/api/assets/vendor/prettify/COPYING | 202 - output/api/assets/vendor/prettify/README.html | 203 - .../assets/vendor/prettify/prettify-min.css | 1 - .../assets/vendor/prettify/prettify-min.js | 1 - output/api/classes/CLI.html | 143 - output/api/classes/DocBuilder.html | 2558 ------ output/api/classes/DocParser.html | 7949 ----------------- output/api/classes/DocView.html | 295 - output/api/classes/Files.html | 1190 --- output/api/classes/Help.html | 277 - output/api/classes/Main.html | 152 - output/api/classes/Options.html | 224 - output/api/classes/Server.html | 697 -- output/api/classes/Utils.html | 1034 --- output/api/classes/YUIDoc.html | 874 -- output/api/classes/index.html | 10 - output/api/data.json | 2627 +----- output/api/files/index.html | 10 - output/api/files/lib_builder.js.html | 1784 ---- output/api/files/lib_cli.js.html | 160 - output/api/files/lib_docparser.js.html | 1578 ---- output/api/files/lib_docview.js.html | 175 - output/api/files/lib_files.js.html | 596 -- output/api/files/lib_help.js.html | 190 - output/api/files/lib_index.js.html | 232 - output/api/files/lib_options.js.html | 287 - output/api/files/lib_project.js.html | 177 - output/api/files/lib_server.js.html | 346 - output/api/files/lib_utils.js.html | 603 -- output/api/files/lib_yuidoc.js.html | 527 -- output/api/index.html | 125 - output/api/modules/index.html | 10 - output/api/modules/yuidoc.html | 194 - 48 files changed, 17 insertions(+), 27176 deletions(-) delete mode 100644 output/api/api.js delete mode 100644 output/api/assets/css/external-small.png delete mode 100644 output/api/assets/css/logo.png delete mode 100644 output/api/assets/css/main.css delete mode 100644 output/api/assets/favicon.ico delete mode 100644 output/api/assets/img/spinner.gif delete mode 100644 output/api/assets/index.html delete mode 100644 output/api/assets/js/api-filter.js delete mode 100644 output/api/assets/js/api-list.js delete mode 100644 output/api/assets/js/api-search.js delete mode 100644 output/api/assets/js/apidocs.js delete mode 100644 output/api/assets/js/yui-prettify.js delete mode 100644 output/api/assets/vendor/prettify/CHANGES.html delete mode 100644 output/api/assets/vendor/prettify/COPYING delete mode 100644 output/api/assets/vendor/prettify/README.html delete mode 100644 output/api/assets/vendor/prettify/prettify-min.css delete mode 100644 output/api/assets/vendor/prettify/prettify-min.js delete mode 100644 output/api/classes/CLI.html delete mode 100644 output/api/classes/DocBuilder.html delete mode 100644 output/api/classes/DocParser.html delete mode 100644 output/api/classes/DocView.html delete mode 100644 output/api/classes/Files.html delete mode 100644 output/api/classes/Help.html delete mode 100644 output/api/classes/Main.html delete mode 100644 output/api/classes/Options.html delete mode 100644 output/api/classes/Server.html delete mode 100644 output/api/classes/Utils.html delete mode 100644 output/api/classes/YUIDoc.html delete mode 100644 output/api/classes/index.html delete mode 100644 output/api/files/index.html delete mode 100644 output/api/files/lib_builder.js.html delete mode 100644 output/api/files/lib_cli.js.html delete mode 100644 output/api/files/lib_docparser.js.html delete mode 100644 output/api/files/lib_docview.js.html delete mode 100644 output/api/files/lib_files.js.html delete mode 100644 output/api/files/lib_help.js.html delete mode 100644 output/api/files/lib_index.js.html delete mode 100644 output/api/files/lib_options.js.html delete mode 100644 output/api/files/lib_project.js.html delete mode 100644 output/api/files/lib_server.js.html delete mode 100644 output/api/files/lib_utils.js.html delete mode 100644 output/api/files/lib_yuidoc.js.html delete mode 100644 output/api/index.html delete mode 100644 output/api/modules/index.html delete mode 100644 output/api/modules/yuidoc.html diff --git a/lib/project.js b/lib/project.js index e1f13a85..31d66922 100644 --- a/lib/project.js +++ b/lib/project.js @@ -47,7 +47,7 @@ YUI.add('project', function (Y) { } options.paths = Y.validatePaths(options.paths, options.ignorePaths); -debugger; + if (!options.paths.length) { Y.log('Paths argument was empty', 'warn', 'yuidoc'); Y.showHelp(); diff --git a/lib/utils.js b/lib/utils.js index 1ee6faac..c9617233 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -7,7 +7,7 @@ var path = require('path'), glob = require('glob'), - minimatch = require('minimatch'), + minimatch = require('minimatch'), fs = require('graceful-fs'); /** @@ -343,16 +343,16 @@ YUI.add('utils', function (Y) { * @param {Array} paths The array of paths to validate * @param {String} [ignore=false] A string to call `.indexOf` on a path to determine if it should be ignored */ - var validatePaths = function(paths, ignore) { - ignore = [].concat(ignore || []); - return [].concat(paths || process.cwd()) - .reduce(function(paths, path){ return paths.concat(glob.sync(path)); }, []) - .filter(function(path){ - return !ignore.filter(function(ignoreGlob){ return minimatch(path, ignoreGlob); }).length; - }) - .filter(function(path, i, paths){ - return !paths.slice(i+1).filter(function(path2){ return path === path2; }).length; - }); + var validatePaths = function(globpaths, ignore) { + ignore = [].concat(ignore || []); + return [].concat(globpaths || process.cwd()) + .reduce(function(filepaths, globpath){ return filepaths.concat(glob.sync(globpath)); }, []) + .filter(function(filepath){ + return !ignore.filter(function(ignoreGlob){ return minimatch(filepath, ignoreGlob); }).length; + }) + .filter(function(filepath, i, filepaths){ + return !filepaths.slice(i + 1).filter(function(filepath2){ return filepath === filepath2; }).length; + }); }; Y.validatePaths = validatePaths; diff --git a/output/api/api.js b/output/api/api.js deleted file mode 100644 index ce5fa4d2..00000000 --- a/output/api/api.js +++ /dev/null @@ -1,27 +0,0 @@ -YUI.add("yuidoc-meta", function(Y) { - Y.YUIDoc = { meta: { - "classes": [ - "CLI", - "DocBuilder", - "DocParser", - "DocView", - "Files", - "Help", - "Main", - "Options", - "Server", - "Utils", - "YUIDoc" - ], - "modules": [ - "yuidoc" - ], - "allModules": [ - { - "displayName": "yuidoc", - "name": "yuidoc", - "description": "This is the __module__ description for the `YUIDoc` module.\n\n var options = {\n paths: [ './lib' ],\n outdir: './out'\n };\n\n var Y = require('yuidocjs');\n var json = (new Y.YUIDoc(options)).run();" - } - ] -} }; -}); \ No newline at end of file diff --git a/output/api/assets/css/external-small.png b/output/api/assets/css/external-small.png deleted file mode 100644 index 759a1cdcb5b1697e5be290d98b830e279cd71f3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 491 zcmVDs{zR1^XE?tfB*h@ASKHAa7wwn{MEbP z7_^nS7{V*>+A}bS;P%45fB%Ai|Neasi2rl3{=EO;!w318%8Ovl7jArHc=P5Brfr~D z0AYimtss2w$hlYlfd>7*aO3TNzw875LBK0xAD9Np|A(oEVYnB*eE9~V6wP%78SXuL z&#-X)Er#`zY#Ce)^8hM>B_8 diff --git a/output/api/assets/css/logo.png b/output/api/assets/css/logo.png deleted file mode 100644 index c82444af95895d38bea6fe96cc5354a7419f770c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7143 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