UNPKG

utility2

Version:

this zero-dependency package will provide high-level functions to to build, test, and deploy webapps

1,325 lines (1,302 loc) 39.9 kB
#!/usr/bin/env node /* * lib.apidoc.js (2020.6.9) * https://github.com/kaizhu256/node-apidoc-lite * this zero-dependency package will auto-generate documentation for your npm-package with zero-config * */ /* istanbul instrument in package apidoc */ // assets.utility2.header.js - start /* jslint utility2:true */ /* istanbul ignore next */ // run shared js-env code - init-local (function () { "use strict"; let isBrowser; let isWebWorker; let local; // polyfill globalThis if (!(typeof globalThis === "object" && globalThis)) { if (typeof window === "object" && window && window.window === window) { window.globalThis = window; } if (typeof global === "object" && global && global.global === global) { global.globalThis = global; } } // init debugInline if (!globalThis.debugInline) { let consoleError; consoleError = console.error; globalThis.debugInline = function (...argList) { /* * this function will both print <argList> to stderr * and return <argList>[0] */ consoleError("\n\ndebugInline"); consoleError(...argList); consoleError("\n"); return argList[0]; }; } // init isBrowser isBrowser = ( typeof globalThis.XMLHttpRequest === "function" && globalThis.navigator && typeof globalThis.navigator.userAgent === "string" ); // init isWebWorker isWebWorker = ( isBrowser && typeof globalThis.importScripts === "function" ); // init function function objectDeepCopyWithKeysSorted(obj) { /* * this function will recursively deep-copy <obj> with keys sorted */ let sorted; if (typeof obj !== "object" || !obj) { return obj; } // recursively deep-copy list with child-keys sorted if (Array.isArray(obj)) { return obj.map(objectDeepCopyWithKeysSorted); } // recursively deep-copy obj with keys sorted sorted = {}; Object.keys(obj).sort().forEach(function (key) { sorted[key] = objectDeepCopyWithKeysSorted(obj[key]); }); return sorted; } function assertJsonEqual(aa, bb) { /* * this function will assert JSON.stringify(<aa>) === JSON.stringify(<bb>) */ aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa)); bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb)); if (aa !== bb) { throw new Error(JSON.stringify(aa) + " !== " + JSON.stringify(bb)); } } function assertOrThrow(passed, msg) { /* * this function will throw <msg> if <passed> is falsy */ if (passed) { return; } throw ( ( msg && typeof msg.message === "string" && typeof msg.stack === "string" ) // if msg is err, then leave as is ? msg : new Error( typeof msg === "string" // if msg is string, then leave as is ? msg // else JSON.stringify(msg) : JSON.stringify(msg, undefined, 4) ) ); } function coalesce(...argList) { /* * this function will coalesce null, undefined, or "" in <argList> */ let arg; let ii; ii = 0; while (ii < argList.length) { arg = argList[ii]; if (arg !== undefined && arg !== null && arg !== "") { return arg; } ii += 1; } return arg; } function identity(val) { /* * this function will return <val> */ return val; } function noop() { /* * this function will do nothing */ return; } function objectAssignDefault(tgt = {}, src = {}, depth = 0) { /* * this function will if items from <tgt> are null, undefined, or "", * then overwrite them with items from <src> */ let recurse; recurse = function (tgt, src, depth) { Object.entries(src).forEach(function ([ key, bb ]) { let aa; aa = tgt[key]; if (aa === undefined || aa === null || aa === "") { tgt[key] = bb; return; } if ( depth !== 0 && typeof aa === "object" && aa && !Array.isArray(aa) && typeof bb === "object" && bb && !Array.isArray(bb) ) { recurse(aa, bb, depth - 1); } }); }; recurse(tgt, src, depth | 0); return tgt; } function onErrorThrow(err) { /* * this function will throw <err> if exists */ if (err) { throw err; } } // bug-workaround - throw unhandledRejections in node-process if ( typeof process === "object" && process && typeof process.on === "function" && process.unhandledRejections !== "strict" ) { process.unhandledRejections = "strict"; process.on("unhandledRejection", function (err) { throw err; }); } // init local local = { assertJsonEqual, assertOrThrow, coalesce, identity, isBrowser, isWebWorker, local, noop, objectAssignDefault, objectDeepCopyWithKeysSorted, onErrorThrow }; globalThis.globalLocal = local; }()); // assets.utility2.header.js - end (function (local) { "use strict"; /* istanbul ignore next */ // run shared js-env code - init-before (function () { // init local local = ( globalThis.utility2_rollup // || globalThis.utility2_rollup_old // || require("./assets.utility2.rollup.js") || globalThis.globalLocal ); // init exports if (local.isBrowser) { globalThis.utility2_apidoc = local; } else { module.exports = local; module.exports.__dirname = __dirname; } // init lib main local.apidoc = local; /* validateLineSortedReset */ local.cliRun = function ({ rgxComment }) { /* * this function will run cli */ let cliDict; cliDict = local.cliDict; cliDict._eval = cliDict._eval || function () { /* * <code> * will eval <code> */ globalThis.local = local; require("vm").runInThisContext(process.argv[3]); }; cliDict._help = cliDict._help || function () { /* * * will print help */ let commandList; let file; let packageJson; let str; let strDict; commandList = [ { argList: "<arg2> ...", description: "usage:", command: [ "<arg1>" ] }, { argList: "'console.log(\"hello world\")'", description: "example:", command: [ "--eval" ] } ]; file = __filename.replace(( /.*\// ), ""); packageJson = require("./package.json"); // validate comment rgxComment = rgxComment || ( /\)\u0020\{\n(?:|\u0020{4})\/\*\n(?:\u0020|\u0020{5})\*((?:\u0020<[^>]*?>|\u0020\.\.\.)*?)\n(?:\u0020|\u0020{5})\*\u0020(will\u0020.*?\S)\n(?:\u0020|\u0020{5})\*\/\n(?:\u0020{4}|\u0020{8})\S/ ); strDict = {}; Object.keys(cliDict).sort().forEach(function (key, ii) { if (key[0] === "_" && key !== "_default") { return; } str = String(cliDict[key]); if (key === "_default") { key = ""; } strDict[str] = strDict[str] || (ii + 2); ii = strDict[str]; if (commandList[ii]) { commandList[ii].command.push(key); return; } commandList[ii] = rgxComment.exec(str); local.assertOrThrow(commandList[ii], ( "cliRun - cannot parse comment in COMMAND " + key + ":\nnew RegExp(" + JSON.stringify(rgxComment.source) + ").exec(" + JSON.stringify(str).replace(( /\\\\/g ), "\u0000").replace(( /\\n/g ), "\\n\\\n").replace(( /\u0000/g ), "\\\\") + ");" )); commandList[ii] = { argList: local.coalesce(commandList[ii][1], "").trim(), command: [ key ], description: commandList[ii][2] }; }); str = ""; str += packageJson.name + " (" + packageJson.version + ")\n\n"; str += commandList.filter(function (elem) { return elem; }).map(function (elem, ii) { elem.command = elem.command.filter(function (elem) { return elem; }); switch (ii) { case 0: case 1: elem.argList = [ elem.argList ]; break; default: elem.argList = elem.argList.split(" "); elem.description = ( "# COMMAND " + (elem.command[0] || "<none>") + "\n# " + elem.description ); } return ( elem.description + "\n " + file + " " + elem.command.sort().join("|") + " " + elem.argList.join(" ") ); }).join("\n\n"); console.log(str); }; cliDict["--eval"] = cliDict["--eval"] || cliDict._eval; cliDict["--help"] = cliDict["--help"] || cliDict._help; cliDict["-e"] = cliDict["-e"] || cliDict._eval; cliDict["-h"] = cliDict["-h"] || cliDict._help; cliDict._default = cliDict._default || cliDict._help; cliDict.help = cliDict.help || cliDict._help; cliDict._interactive = cliDict._interactive || function () { /* * * will start interactive-mode */ globalThis.local = local; local.identity(local.replStart || require("repl").start)({ useGlobal: true }); }; cliDict["--interactive"] = cliDict["--interactive"] || cliDict._interactive; cliDict["-i"] = cliDict["-i"] || cliDict._interactive; cliDict._version = cliDict._version || function () { /* * * will print version */ console.log(require(__dirname + "/package.json").version); }; cliDict["--version"] = cliDict["--version"] || cliDict._version; cliDict["-v"] = cliDict["-v"] || cliDict._version; // default to --help command if no arguments are given if (process.argv.length <= 2) { cliDict._help(); return; } if (cliDict[process.argv[2]]) { cliDict[process.argv[2]](); return; } cliDict._default(); }; local.moduleDirname = function (module, pathList) { /* * this function will search <pathList> for <module>'s __dirname */ let result; // search "." if (!module || module === "." || module.indexOf("/") >= 0) { return require("path").resolve(module || ""); } // search pathList [].concat( pathList, require("module").globalPaths, [ process.env.HOME + "/node_modules", "/usr/local/lib/node_modules" ] ).some(function (path) { try { result = require("path").resolve(path + "/" + module); result = require("fs").statSync(result).isDirectory() && result; return result; } catch (ignore) { result = ""; } }); return result; }; local.stringHtmlSafe = function (str) { /* * this function will make <str> html-safe * https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-on-html */ return str.replace(( /&/gu ), "&amp;").replace(( /"/gu ), "&quot;").replace(( /'/gu ), "&apos;").replace(( /</gu ), "&lt;").replace(( />/gu ), "&gt;").replace(( /&amp;(amp;|apos;|gt;|lt;|quot;)/igu ), "&$1"); }; /* jslint ignore:start */ local.templateApidocHtml = '\ <div class="apidocDiv">\n\ <style>\n\ /*csslint\n\ */\n\ .apidocDiv {\n\ background: #fff;\n\ font-family: Arial, Helvetica, sans-serif;\n\ }\n\ .apidocDiv a[href] {\n\ color: #33f;\n\ font-weight: bold;\n\ text-decoration: none;\n\ }\n\ .apidocDiv a[href]:hover {\n\ text-decoration: underline;\n\ }\n\ .apidocCodeCommentSpan {\n\ background: #bbf;\n\ color: #000;\n\ display: block;\n\ }\n\ .apidocCodeKeywordSpan {\n\ color: #d00;\n\ font-weight: bold;\n\ }\n\ .apidocCodePre {\n\ background: #eef;\n\ border: 1px solid;\n\ color: #777;\n\ overflow-wrap: break-word;\n\ padding: 5px;\n\ white-space: pre-wrap;\n\ }\n\ .apidocFooterDiv {\n\ margin-top: 20px;\n\ text-align: center;\n\ }\n\ .apidocModuleLi {\n\ margin-top: 10px;\n\ }\n\ .apidocSectionDiv {\n\ border-top: 1px solid;\n\ margin-top: 20px;\n\ }\n\ .apidocSignatureSpan {\n\ color: #777;\n\ font-weight: bold;\n\ }\n\ </style>\n\ <h1>api documentation for\n\ <a\n\ {{#if env.npm_package_homepage}}\n\ href="{{env.npm_package_homepage}}"\n\ {{/if env.npm_package_homepage}}\n\ >{{env.npm_package_name}} ({{env.npm_package_version}})</a>\n\ </h1>\n\ <h4>{{env.npm_package_description}}</h4>\n\ <div class="apidocSectionDiv"><a\n\ href="#apidoc.tableOfContents"\n\ id="apidoc.tableOfContents"\n\ ><h1>table of contents</h1></a><ol>\n\ {{#each moduleList}}\n\ <li class="apidocModuleLi"><a href="#{{id}}">module {{name}}</a><ol>\n\ {{#each elemList}}\n\ <li>\n\ {{#if source}}\n\ <a class="apidocElementLiA" href="#{{id}}">\n\ {{name}}\n\ <span class="apidocSignatureSpan">{{signature}}</span>\n\ </a>\n\ {{#unless source}}\n\ <span class="apidocSignatureSpan">{{name}}</span>\n\ {{/if source}}\n\ </li>\n\ {{/each elemList}}\n\ </ol></li>\n\ {{/each moduleList}}\n\ </ol></div>\n\ {{#each moduleList}}\n\ <div class="apidocSectionDiv">\n\ <h1><a href="#{{id}}" id="{{id}}">module {{name}}</a></h1>\n\ {{#each elemList}}\n\ {{#if source}}\n\ <h2>\n\ <a href="#{{id}}" id="{{id}}">\n\ {{name}}\n\ <span class="apidocSignatureSpan">{{signature}}</span>\n\ </a>\n\ </h2>\n\ <ul>\n\ <li>description and source-code<pre class="apidocCodePre">{{source truncate 4096}}</pre></li>\n\ <li>example use<pre class="apidocCodePre">{{example}}</pre></li>\n\ </ul>\n\ {{/if source}}\n\ {{/each elemList}}\n\ </div>\n\ {{/each moduleList}}\n\ <div class="apidocFooterDiv">\n\ [ this document was created with\n\ <a href="https://github.com/kaizhu256/node-utility2" target="_blank">utility2</a>\n\ ]\n\ </div>\n\ </div>\n\ '; /* jslint ignore:end */ local.templateRender = function (template, dict, opt = {}, ii = 0) { /* * this function will render <template> with given <dict> */ let argList; let getVal; let match; let renderPartial; let rgx; let skip; let val; if (dict === null || dict === undefined) { dict = {}; } getVal = function (key) { argList = key.split(" "); val = dict; if (argList[0] === "#this/") { return val; } if (argList[0] === "#ii/") { return ii; } // iteratively lookup nested val in dict argList[0].split(".").forEach(function (key) { val = val && val[key]; }); return val; }; renderPartial = function (match0, helper, key, partial) { switch (helper) { case "each": case "eachTrimEndComma": val = getVal(key); val = ( Array.isArray(val) ? val.map(function (dict, ii) { // recurse with partial return local.templateRender(partial, dict, opt, ii); }).join("") : "" ); // remove trailing-comma from last elem if (helper === "eachTrimEndComma") { val = val.trimEnd().replace(( /,$/ ), ""); } return val; case "if": partial = partial.split("{{#unless " + key + "}}"); partial = ( getVal(key) ? partial[0] // handle "unless" case : partial.slice(1).join("{{#unless " + key + "}}") ); // recurse with partial return local.templateRender(partial, dict, opt); case "unless": return ( getVal(key) ? "" // recurse with partial : local.templateRender(partial, dict, opt) ); default: // recurse with partial return match0[0] + local.templateRender(match0.slice(1), dict, opt); } }; // render partials rgx = ( /\{\{#(\w+)\u0020([^}]+?)\}\}/g ); template = template || ""; match = rgx.exec(template); while (match) { rgx.lastIndex += 1 - match[0].length; template = template.replace( new RegExp( "\\{\\{#(" + match[1] + ") (" + match[2] + ")\\}\\}([\\S\\s]*?)\\{\\{/" + match[1] + " " + match[2] + "\\}\\}" ), renderPartial ); match = rgx.exec(template); } // search for keys in template return template.replace(( /\{\{[^}]+?\}\}/g ), function (match0) { let markdownToHtml; let notHtmlSafe; notHtmlSafe = opt.notHtmlSafe; try { val = getVal(match0.slice(2, -2)); if (val === undefined) { return match0; } argList.slice(1).forEach(function (fmt, ii, list) { switch (fmt) { case "*": case "+": case "-": case "/": skip = ii + 1; val = String( fmt === "*" ? Number(val) * Number(list[skip]) : fmt === "+" ? Number(val) + Number(list[skip]) : fmt === "-" ? Number(val) - Number(list[skip]) : Number(val) / Number(list[skip]) ); break; case "alphanumeric": val = val.replace(( /\W/g ), "_"); break; case "decodeURIComponent": val = decodeURIComponent(val); break; case "encodeURIComponent": val = encodeURIComponent(val); break; case "jsonStringify": val = JSON.stringify(val); break; case "jsonStringify4": val = JSON.stringify(val, undefined, 4); break; case "markdownSafe": val = val.replace(( /`/g ), "'"); break; case "markdownToHtml": markdownToHtml = true; break; case "notHtmlSafe": notHtmlSafe = true; break; case "padEnd": case "padStart": case "replace": case "slice": skip = ii + 2; val = String(val)[fmt]( list[skip - 1], list[skip].replace("\"\"", "").replace("\"_\"", " ") ); break; case "truncate": skip = ii + 1; if (val.length > list[skip]) { val = val.slice( 0, Math.max(list[skip] - 3, 0) ).trimEnd() + "..."; } break; // default to String.prototype[fmt]() default: if (ii <= skip) { break; } val = val[fmt](); } }); val = String(val); // default to htmlSafe if (!notHtmlSafe) { val = val.replace(( /&/gu ), "&amp;").replace(( /"/gu ), "&quot;").replace(( /'/gu ), "&apos;").replace(( /</gu ), "&lt;").replace(( />/gu ), "&gt;").replace(( /&amp;(amp;|apos;|gt;|lt;|quot;)/igu ), "&$1"); } markdownToHtml = ( markdownToHtml && (typeof local.marked === "function" && local.marked) ); if (markdownToHtml) { val = markdownToHtml(val).replace(( /&amp;(amp;|apos;|gt;|lt;|quot;)/igu ), "&$1"); } return val; } catch (errCaught) { errCaught.message = ( "templateRender could not render expression " + JSON.stringify(match0) + "\n" ) + errCaught.message; local.assertOrThrow(undefined, errCaught); } }); }; local.tryCatchOnError = function (fnc, onError) { /* * this function will run <fnc> in tryCatch block, * else call onError with errCaught */ let result; // validate onError local.assertOrThrow(typeof onError === "function", typeof onError); try { // reset errCaught delete local._debugTryCatchError; result = fnc(); delete local._debugTryCatchError; return result; } catch (errCaught) { // debug errCaught local._debugTryCatchError = errCaught; return onError(errCaught); } }; }()); // run shared js-env code - function (function () { local.apidocCreate = function (opt) { /* * this function will create the apidoc from <opt>.dir */ let elemCreate; let module; let moduleMain; let readExample; let tmp; let toString; let trimStart; if (opt.modeNoop) { return ""; } elemCreate = function (module, prefix, key) { /* * this function will create the apidoc-elem in given <module> */ let elem; if (opt.modeNoApidoc) { return elem; } elem = {}; elem.moduleName = prefix.split("."); // handle case where module is a function if (elem.moduleName.slice(-1)[0] === key) { elem.moduleName.pop(); } elem.moduleName = elem.moduleName.join("."); elem.id = encodeURIComponent("apidoc.elem." + prefix + "." + key); elem.typeof = typeof module[key]; elem.name = ( elem.typeof + " <span class=\"apidocSignatureSpan\">" + elem.moduleName + ".</span>" + key ); // handle case where module is a function elem.name = elem.name.replace(">.<", "><"); if (elem.typeof !== "function") { return elem; } // init source elem.source = local.stringHtmlSafe( trimStart(toString(module[key])) || "n/a" ).replace(( /\([\S\s]*?\)/ ), function (match0) { // init signature elem.signature = match0.replace(( /\u0020*?\/\*[\S\s]*?\*\/\u0020*/g ), "").replace(( /,/g ), ", ").replace(( /\s+/g ), " "); return elem.signature; }).replace(( /(\u0020*?\/\*[\S\s]*?\*\/\n)/ ), "<span class=\"apidocCodeCommentSpan\">$1</span>").replace(( /^function\u0020\(/ ), key + " = function ("); // init example opt.exampleList.some(function (example) { example.replace( new RegExp("((?:\n.*?){8}\\.)(" + key + ")(\\((?:.*?\n){8})"), function (ignore, match1, match2, match3) { elem.example = "..." + trimStart( local.stringHtmlSafe(match1) + "<span class=\"apidocCodeKeywordSpan\">" + local.stringHtmlSafe(match2) + "</span>" + local.stringHtmlSafe(match3) ).trimEnd() + "\n..."; return ""; } ); return elem.example; }); elem.example = elem.example || "n/a"; return elem; }; readExample = function (file) { /* * this function will read the example from given file */ let result; local.tryCatchOnError(function () { file = require("path").resolve(opt.dir, file); console.error("apidocCreate - readExample " + file); result = ""; result = local.identity( "\n\n\n\n\n\n\n\n" // bug-workaround - truncate example to manageable size + require("fs").readFileSync(file, "utf8").slice(0, 262144) + "\n\n\n\n\n\n\n\n" ).replace(( /\r\n*/g ), "\n"); }, console.error); return result; }; toString = function (value) { /* * this function will try to return the string form of the value */ let result; local.tryCatchOnError(function () { result = ""; result = String(value); }, console.error); return result; }; trimStart = function (str) { /* * this function will normalize whitespace before <str> */ let whitespace; whitespace = ""; str.trim().replace(( /^\u0020*/gm ), function (match0) { if (!whitespace || match0.length < whitespace.length) { whitespace = match0; } return ""; }); str = str.replace(new RegExp("^" + whitespace, "gm"), ""); // enforce 128 character column limit str = str.replace(( /^.{128}[^\\\n]+/gm ), function (match0) { return match0.replace(( /(.{128}(?:\b|\w+))/g ), "$1\n").trimEnd(); }); return str; }; // init opt opt.dir = local.moduleDirname( opt.dir, opt.modulePathList || require("module").paths ); local.objectAssignDefault(opt, { env: { npm_package_description: "" }, packageJson: JSON.parse(readExample("package.json")), require: function (file) { return local.tryCatchOnError(function () { return require(file); }, console.error); } }); Object.keys(opt.packageJson).forEach(function (key) { tmp = opt.packageJson[key]; // strip email from npmdoc documentation // https://github.com/npmdoc/node-npmdoc-hpp/issues/1 if (tmp) { if (tmp.email) { delete tmp.email; } if (Array.isArray(tmp)) { tmp.forEach(function (elem) { if (elem && elem.email) { delete elem.email; } }); } } if (key[0] === "_" || key === "readme") { delete opt.packageJson[key]; } else if (typeof tmp === "string") { opt.env["npm_package_" + key] = tmp; } }); local.objectAssignDefault(opt, { blacklistDict: { globalThis }, circularSet: new Set([ globalThis ]), exampleDict: {}, exampleList: [], html: "", libFileList: [], moduleDict: {}, moduleExtraDict: {}, packageJson: { bin: {} }, template: local.templateApidocHtml, whitelistDict: {} }, 2); // init exampleList ([ 1, 2, 3, 4 ]).forEach(function (depth) { opt.exampleList = opt.exampleList.concat( // find . -maxdepth 1 -mindepth 1 -name "*.js" -type f // https://stackoverflow.com/questions/4509624/how-to-limit-depth-for-recursive-file-list require("child_process").execSync( "find \"" + opt.dir + "\" -maxdepth " + depth + " -mindepth " + depth + " -type f | sed -e \"s|" + opt.dir + "/||\" | grep -iv " /* jslint ignore:start */ + '"\ /\\.\\|\\(\\b\\|_\\)\\(\ bower_component\\|\ coverage\\|\ git\\|\ min\\|\ node_module\\|\ rollup\\|\ tmp\\|\ vendor\\)s\\{0,1\\}\\(\\b\\|_\\)\ " ' /* jslint ignore:end */ + " | sort | head -n 256" ).toString().split("\n") ); }); opt.exampleList = opt.exampleList.filter(function (file) { if (file && !opt.exampleDict[file]) { opt.exampleDict[file] = true; return true; } }).slice(0, 256).map(readExample); // init moduleMain local.tryCatchOnError(function () { console.error("apidocCreate - requiring " + opt.dir + " ..."); moduleMain = {}; moduleMain = ( opt.moduleDict[opt.env.npm_package_name] || opt.require(opt.dir) || opt.require( opt.dir + "/" + (opt.packageJson.bin)[Object.keys(opt.packageJson.bin)[0]] ) || {} ); opt.circularSet.add(moduleMain); console.error("apidocCreate - ... required " + opt.dir); }, console.error); tmp = {}; // handle case where module is a function if (typeof moduleMain === "function") { (function () { let str; str = toString(moduleMain); tmp = function () { return; }; // hack-coverage tmp(); Object.defineProperties(tmp, { toString: { get: function () { return function () { return str; }; } } }); }()); } // normalize moduleMain moduleMain = local.objectAssignDefault(tmp, moduleMain); opt.moduleDict[opt.env.npm_package_name] = moduleMain; // init circularSet - builtins [ "assert", "buffer", "child_process", "cluster", "crypto", "dgram", "dns", "domain", "events", "fs", "http", "https", "net", "os", "path", "querystring", "readline", "repl", "stream", "string_decoder", "timers", "tls", "tty", "url", "util", "vm", "zlib" ].forEach(function (key) { local.tryCatchOnError(function () { opt.circularSet.add(require(key)); }, local.noop); }); // init circularSet - blacklistDict Object.keys(opt.blacklistDict).forEach(function (key) { opt.circularSet.add(opt.blacklistDict[key]); }); // init circularSet - moduleDict Object.keys(opt.moduleDict).forEach(function (key) { opt.circularSet.add(opt.moduleDict[key]); }); // init circularSet - prototype opt.circularSet.forEach(function (elem) { opt.circularSet.add(elem && elem.prototype); }); // init moduleDict child local.apidocModuleDictAdd(opt, opt.moduleDict); // init moduleExtraDict opt.moduleExtraDict[opt.env.npm_package_name] = ( opt.moduleExtraDict[opt.env.npm_package_name] || {} ); module = opt.moduleExtraDict[opt.env.npm_package_name]; ([ 1, 2, 3, 4 ]).forEach(function (depth) { opt.libFileList = opt.libFileList.concat( // find . -maxdepth 1 -mindepth 1 -name "*.js" -type f // https://stackoverflow.com/questions/4509624/how-to-limit-depth-for-recursive-file-list require("child_process").execSync( "find \"" + opt.dir + "\" -maxdepth " + depth + " -mindepth " + depth + " -name \"*.js\" -type f | sed -e \"s|" + opt.dir + "/||\" | grep -iv " /* jslint ignore:start */ + '"\ /\\.\\|\\(\\b\\|_\\)\\(\ archive\\|artifact\\|asset\\|\ bower_component\\|build\\|\ coverage\\|\ doc\\|dist\\|\ example\\|external\\|\ fixture\\|\ git\\|\ log\\|\ min\\|mock\\|\ node_module\\|\ rollup\\|\ spec\\|\ test\\|tmp\\|\ vendor\\)s\\{0,1\\}\\(\\b\\|_\\)\ " ' /* jslint ignore:end */ + " | sort | head -n 256" ).toString().split("\n") ); }); opt.ii = 256; opt.libFileList.every(function (file) { local.tryCatchOnError(function () { tmp = {}; tmp.name = require("path").basename(file).replace( "lib.", "" ).replace(( /\.[^.]*?$/ ), "").replace(( /\W/g ), "_"); Array.from([ tmp.name, tmp.name.slice(0, 1).toUpperCase() + tmp.name.slice(1) ]).some(function (name) { tmp.isFiltered = name && ( !opt.packageJson.main || String("./" + file).indexOf(opt.packageJson.main) < 0 ) && !module[name]; return !tmp.isFiltered; }); if (!tmp.isFiltered) { return; } console.error("apidocCreate - libFile " + file); tmp.module = opt.require(opt.dir + "/" + file); // filter circular-reference if (!(tmp.module && opt.circularSet.has(tmp.module))) { return; } opt.ii -= 1; module[tmp.name] = tmp.module; }, console.error); return opt.ii; }); local.apidocModuleDictAdd(opt, opt.moduleExtraDict); Object.keys(opt.moduleDict).forEach(function (key) { if (key.indexOf(opt.env.npm_package_name + ".") !== 0) { return; } tmp = key.split(".").slice(1).join("."); moduleMain[tmp] = moduleMain[tmp] || opt.moduleDict[key]; }); // init moduleList opt.moduleList = Object.keys(opt.moduleDict).sort().map(function (prefix) { module = opt.moduleDict[prefix]; // handle case where module is a function if (typeof module === "function") { local.tryCatchOnError(function () { module[prefix.split(".").slice(-1)[0]] = ( module[prefix.split(".").slice(-1)[0]] || module ); }, console.error); } return { elemList: Object.keys(module).filter(function (key) { return local.tryCatchOnError(function () { return ( key && ( /^\w[\w\-.]*?$/ ).test(key) && key.indexOf("testCase_") !== 0 && ( module[key] !== opt.blacklistDict[key] || opt.whitelistDict[key] ) ); }, console.error); }).map(function (key) { return elemCreate(module, prefix, key); }).sort(function (aa, bb) { return ( aa.name > bb.name ? 1 : -1 ); }), id: encodeURIComponent("apidoc.module." + prefix), name: prefix }; }); // render apidoc opt.result = local.templateRender(opt.template, opt, { notHtmlSafe: true }).trim().replace(( /\u0020+$/gm ), "") + "\n"; return opt.result; }; local.apidocModuleDictAdd = function (opt, moduleDict) { /* * this function will add the modules in <moduleDict> to <opt>.moduleDict */ let isModule; let objectKeys; let tmp; objectKeys = function (dict) { /* * this function will return a list of the dict's keys, with valid getters */ return Object.keys(dict).sort().filter(function (key) { return local.tryCatchOnError(function () { return dict[key] || true; }, local.noop); }); }; [ "child", "prototype", "grandchild", "prototype" ].forEach(function (elem) { objectKeys(moduleDict).forEach(function (prefix) { if (!( /^\w[\w\-.]*?$/ ).test(prefix)) { return; } objectKeys(moduleDict[prefix]).forEach(function (key) { if (!( /^\w[\w\-.]*?$/ ).test(key) || !moduleDict[prefix][key]) { return; } tmp = ( elem === "prototype" ? { module: moduleDict[prefix][key].prototype, name: prefix + "." + key + ".prototype" } : { module: moduleDict[prefix][key], name: prefix + "." + key } ); if ( !tmp.module || !( typeof tmp.module === "function" || typeof tmp.module === "object" ) || Array.isArray(tmp.module) || opt.moduleDict[tmp.name] || opt.circularSet.has(tmp.module) ) { return; } isModule = Array.from([ tmp.module, tmp.module.prototype ]).some(function (dict) { return objectKeys(dict || {}).some(function (key) { return typeof dict[key] === "function"; }); }); if (!isModule) { return; } opt.circularSet.add(tmp.module); opt.moduleDict[tmp.name] = tmp.module; }); }); }); }; }()); // run node js-env code - init-after /* istanbul ignore next */ (function () { if (local.isBrowser) { return; } local.cliDict = {}; local.cliDict._default = function () { /* * <moduleDirectory> * will create apidoc from <moduleDirectory> */ // jslint files process.stdout.write(local.apidocCreate({ dir: process.argv[2], modulePathList: module.paths })); }; // run the cli if (module === require.main && !globalThis.utility2_rollup) { local.cliRun({}); } }()); }());