UNPKG

firedoc

Version:

API Doc generator rewritten from [YUIDoc](https://github.com/yui/yuidoc). We use this tool to document a large JavaScript game engine [Fireball](http://github.com/fireball-x/fireball) at [docs-zh.fireball-x.com/api](http://docs-zh.fireball-x.com/api/) and

163 lines (147 loc) 5.05 kB
#!/usr/bin/env node const _ = require('underscore'); const fs = require('fs'); const path = require('path'); const url = require('url'); const npm = require('npm'); const exec = require('child_process').execSync; const rimraf = require('rimraf'); const semver = require('semver'); const program = require('commander'); const Promise = require('bluebird'); // Promisify some methods const loadNpmAsync = Promise.promisify(npm.load); const rimrafAsync = Promise.promisify(rimraf); // We can't initilize the `npm.commands` before getting the callback from // `npm.load`. // // https://github.com/npm/npm/blob/master/lib/npm.js#L175-L180 // NPM wrote a getter on `npm.commands` to detect this, because of the reason // from NPM, we have to put a `var` and update it later. var installNpmPkgAsync; program .option('-a --alias <name>', 'specify the theme/plugin name') .option('-t --theme', 'install package as theme') .option('-p --plugin', 'install package as plugin') .option('-v --verbose', 'print all verbose information') .parse(process.argv); // Make variablize is because we should rewrite this label. var debug = require('debug'); if (program.verbose) { debug.enable('firedoc:*'); } // Here we rewrite the `debug` to enuse it. debug = debug('firedoc:install'); // The user can input the --alias to forcely set // the `name` value var name = program.alias(); var remote = program.args[0]; // Commonly, if remote is not a url but a pure name, FireDoc // should prepend it with `github.com/fireball-x` and make it // to be a valid URI. if (/[a-z0-9_\-]+/i.test(remote)) { // Check the remote does start from `firedoc-theme-`, this // allows the pure theme name like: // // notab` -> `firedoc-theme-notab` // if (remote.slice(0, 14) !== 'firedoc-theme-') { remote = 'firedoc-theme-' + remote; } remote = 'https://github.com/fireball-x/' + remote; } // By default, we should get the name from the url, like if // we get the following remote: // // https://github.com/fireball-x/firedoc-theme-notab // // So we should extract the name to: firedoc-theme-notab // so far. // if (!name) { var urlObj = url.parse(remote); // If the user inputs a url end with a `.git`, we should // not put the extension name to the `name` variable. name = path.basename(urlObj.path).replace('.git', ''); } const themedir = path.join(__dirname, '../themes'); const destdir = themedir + '/' + name; // This option is used for calling `git.Clone`, that basically // is for authorization of SSH/HTTPS from Github/Bitbucket. const cloneOption = { 'remoteCallbacks': { // set a function to return 1 always to skip the authentication certificateCheck: function () { return 1; }, // this is for SSH agent credentials: function (url, user) { return git.Cred.sshKeyFromAgent(username); } } // Check http://www.nodegit.org/guides/cloning for more details // about NODEGIT }; // TODO(Yorkie): This function to be extended in the future, just quite // not sure the error report for now. // // #PR-WELCOME // function errorHandler (e) { throw e; } // Build the installing package string. It supports the following styles: // // - [<@scope>/]<pkg> // - [<@scope>/]<pkg>@<tag> // - [<@scope>/]<pkg>@<version> // - [<@scope>/]<pkg>@<version range> (Very Important) // - <git:// url> // - etc. // // Thanks to the powerful support from libnpm, `firedoc-install(1)` also // supports the above installation ways. function buildNpmPackageName (version, name) { debug('Validing the package(semver): ' + name); return name + '@' + version; } function installNpmPackage (pkg) { debug('Installing the dependence: ' + pkg); // Rewrite the file-scoped `installNpmPkgAsync`, promisify the // `npm.commands.install` once here, and free to use forever. if (!installNpmPkgAsync) { installNpmPkgAsync = Promise.promisify(npm.commands.install); } // call the promisified `npm.commands.install` and set the theme dir // to where the package would be installed. return installNpmPkgAsync(destdir, pkg); } // This line is the start line in real runtime logic, the entire logic // of installing theme would inclued the following steps: // // - clean the original/installed theme directory (#PR-WELCOME, remove this?) // - clone the project the theme directory // - install npm package // ? install bower(#PR-WELCOME, do we really need to support bower progress?) // debug('cleaning the original folder: ' + name); rimrafAsync(destdir) .then(function () { debug('Start cloning "' + remote + '" into "' + path.relative(process.cwd(), destdir) + '"'); return exec(`git clone ${remote} ${destdir}`); }) .then(function () { debug('Start installing the dependencies'); return _.map( require(destdir + '/package.json').dependencies, buildNpmPackageName ); }) .then(function (deps) { return loadNpmAsync({}).then(function () { return Promise.map(deps, installNpmPackage); }); }) .catch(errorHandler) .done(function () { debug('Installed ' + name); });